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; @@ -189,6 +190,11 @@ ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) void *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; @@ -202,6 +208,10 @@ /// The module destructor. This will dropAllReferences. ~Module(); + void insertVarAddressMap(DbgVariableIntrinsic *DDI); + + Value *findVarAddressMap(Value *Var); + /// @} /// @name Module Level Accessors /// @{ Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -997,17 +997,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/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/SymbolTableListTraits.h" @@ -625,3 +626,18 @@ } return GV; } + +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/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -1609,6 +1609,20 @@ bool llvm::salvageDebugInfo(Instruction &I) { SmallVector DbgUsers; + + // Return false if any of the operand is already deleted + for (unsigned i = 0; i < I.getNumOperands(); ++i) + if (!I.getOperand(i)) + return false; + + // Preserve the information we may need later when called function from + // current function is inlined. We need this information for + // DW_OP_LLVM_implicit_pointer. + if (auto DDI = dyn_cast(&I)) + if (I.getModule()->getDwarfVersion() >= 5) + if (DDI->isAddressOfVariable()) + I.getModule()->insertVarAddressMap(DDI); + findDbgUsers(DbgUsers, &I); if (DbgUsers.empty()) return false; @@ -1625,6 +1639,23 @@ Instruction &I, ArrayRef DbgUsers) { auto &Ctx = I.getContext(); auto wrapMD = [&](Value *V) { return wrapValueInMetadata(Ctx, V); }; + bool Changed = false; + Value *DebugDeclareAddress = nullptr; + + if ((I.getModule()->getDwarfVersion() >= 5) && isa(I)) { + 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 = I.getModule()->findVarAddressMap(&I); + } for (auto *DII : DbgUsers) { // Do not add DW_OP_stack_value for DbgDeclare and DbgAddr, because they @@ -1638,14 +1669,74 @@ // salvageDebugInfoImpl should fail on examining the first element of // DbgUsers, or none of them. if (!DIExpr) - return false; + 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 (isa(I) && + (!DebugDeclareAddress || DII->isAddressOfVariable() || + !DII->getExpression()->extractIfOffset(ExprOffset))) + continue; + + if (isa(I)) { + // It will cause below transformation + // + // Before transformation + // + // %a = alloca [2 x i32], align 4 + // call void @llvm.dbg.declare(metadata [2 x i32]* %arr, metadata !16, + // metadata !DIExpression()), !dbg !22 + // + // call void @llvm.dbg.value(metadata [2 x i32]* %arr, metadata !20, + // metadata !DIExpression()), !dbg !24 + // + // call void @llvm.dbg.value(metadata [2 x i32]* %arr, metadata !20, + // metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)), + // !dbg !24 + // + // !16 = !DILocalVariable(name: "arr", scope: !12, file: !3, line: 5, + // type: !17) !20 = !DILocalVariable(name: "ptr", scope: !12, file: !3, + // line: 6, type: !21) + // + // + // After transformation + // + // %a = alloca [2 x i32], align 4 + // call void @llvm.dbg.declare(metadata [2 x i32]* %arr, metadata !16, + // metadata !DIExpression()), !dbg !22 + // + // call void @llvm.dbg.deref_value(metadata !16, metadata !20, metadata + // !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 0)), !dbg + // !24 + // + // call void @llvm.dbg.deref_value(metadata !16, metadata !20, metadata + // !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 4)), !dbg + // !24 + // + SmallVector Ops; + Ops.push_back(dwarf::DW_OP_LLVM_implicit_pointer); + Ops.push_back(dwarf::DW_OP_LLVM_arg0); + Ops.push_back(ExprOffset); + DIExpr = DIExpression::get(DIExpr->getContext(), Ops); + DIBuilder DIB(*I.getModule(), /*AllowUnresolved*/ false); + DIB.insertDbgDerefValueIntrinsic(DebugDeclareAddress, + DII->getVariable(), DIExpr, + DII->getDebugLoc(), DII); + DII->eraseFromParent(); + } else { + DII->setOperand(0, wrapMD(I.getOperand(0))); - DII->setOperand(0, wrapMD(I.getOperand(0))); - DII->setOperand(2, MetadataAsValue::get(Ctx, DIExpr)); - LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); + DII->setOperand(2, MetadataAsValue::get(Ctx, DIExpr)); + LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); + } + Changed = true; } - return true; + return Changed; } DIExpression *llvm::salvageDebugInfoImpl(Instruction &I, @@ -1729,6 +1820,8 @@ // *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(&I)) { + return SrcDIExpr; } return nullptr; }