Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ llvm/include/llvm/IR/Instruction.h @@ -33,6 +33,7 @@ namespace llvm { class BasicBlock; +class DbgVariableIntrinsic; class FastMathFlags; class MDNode; class Module; @@ -343,6 +344,22 @@ /// Sets the metadata on this instruction from the AAMDNodes structure. void setAAMetadata(const AAMDNodes &N); + /// Given DIExpression \p DIExpr operating on this instruction, write the + /// effects of this instruction into the returned DIExpression, or return + /// nullptr if it cannot be salvaged. \p StackVal: whether DW_OP_stack_value + /// should be appended to the expression. + DIExpression *salvageDebugInfoImpl(DIExpression *SrcDIExpr, + bool WithStackValue); + + /// Implementation of salvageDebugInfo, applying only to instructions in + /// \p DbgUsers, rather than all debug users of this instruction. + void salvageDebugInfoForDbgValues(ArrayRef DbgUsers); + + /// Assuming this instruction is going to be deleted, attempt to salvage + /// debug users by writing the effect of this instruction in a DIExpression. + /// Returns true if any debug users were updated. + void salvageDebugInfo(); + /// Retrieve the raw weight values of a conditional branch or select. /// Returns true on success with profile weights filled in. /// Returns false if no metadata or invalid metadata was found. Index: llvm/include/llvm/IR/Module.h =================================================================== --- llvm/include/llvm/IR/Module.h +++ llvm/include/llvm/IR/Module.h @@ -41,6 +41,7 @@ namespace llvm { +class DbgVariableIntrinsic; class Error; class FunctionType; class GVMaterializer; @@ -197,6 +198,11 @@ ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) NamedMDSymTabType NamedMDSymTab; ///< NamedMDNode names. DataLayout DL; ///< DataLayout associated with the module + /// Instruction combiner optimization deletes debugdeclare intrinsic, + /// cases when debugdeclare instrinsic is deleted from caller while callee + /// is later inlined, which makes opportunity to create DW_OP_implicit_pointer + /// we will preserve location of variable in DenseMap to use later + DenseMap VarAddrMap; friend class Constant; @@ -210,9 +216,13 @@ /// The module destructor. This will dropAllReferences. ~Module(); -/// @} -/// @name Module Level Accessors -/// @{ + void insertVarAddressMap(DbgVariableIntrinsic *DDI); + + Value *findVarAddressMap(Value *Var); + + /// @} + /// @name Module Level Accessors + /// @{ /// Get the module identifier which is, essentially, the name of the module. /// @returns the module identifier as a string Index: llvm/include/llvm/IR/Value.h =================================================================== --- llvm/include/llvm/IR/Value.h +++ llvm/include/llvm/IR/Value.h @@ -15,6 +15,7 @@ #include "llvm-c/Types.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Use.h" @@ -34,6 +35,7 @@ class ConstantData; class ConstantAggregate; class DataLayout; +class DbgVariableIntrinsic; class Function; class GlobalAlias; class GlobalIFunc; @@ -313,6 +315,9 @@ } } + /// Finds the debug info intrinsics describing this value. + void findDbgUsers(SmallVectorImpl &DbgUsers); + /// replaceUsesOutsideBlock - Go through the uses list for this definition and /// make each use point to "V" instead of "this" when the use is outside the /// block. 'This's use list is expected to have at least one element. Index: llvm/include/llvm/Transforms/Utils/Local.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Local.h +++ llvm/include/llvm/Transforms/Utils/Local.h @@ -287,9 +287,6 @@ /// Finds the llvm.dbg.value intrinsics describing a value. void findDbgValues(SmallVectorImpl &DbgValues, Value *V); -/// Finds the debug info intrinsics describing a value. -void findDbgUsers(SmallVectorImpl &DbgInsts, Value *V); - /// Replaces llvm.dbg.declare instruction when the address it /// describes is replaced with a new value. If Deref is true, an /// additional DW_OP_deref is prepended to the expression. If Offset @@ -306,25 +303,9 @@ void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, int Offset = 0); -/// Assuming the instruction \p I is going to be deleted, attempt to salvage -/// debug users of \p I by writing the effect of \p I in a DIExpression. If it -/// cannot be salvaged changes its debug uses to undef. -void salvageDebugInfo(Instruction &I); - - -/// Implementation of salvageDebugInfo, applying only to instructions in -/// \p Insns, rather than all debug users from findDbgUsers( \p I). -/// Returns true if any debug users were updated. -/// Mark undef if salvaging cannot be completed. -void salvageDebugInfoForDbgValues(Instruction &I, - ArrayRef Insns); - -/// Given an instruction \p I and DIExpression \p DIExpr operating on it, write -/// the effects of \p I into the returned DIExpression, or return nullptr if -/// it cannot be salvaged. \p StackVal: whether DW_OP_stack_value should be -/// appended to the expression. -DIExpression *salvageDebugInfoImpl(Instruction &I, DIExpression *DIExpr, - bool StackVal); +/// Finds alloca where the value comes from. +AllocaInst *findAllocaForValue(Value *V, + DenseMap &AllocaForValue); /// Point debug users of \p From to \p To or salvage them. Use this function /// only when replacing all uses of \p From with \p To, with a guarantee that Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1224,7 +1224,7 @@ // variable. FIXME: Further work could recover those too. while (isa(V)) { Instruction &VAsInst = *cast(V); - DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue); + DIExpression *NewExpr = VAsInst.salvageDebugInfoImpl(Expr, StackValue); // If we cannot salvage any further, and haven't yet found a suitable debug // expression, bail out. Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1211,17 +1211,22 @@ } bool DIExpression::extractIfOffset(int64_t &Offset) const { - if (getNumElements() == 0) { + unsigned numElements = getNumElements(); + + if (numElements == 0) { Offset = 0; return true; } - if (getNumElements() == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { + if (Elements[numElements - 1] == dwarf::DW_OP_stack_value) + numElements--; + + if (numElements == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { Offset = Elements[1]; return true; } - if (getNumElements() == 3 && Elements[0] == dwarf::DW_OP_constu) { + if (numElements == 3 && Elements[0] == dwarf::DW_OP_constu) { if (Elements[2] == dwarf::DW_OP_plus) { Offset = Elements[1]; return true; Index: llvm/lib/IR/Instruction.cpp =================================================================== --- llvm/lib/IR/Instruction.cpp +++ llvm/lib/IR/Instruction.cpp @@ -11,11 +11,14 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" #include "llvm/ADT/DenseSet.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" using namespace llvm; @@ -75,6 +78,9 @@ } iplist::iterator Instruction::eraseFromParent() { + // Try to preserve debug information attached to the instruction. + salvageDebugInfo(); + return getParent()->getInstList().erase(getIterator()); } @@ -779,3 +785,226 @@ New->copyMetadata(*this); return New; } + +void Instruction::salvageDebugInfo() { + SmallVector DbgUsers; + + // Return false if any of the operand is already deleted + for (unsigned i = 0; i < getNumOperands(); ++i) + if (!getOperand(i)) + return; + + // preserve the information we may need later when called function from + // current function is inlined. We need this information for + // DW_OP_implicit_pointer. + if (auto DDI = dyn_cast(this)) + if (getModule()->getDwarfVersion() >= 5) + if (DDI->isAddressOfVariable()) + getModule()->insertVarAddressMap(DDI); + + findDbgUsers(DbgUsers); + if (DbgUsers.empty()) + return; + + salvageDebugInfoForDbgValues(DbgUsers); +} + +void Instruction::salvageDebugInfoForDbgValues( + ArrayRef DbgUsers) { + auto &Ctx = getContext(); + bool Salvaged = false; + auto wrapMD = [&](Value *V) { + return MetadataAsValue::get(Ctx, ValueAsMetadata::get(V)); + }; + Value *DebugDeclareAddress = nullptr; + SmallVector StoreInsts; + + if (getModule()->getDwarfVersion() >= 5) { + if (isa(*this)) { + for (auto *DII : DbgUsers) { + if (DII->isAddressOfVariable()) { + if (const llvm::MetadataAsValue *MDV = + dyn_cast(DII->getOperand(1))) + if (isa(MDV->getMetadata())) { + DebugDeclareAddress = DII->getOperand(1); + } + break; + } + } + } + + if (!DebugDeclareAddress) + DebugDeclareAddress = getModule()->findVarAddressMap(this); + + if (!DebugDeclareAddress) { + StoreInst *SI; + for (auto &AIUse : uses()) { + User *U = AIUse.getUser(); + if ((SI = dyn_cast(U)) && SI->getOperand(1) == this) + StoreInsts.push_back(SI); + } + } + } + + for (auto *DII : DbgUsers) { + // Do not add DW_OP_stack_value for DbgDeclare and DbgAddr, because they + // are implicitly pointing out the value as a DWARF memory location + // description. + bool StackValue = isa(DII); + + DIExpression *DIExpr = + salvageDebugInfoImpl(DII->getExpression(), StackValue); + + // salvageDebugInfoImpl should fail on examining the first element of + // DbgUsers, or none of them. + if (!DIExpr) + continue; + + int64_t ExprOffset = 0; + + // It is AllocaInst and either of below is true then continue + // - We failed to get the variable description, or + // - Current instruction is not llvm.dbg.value, or + // - Current instruction doesnt have constant offset + if (!StoreInsts.empty()) { + if (!DII->getExpression()->extractIfOffset(ExprOffset)) + continue; + } else if (isa(this) && + (!DebugDeclareAddress || DII->isAddressOfVariable() || + !DII->getExpression()->extractIfOffset(ExprOffset))) + continue; + + if (!StoreInsts.empty()) { + DIBuilder DIB(*getModule(), /*AllowUnresolved*/ false); + + DIExpression *DIExpr = DII->getExpression(); + + for (auto *SI : StoreInsts) { + Value *ReplVal = SI->getOperand(0); + DIExpression *DIExprNew = DIExpression::get( + DIExpr->getContext(), {dwarf::DW_OP_LLVM_implicit_pointer}); + + if (!StackValue) + DIB.insertDbgValueIntrinsic(ReplVal, DII->getVariable(), DIExprNew, + DII->getDebugLoc(), SI); + else { + DII->setOperand(0, wrapMD(ReplVal)); + DII->setOperand(2, MetadataAsValue::get(Ctx, DIExprNew)); + } + } + Salvaged = true; + } else if (!isa(this)) { + DII->setOperand(0, wrapMD(getOperand(0))); + DII->setOperand(2, MetadataAsValue::get(Ctx, DIExpr)); + Salvaged = true; + } + } + + if (Salvaged) + return; + + for (auto *DII : DbgUsers) { + Value *Undef = UndefValue::get(getType()); + DII->setOperand(0, MetadataAsValue::get(DII->getContext(), + ValueAsMetadata::get(Undef))); + } +} + +DIExpression *Instruction::salvageDebugInfoImpl(DIExpression *SrcDIExpr, + bool WithStackValue) { + auto &M = *getModule(); + auto &DL = M.getDataLayout(); + + // Apply a vector of opcodes to the source DIExpression. + auto doSalvage = [&](SmallVectorImpl &Ops) -> DIExpression * { + DIExpression *DIExpr = SrcDIExpr; + if (!Ops.empty()) { + DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue); + } + return DIExpr; + }; + + // Apply the given offset to the source DIExpression. + auto applyOffset = [&](uint64_t Offset) -> DIExpression * { + SmallVector Ops; + DIExpression::appendOffset(Ops, Offset); + return doSalvage(Ops); + }; + + // initializer-list helper for applying operators to the source DIExpression. + auto applyOps = [&](ArrayRef Opcodes) -> DIExpression * { + SmallVector Ops(Opcodes.begin(), Opcodes.end()); + return doSalvage(Ops); + }; + + if (auto *CI = dyn_cast(this)) { + // No-op casts are irrelevant for debug info. + if (CI->isNoopCast(DL)) + return SrcDIExpr; + + Type *Type = CI->getType(); + // Casts other than Trunc, SExt, or ZExt to scalar types cannot be salvaged. + if (Type->isVectorTy() || + !(isa(this) || isa(this) || isa(this))) + return nullptr; + + Value *FromValue = CI->getOperand(0); + unsigned FromTypeBitSize = FromValue->getType()->getScalarSizeInBits(); + unsigned ToTypeBitSize = Type->getScalarSizeInBits(); + + return applyOps(DIExpression::getExtOps(FromTypeBitSize, ToTypeBitSize, + isa(this))); + } + + if (auto *GEP = dyn_cast(this)) { + unsigned BitWidth = + M.getDataLayout().getIndexSizeInBits(GEP->getPointerAddressSpace()); + // Rewrite a constant GEP into a DIExpression. + APInt Offset(BitWidth, 0); + if (GEP->accumulateConstantOffset(M.getDataLayout(), Offset)) { + return applyOffset(Offset.getSExtValue()); + } else { + return nullptr; + } + } else if (auto *BI = dyn_cast(this)) { + // Rewrite binary operations with constant integer operands. + auto *ConstInt = dyn_cast(getOperand(1)); + if (!ConstInt || ConstInt->getBitWidth() > 64) + return nullptr; + + uint64_t Val = ConstInt->getSExtValue(); + switch (BI->getOpcode()) { + case Instruction::Add: + return applyOffset(Val); + case Instruction::Sub: + return applyOffset(-int64_t(Val)); + case Instruction::Mul: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_mul}); + case Instruction::SDiv: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_div}); + case Instruction::SRem: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_mod}); + case Instruction::Or: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_or}); + case Instruction::And: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_and}); + case Instruction::Xor: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_xor}); + case Instruction::Shl: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shl}); + case Instruction::LShr: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shr}); + case Instruction::AShr: + return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shra}); + default: + // TODO: Salvage constants from each kind of binop we know about. + return nullptr; + } + // *Not* to do: we should not attempt to salvage load instructions, + // because the validity and lifetime of a dbg.value containing + // DW_OP_deref becomes difficult to analyze. See PR40628 for examples. + } else if ((M.getDwarfVersion() >= 5) && isa(this)) { + return SrcDIExpr; + } + return nullptr; +} Index: llvm/lib/IR/Module.cpp =================================================================== --- llvm/lib/IR/Module.cpp +++ llvm/lib/IR/Module.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/ModuleSummaryIndex.h" @@ -694,3 +695,18 @@ } } } + +void Module::insertVarAddressMap(DbgVariableIntrinsic *DDI) { + if (DDI->getOperand(0) != nullptr) + VarAddrMap.insert( + std::pair(DDI->getOperand(0), DDI->getOperand(1))); +} + +Value *Module::findVarAddressMap(Value *Var) { + if (Var->isUsedByMetadata()) + if (auto *L = LocalAsMetadata::getIfExists(Var)) + if (auto *MDV = MetadataAsValue::getIfExists(Var->getContext(), L)) + return VarAddrMap[MDV]; + + return nullptr; +} Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -533,6 +533,18 @@ }); } +void Value::findDbgUsers(SmallVectorImpl &DbgUsers) { + // This function is hot. Check whether the value has any metadata to avoid a + // DenseMap lookup. + if (!isUsedByMetadata()) + return; + if (auto *L = LocalAsMetadata::getIfExists(this)) + if (auto *MDV = MetadataAsValue::getIfExists(getContext(), L)) + for (User *U : MDV->users()) + if (DbgVariableIntrinsic *DII = dyn_cast(U)) + DbgUsers.push_back(DII); +} + namespace { // Various metrics for how much to strip off of pointers. enum PointerStripKind { Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -444,7 +444,7 @@ Instruction *eraseInstFromFunction(Instruction &I) override { LLVM_DEBUG(dbgs() << "IC: ERASE " << I << '\n'); assert(I.use_empty() && "Cannot erase instruction that is used!"); - salvageDebugInfo(I); + I.salvageDebugInfo(); // Make sure that we reprocess all operands now that we reduced their // use counts. Index: llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -76,7 +76,7 @@ Depth, I); if (!NewVal) return false; if (Instruction* OpInst = dyn_cast(U)) - salvageDebugInfo(*OpInst); + OpInst->salvageDebugInfo(); replaceUse(U, NewVal); return true; Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2592,7 +2592,7 @@ SmallVector DVIs; std::unique_ptr DIB; if (isa(MI)) { - findDbgUsers(DVIs, &MI); + MI.findDbgUsers(DVIs); DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); } @@ -2632,6 +2632,7 @@ } else { // Casts, GEP, or anything else: we're about to delete this instruction, // so it can not have any valid uses. + I->salvageDebugInfo(); replaceInstUsesWith(*I, UndefValue::get(I->getType())); } eraseInstFromFunction(*I); @@ -3535,7 +3536,7 @@ // mark the location undef: we know it was supposed to receive a new location // here, but that computation has been sunk. SmallVector DbgUsers; - findDbgUsers(DbgUsers, I); + I->findDbgUsers(DbgUsers); // Update the arguments of a dbg.declare instruction, so that it // does not point into a sunk instruction. @@ -3565,7 +3566,7 @@ // Perform salvaging without the clones, then sink the clones. if (!DIIClones.empty()) { - salvageDebugInfoForDbgValues(*I, DbgUsers); + I->salvageDebugInfoForDbgValues(DbgUsers); for (auto &DIIClone : DIIClones) { DIIClone->insertBefore(&*InsertPos); LLVM_DEBUG(dbgs() << "SINK: " << *DIIClone << '\n'); @@ -3852,7 +3853,7 @@ if (isInstructionTriviallyDead(Inst, TLI)) { ++NumDeadInst; LLVM_DEBUG(dbgs() << "IC: DCE: " << *Inst << '\n'); - salvageDebugInfo(*Inst); + Inst->salvageDebugInfo(); Inst->eraseFromParent(); MadeIRChange = true; continue; Index: llvm/lib/Transforms/Scalar/BDCE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/BDCE.cpp +++ llvm/lib/Transforms/Scalar/BDCE.cpp @@ -106,7 +106,7 @@ (I.getType()->isIntOrIntVectorTy() && DB.getDemandedBits(&I).isNullValue() && wouldInstructionBeTriviallyDead(&I))) { - salvageDebugInfo(I); + I.salvageDebugInfo(); Worklist.push_back(&I); I.dropAllReferences(); Changed = true; Index: llvm/lib/Transforms/Scalar/DCE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/DCE.cpp +++ llvm/lib/Transforms/Scalar/DCE.cpp @@ -80,7 +80,7 @@ if (!DebugCounter::shouldExecute(DCECounter)) return false; - salvageDebugInfo(*I); + I->salvageDebugInfo(); salvageKnowledge(I); // Null out all of the instruction's operands to see if any operand becomes Index: llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -182,7 +182,7 @@ ++NumFastOther; // Try to preserve debug information attached to the dead instruction. - salvageDebugInfo(*DeadInst); + DeadInst->salvageDebugInfo(); salvageKnowledge(DeadInst); // This instruction is dead, zap it, in stages. Start by removing it from @@ -2313,7 +2313,7 @@ ++NumFastOther; // Try to preserve debug information attached to the dead instruction. - salvageDebugInfo(*DeadInst); + DeadInst->salvageDebugInfo(); salvageKnowledge(DeadInst); // Remove the Instruction from MSSA. Index: llvm/lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -1202,7 +1202,7 @@ } salvageKnowledge(&Inst, &AC); - salvageDebugInfo(Inst); + Inst.salvageDebugInfo(); removeMSSA(Inst); Inst.eraseFromParent(); Changed = true; Index: llvm/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GVN.cpp +++ llvm/lib/Transforms/Scalar/GVN.cpp @@ -2392,7 +2392,7 @@ assert(I->getParent() == BB && "Removing instruction from wrong block?"); LLVM_DEBUG(dbgs() << "GVN removed: " << *I << '\n'); salvageKnowledge(I, AC); - salvageDebugInfo(*I); + I->salvageDebugInfo(); if (MD) MD->removeInstruction(I); if (MSSAU) MSSAU->removeMemoryAccess(I); Index: llvm/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LICM.cpp +++ llvm/lib/Transforms/Scalar/LICM.cpp @@ -501,7 +501,7 @@ if (isInstructionTriviallyDead(&I, TLI)) { LLVM_DEBUG(dbgs() << "LICM deleting dead inst: " << I << '\n'); salvageKnowledge(&I); - salvageDebugInfo(I); + I.salvageDebugInfo(); ++II; eraseInstruction(I, *SafetyInfo, CurAST, MSSAU); Changed = true; @@ -521,7 +521,7 @@ if (sink(I, LI, DT, BFI, CurLoop, SafetyInfo, MSSAU, ORE)) { if (!FreeInLoop) { ++II; - salvageDebugInfo(I); + I.salvageDebugInfo(); eraseInstruction(I, *SafetyInfo, CurAST, MSSAU); } Changed = true; Index: llvm/lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- llvm/lib/Transforms/Scalar/Reassociate.cpp +++ llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -1943,7 +1943,7 @@ ValueRankMap.erase(I); Insts.remove(I); RedoInsts.remove(I); - llvm::salvageDebugInfo(*I); + I->salvageDebugInfo(); I->eraseFromParent(); for (auto Op : Ops) if (Instruction *OpInst = dyn_cast(Op)) @@ -1960,7 +1960,7 @@ // Erase the dead instruction. ValueRankMap.erase(I); RedoInsts.remove(I); - llvm::salvageDebugInfo(*I); + I->salvageDebugInfo(); I->eraseFromParent(); // Optimize its operands. SmallPtrSet Visited; // Detect self-referential nodes. Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -1450,7 +1450,7 @@ static void eraseDebugIntrinsicsWithNonLocalRefs(Function &F) { for (Instruction &I : instructions(F)) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, &I); + I.findDbgUsers(DbgUsers); for (DbgVariableIntrinsic *DVI : DbgUsers) if (DVI->getFunction() != &F) DVI->eraseFromParent(); Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -522,7 +522,7 @@ assert(I->use_empty() && "Instructions with uses are not dead."); // Don't lose the debug info while deleting the instructions. - salvageDebugInfo(*I); + I->salvageDebugInfo(); if (AboutToDeleteCallback) AboutToDeleteCallback(I); @@ -552,7 +552,7 @@ bool llvm::replaceDbgUsesWithUndef(Instruction *I) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, I); + I->findDbgUsers(DbgUsers); for (auto *DII : DbgUsers) { Value *Undef = UndefValue::get(I->getType()); DII->setOperand(0, MetadataAsValue::get(DII->getContext(), @@ -611,7 +611,7 @@ const DataLayout &DL, const TargetLibraryInfo *TLI) { if (isInstructionTriviallyDead(I, TLI)) { - salvageDebugInfo(*I); + I->salvageDebugInfo(); // Null out all of the instruction's operands to see if any operand becomes // dead as we go. @@ -1656,19 +1656,6 @@ DbgValues.push_back(DVI); } -void llvm::findDbgUsers(SmallVectorImpl &DbgUsers, - Value *V) { - // This function is hot. Check whether the value has any metadata to avoid a - // DenseMap lookup. - if (!V->isUsedByMetadata()) - return; - if (auto *L = LocalAsMetadata::getIfExists(V)) - if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L)) - for (User *U : MDV->users()) - if (DbgVariableIntrinsic *DII = dyn_cast(U)) - DbgUsers.push_back(DII); -} - bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, DIBuilder &Builder, uint8_t DIExprFlags, int Offset) { @@ -1726,148 +1713,6 @@ return MetadataAsValue::get(C, ValueAsMetadata::get(V)); } -/// Where possible to salvage debug information for \p I do so -/// and return True. If not possible mark undef and return False. -void llvm::salvageDebugInfo(Instruction &I) { - SmallVector DbgUsers; - findDbgUsers(DbgUsers, &I); - salvageDebugInfoForDbgValues(I, DbgUsers); -} - -void llvm::salvageDebugInfoForDbgValues( - Instruction &I, ArrayRef DbgUsers) { - auto &Ctx = I.getContext(); - bool Salvaged = false; - auto wrapMD = [&](Value *V) { return wrapValueInMetadata(Ctx, V); }; - - for (auto *DII : DbgUsers) { - // Do not add DW_OP_stack_value for DbgDeclare and DbgAddr, because they - // are implicitly pointing out the value as a DWARF memory location - // description. - bool StackValue = isa(DII); - - DIExpression *DIExpr = - salvageDebugInfoImpl(I, DII->getExpression(), StackValue); - - // salvageDebugInfoImpl should fail on examining the first element of - // DbgUsers, or none of them. - if (!DIExpr) - break; - - DII->setOperand(0, wrapMD(I.getOperand(0))); - DII->setOperand(2, MetadataAsValue::get(Ctx, DIExpr)); - LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); - Salvaged = true; - } - - if (Salvaged) - return; - - for (auto *DII : DbgUsers) { - Value *Undef = UndefValue::get(I.getType()); - DII->setOperand(0, MetadataAsValue::get(DII->getContext(), - ValueAsMetadata::get(Undef))); - } -} - -DIExpression *llvm::salvageDebugInfoImpl(Instruction &I, - DIExpression *SrcDIExpr, - bool WithStackValue) { - auto &M = *I.getModule(); - auto &DL = M.getDataLayout(); - - // Apply a vector of opcodes to the source DIExpression. - auto doSalvage = [&](SmallVectorImpl &Ops) -> DIExpression * { - DIExpression *DIExpr = SrcDIExpr; - if (!Ops.empty()) { - DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue); - } - return DIExpr; - }; - - // Apply the given offset to the source DIExpression. - auto applyOffset = [&](uint64_t Offset) -> DIExpression * { - SmallVector Ops; - DIExpression::appendOffset(Ops, Offset); - return doSalvage(Ops); - }; - - // initializer-list helper for applying operators to the source DIExpression. - auto applyOps = [&](ArrayRef Opcodes) -> DIExpression * { - SmallVector Ops(Opcodes.begin(), Opcodes.end()); - return doSalvage(Ops); - }; - - if (auto *CI = dyn_cast(&I)) { - // No-op casts are irrelevant for debug info. - if (CI->isNoopCast(DL)) - return SrcDIExpr; - - Type *Type = CI->getType(); - // Casts other than Trunc, SExt, or ZExt to scalar types cannot be salvaged. - if (Type->isVectorTy() || - !(isa(&I) || isa(&I) || isa(&I))) - return nullptr; - - Value *FromValue = CI->getOperand(0); - unsigned FromTypeBitSize = FromValue->getType()->getScalarSizeInBits(); - unsigned ToTypeBitSize = Type->getScalarSizeInBits(); - - return applyOps(DIExpression::getExtOps(FromTypeBitSize, ToTypeBitSize, - isa(&I))); - } - - if (auto *GEP = dyn_cast(&I)) { - unsigned BitWidth = - M.getDataLayout().getIndexSizeInBits(GEP->getPointerAddressSpace()); - // Rewrite a constant GEP into a DIExpression. - APInt Offset(BitWidth, 0); - if (GEP->accumulateConstantOffset(M.getDataLayout(), Offset)) { - return applyOffset(Offset.getSExtValue()); - } else { - return nullptr; - } - } else if (auto *BI = dyn_cast(&I)) { - // Rewrite binary operations with constant integer operands. - auto *ConstInt = dyn_cast(I.getOperand(1)); - if (!ConstInt || ConstInt->getBitWidth() > 64) - return nullptr; - - uint64_t Val = ConstInt->getSExtValue(); - switch (BI->getOpcode()) { - case Instruction::Add: - return applyOffset(Val); - case Instruction::Sub: - return applyOffset(-int64_t(Val)); - case Instruction::Mul: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_mul}); - case Instruction::SDiv: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_div}); - case Instruction::SRem: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_mod}); - case Instruction::Or: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_or}); - case Instruction::And: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_and}); - case Instruction::Xor: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_xor}); - case Instruction::Shl: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shl}); - case Instruction::LShr: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shr}); - case Instruction::AShr: - return applyOps({dwarf::DW_OP_constu, Val, dwarf::DW_OP_shra}); - default: - // TODO: Salvage constants from each kind of binop we know about. - return nullptr; - } - // *Not* to do: we should not attempt to salvage load instructions, - // because the validity and lifetime of a dbg.value containing - // DW_OP_deref becomes difficult to analyze. See PR40628 for examples. - } - return nullptr; -} - /// A replacement for a dbg.value expression. using DbgValReplacement = Optional; @@ -1879,7 +1724,7 @@ function_ref RewriteExpr) { // Find debug users of From. SmallVector Users; - findDbgUsers(Users, &From); + From.findDbgUsers(Users); if (Users.empty()) return false; @@ -1923,7 +1768,7 @@ if (!UndefOrSalvage.empty()) { // Try to salvage the remaining debug users. - salvageDebugInfo(From); + From.salvageDebugInfo(); Changed = true; } @@ -2737,7 +2582,7 @@ void llvm::dropDebugUsers(Instruction &I) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, &I); + I.findDbgUsers(DbgUsers); for (auto *DII : DbgUsers) DII->eraseFromParent(); } Index: llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp =================================================================== --- llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -151,7 +151,7 @@ } } - findDbgUsers(DbgUsers, AI); + AI->findDbgUsers(DbgUsers); } }; Index: llvm/test/DebugInfo/X86/implicit_pointer_temp_dyn_alloc.cc =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/implicit_pointer_temp_dyn_alloc.cc @@ -0,0 +1,15 @@ +// RUN: clang %s -O2 -gdwarf-5 -S -emit-llvm -o %t.ll +// RUN: FileCheck %s --input-file=%t.ll + +int main() { + int *i = new int(3); + int *j = new int(4); + // CHECK: call void @llvm.dbg.value(metadata i32 3, metadata [[MD1:!.+]], metadata !DIExpression(DW_OP_LLVM_explicit_pointer)) + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD2:!.+]], metadata !DIExpression(DW_OP_LLVM_explicit_pointer)) + delete i; + delete j; + + return 0; +} +// CHECK: [[MD1]] = !DILocalVariable(name: "i" +// CHECK: [[MD2]] = !DILocalVariable(name: "j" Index: llvm/unittests/IR/DebugInfoTest.cpp =================================================================== --- llvm/unittests/IR/DebugInfoTest.cpp +++ llvm/unittests/IR/DebugInfoTest.cpp @@ -181,9 +181,9 @@ SmallVector DVIs; findDbgValues(DVIs, &I); - // Delete %b. The dbg.value should now point to undef. + // Delete %b. The dbg.value should now point to %a. I.eraseFromParent(); - EXPECT_TRUE(isa(DVIs[0]->getValue())); + EXPECT_FALSE(isa(DVIs[0]->getValue())); } TEST(DIBuilder, CreateFortranArrayTypeWithAttributes) { Index: llvm/unittests/Transforms/Utils/LocalTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/LocalTest.cpp +++ llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -733,7 +733,7 @@ EXPECT_TRUE(replaceAllDbgUsesWith(D, C, C, DT)); SmallVector CDbgVals; - findDbgUsers(CDbgVals, &C); + C.findDbgUsers(CDbgVals); EXPECT_EQ(2U, CDbgVals.size()); EXPECT_TRUE(any_of(CDbgVals, [](DbgVariableIntrinsic *DII) { return isa(DII); @@ -745,7 +745,7 @@ EXPECT_TRUE(replaceAllDbgUsesWith(C, D, D, DT)); SmallVector DDbgVals; - findDbgUsers(DDbgVals, &D); + D.findDbgUsers(DDbgVals); EXPECT_EQ(2U, DDbgVals.size()); EXPECT_TRUE(any_of(DDbgVals, [](DbgVariableIntrinsic *DII) { return isa(DII);