Index: include/llvm/IR/IntrinsicInst.h =================================================================== --- include/llvm/IR/IntrinsicInst.h +++ include/llvm/IR/IntrinsicInst.h @@ -93,6 +93,10 @@ return cast(getArgOperand(2))->getMetadata(); } + /// Get the size (in bits) of the variable, or fragment of the variable, + /// that is described. + Optional getFragmentSize() const; + /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { Index: lib/IR/IntrinsicInst.cpp =================================================================== --- lib/IR/IntrinsicInst.cpp +++ lib/IR/IntrinsicInst.cpp @@ -24,6 +24,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -48,6 +49,14 @@ return nullptr; } +Optional DbgInfoIntrinsic::getFragmentSize() const { + if (auto Fragment = getExpression()->getFragmentInfo()) + return Fragment->SizeInBits; + if (auto VarSize = getVariable()->getSizeInBits()) + return *VarSize; + return None; +} + int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef NameTable, StringRef Name) { assert(Name.startswith("llvm.")); Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1228,6 +1228,17 @@ return false; } +/// Check if the size of the variable (or fragment of the variable) described by +/// \p DII isn't greater than the size of \p Ty. +static bool ValueCoversEntireFragment(Type *ValTy, DbgInfoIntrinsic *DII) { + const DataLayout &DL = DII->getModule()->getDataLayout(); + uint64_t ValueSize = DL.getTypeSizeInBits(ValTy); + if (auto FragmentSize = DII->getFragmentSize()) + return ValueSize >= *FragmentSize; + return false; +} + + /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value /// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic. void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, @@ -1238,6 +1249,21 @@ auto *DIExpr = DII->getExpression(); Value *DV = SI->getOperand(0); + if (!ValueCoversEntireFragment(SI->getValueOperand()->getType(), DII)) { + // FIXME: If storing to a part of the variable described by the dbg.declare, + // then we want to insert a dbg.value for the corresponding fragment. + LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to dbg.value: " + << *DII << '\n'); + // For now, when there is a store to parts of the variable (but we do not + // know which part) we insert an dbg.value instrinsic to indicate that we + // know nothing about the variables content. + DV = UndefValue::get(DV->getType()); + if (!LdStHasDebugValue(DIVar, DIExpr, SI)) + Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, DII->getDebugLoc(), + SI); + return; + } + // If an argument is zero extended then use argument directly. The ZExt // may be zapped by an optimization pass in future. Argument *ExtendedArg = nullptr; @@ -1281,6 +1307,9 @@ if (LdStHasDebugValue(DIVar, DIExpr, LI)) return; + assert(ValueCoversEntireFragment(LI->getType(), DII) && + "Assuming that the load is loading the full variable."); + // We are now tracking the loaded value instead of the address. In the // future if multi-location support is added to the IR, it might be // preferable to keep tracking both the loaded value and the original @@ -1301,6 +1330,9 @@ if (PhiHasDebugValue(DIVar, DIExpr, APN)) return; + assert(ValueCoversEntireFragment(APN->getType(), DII) && + "Assuming that the load is loading the full variable."); + BasicBlock *BB = APN->getParent(); auto InsertionPt = BB->getFirstInsertionPt(); Index: test/Transforms/InstCombine/debuginfo.ll =================================================================== --- test/Transforms/InstCombine/debuginfo.ll +++ test/Transforms/InstCombine/debuginfo.ll @@ -71,9 +71,11 @@ ; NOLOWER-NOT: alloca ; NOLOWER-NOT: store ; NOLOWER-NOT: call void @llvm.dbg.declare -; NOLOWER: call void @llvm.dbg.value(metadata i64 %o.coerce0, {{.*}}) +; Here we want to find: call void @llvm.dbg.value(metadata i64 %o.coerce0, metadata [[VARIABLE_O]], metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)) +; NOLOWER: call void @llvm.dbg.value(metadata i64 undef, {{.*}}) ; NOLOWER-NOT: store -; NOLOWER: call void @llvm.dbg.value(metadata i64 %o.coerce1, {{.*}}) +; Here we want to find: call void @llvm.dbg.value(metadata i64 %o.coerce1, metadata [[VARIABLE_O]], metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)) +; NOLOWER: call void @llvm.dbg.value(metadata i64 undef, {{.*}}) ; NOLOWER-NOT: store ; NOLOWER: call void @tworegs_callee(i64 %o.coerce0, i64 %o.coerce1)