Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -90,7 +90,9 @@ Instruction * insertDbgValueIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo, DIExpression *Expr, const DILocation *DL, - BasicBlock *InsertBB, Instruction *InsertBefore); + BasicBlock *InsertBB, Instruction *InsertBefore, + llvm::Value *EntryValue = nullptr, + llvm::DIExpression *EntryDIExpr = nullptr); public: /// Construct a builder for a module. @@ -864,11 +866,14 @@ /// \param Expr A complex location expression. /// \param DL Debug info location. /// \param InsertBefore Location for the new intrinsic. - Instruction *insertDbgValueIntrinsic(llvm::Value *Val, - DILocalVariable *VarInfo, - DIExpression *Expr, - const DILocation *DL, - Instruction *InsertBefore); + /// \param EntryValue An entry value. + /// \param EntryDIExpr An entry value expression. + Instruction * + insertDbgValueIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo, + DIExpression *Expr, const DILocation *DL, + Instruction *InsertBefore, + llvm::Value *EntryValue = nullptr, + llvm::DIExpression *EntryDIExpr = nullptr); /// Replace the vtable holder in the given type. /// Index: llvm/include/llvm/IR/IntrinsicInst.h =================================================================== --- llvm/include/llvm/IR/IntrinsicInst.h +++ llvm/include/llvm/IR/IntrinsicInst.h @@ -211,6 +211,12 @@ return getVariableLocation(/* AllowNullOp = */ false); } + /// \return the entry value for the variable or nullptr. + Value *getVariableEntryValue() const; + + /// \return an expression that applies on the entry value. + DIExpression *getEntryExpression() const; + /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -894,6 +894,8 @@ llvm_metadata_ty]>; def int_dbg_value : Intrinsic<[], [llvm_metadata_ty, + llvm_metadata_ty, + llvm_metadata_ty, llvm_metadata_ty, llvm_metadata_ty]>; def int_dbg_addr : Intrinsic<[], Index: llvm/include/llvm/Transforms/Utils/Local.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Local.h +++ llvm/include/llvm/Transforms/Utils/Local.h @@ -283,6 +283,17 @@ /// dbg.addr. TinyPtrVector FindDbgDeclareUses(Value *V); +/// Represents an entry value. +struct EntryValue { + // Value that is entry one. + Value *V; + // Expression that applies onto V. + DIExpression *Expr; +}; + +/// Finds an entry value for a variable. +EntryValue findEntryValue(Value *V, Function &F); + /// Finds the llvm.dbg.value intrinsics describing a value. void findDbgValues(SmallVectorImpl &DbgValues, Value *V); Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -287,7 +287,8 @@ // a call site parameter expression and if that expression is just a register // location, emit it with addBReg and offset 0, because we should emit a DWARF // expression representing a value, rather than a location. - if (!isMemoryLocation() && !HasComplexExpression && + // FIXME: Simplify the statements regarding entry values. + if (!isMemoryLocation() && (!HasComplexExpression || isEntryValue()) && (!isParameterValue() || isEntryValue())) { for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) @@ -299,7 +300,7 @@ finalizeEntryValue(); if (isEntryValue() && !isIndirect() && !isParameterValue() && - DwarfVersion >= 4) + DwarfVersion >= 4 && !HasComplexExpression) emitOp(dwarf::DW_OP_stack_value); DwarfRegs.clear(); @@ -509,7 +510,7 @@ return; } case dwarf::DW_OP_plus_uconst: - assert(!isRegisterLocation()); + assert(!isRegisterLocation() || isEntryValue()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -540,7 +541,7 @@ emitOp(dwarf::DW_OP_deref); break; case dwarf::DW_OP_constu: - assert(!isRegisterLocation()); + assert(!isRegisterLocation() || isEntryValue()); emitConstu(Op->getArg(0)); break; case dwarf::DW_OP_LLVM_convert: { Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -901,10 +901,12 @@ DILocalVariable *VarInfo, DIExpression *Expr, const DILocation *DL, - Instruction *InsertBefore) { + Instruction *InsertBefore, + Value *EntryValue, + DIExpression *EntryDIExpr) { return insertDbgValueIntrinsic( V, VarInfo, Expr, DL, InsertBefore ? InsertBefore->getParent() : nullptr, - InsertBefore); + InsertBefore, EntryValue, EntryDIExpr); } Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, @@ -960,7 +962,8 @@ Instruction *DIBuilder::insertDbgValueIntrinsic( Value *V, DILocalVariable *VarInfo, DIExpression *Expr, - const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) { + const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore, + Value *EntryValue, DIExpression *EntryDIExpr) { assert(V && "no value passed to dbg.value"); assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value"); assert(DL && "Expected debug loc"); @@ -972,9 +975,17 @@ trackIfUnresolved(VarInfo); trackIfUnresolved(Expr); + + if (!EntryValue) + EntryValue = UndefValue::get(V->getType()); + if (!EntryDIExpr) + EntryDIExpr = DIExpression::get(VMContext, {}); + Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, V), MetadataAsValue::get(VMContext, VarInfo), - MetadataAsValue::get(VMContext, Expr)}; + MetadataAsValue::get(VMContext, Expr), + getDbgIntrinsicValueImpl(VMContext, EntryValue), + MetadataAsValue::get(VMContext, EntryDIExpr)}; IRBuilder<> B(DL->getContext()); initIRBuilder(B, DL, InsertBB, InsertBefore); Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1029,8 +1029,7 @@ // entry values of a simple register location. One reason for this is that // we currently can't calculate the size of the resulting DWARF block for // other expressions. - return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && - getNumElements() == 2; + return I->get() == expr_op_begin()->get() && I->getArg(0) == 1; } case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: @@ -1195,8 +1194,9 @@ if (EntryValue) { Ops.push_back(dwarf::DW_OP_LLVM_entry_value); // Add size info needed for entry value expression. - // Add plus one for target register operand. - Ops.push_back(Expr->getNumElements() + 1); + // It is always of size 1 at the moment, since we support + // simple register locations only. + Ops.push_back(1); } // If there are no ops to prepend, do not even add the DW_OP_stack_value. Index: llvm/lib/IR/IntrinsicInst.cpp =================================================================== --- llvm/lib/IR/IntrinsicInst.cpp +++ llvm/lib/IR/IntrinsicInst.cpp @@ -58,6 +58,23 @@ return getVariable()->getSizeInBits(); } +Value *DbgValueInst::getVariableEntryValue() const { + Value *Op = getArgOperand(3); + if (!Op) + return nullptr; + + auto *MD = cast(Op)->getMetadata(); + if (auto *V = dyn_cast(MD)) + return V->getValue(); + + return nullptr; +} + +DIExpression *DbgValueInst::getEntryExpression() const { + return cast( + cast(getArgOperand(4))->getMetadata()); +} + int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef NameTable, StringRef Name) { assert(Name.startswith("llvm.")); Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -1369,7 +1369,12 @@ return; } - Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, SI); + // If this value can be expressed in terms of an entry value, remember it and + // keep using it as a backup value for the variable. + auto EntryValue = findEntryValue(DV, *(DII->getParent()->getParent())); + + Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, SI, + EntryValue.V, EntryValue.Expr); } /// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value @@ -1593,6 +1598,63 @@ return DDIs; } +EntryValue llvm::findEntryValue(Value *V, Function &F) { + if (F.empty()) + return EntryValue{nullptr, nullptr}; + + // TODO: Avoid: + // 1) inlined vars + // 2) fragments + // 3) locals? (but we might be able to use entry vals for it now) + + DIExpression *DIExpr = DIExpression::get(F.getContext(), {}); + // If the value is an entry itself. + if (isa(V)) { + LLVM_DEBUG(llvm::dbgs() << "Found an entry value: "; V->dump();); + return EntryValue{V, DIExpr}; + } + + auto *BI = dyn_cast(V); + if (!BI) + return EntryValue{nullptr, nullptr}; + + Instruction *I = cast(V); + auto Op0 = I->getOperand(0); + auto Op1 = I->getOperand(1); + + // Not an entry value. + if (!isa(Op0)) + return EntryValue{nullptr, nullptr}; + + LLVM_DEBUG(llvm::dbgs() << "Express the entry value in terms of DWARF: "; + Op0->dump();); + + // Try to express the entry value in terms of DWARF. + // FIXME: This is from salvageDebugInfoImpl(). Factor this out into a func. + auto applyOffset = [&](uint64_t Offset) -> DIExpression * { + SmallVector Ops; + DIExpression::appendOffset(Ops, Offset); + DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, true); + return DIExpr; + }; + + auto *ConstInt = dyn_cast(Op1); + if (!ConstInt || ConstInt->getBitWidth() > 64) + return EntryValue{nullptr, nullptr}; + uint64_t Val = ConstInt->getSExtValue(); + switch (BI->getOpcode()) { + case Instruction::Add: { + auto DIExpr = applyOffset(Val); + + return EntryValue{Op0, DIExpr}; + } default: + // TODO: Address more ops. + return EntryValue{nullptr, nullptr}; + } + + return EntryValue{nullptr, nullptr}; +} + void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { // This function is hot. Check whether the value has any metadata to avoid a // DenseMap lookup. Index: llvm/test/Verifier/diexpression-valid-entry-value.ll =================================================================== --- llvm/test/Verifier/diexpression-valid-entry-value.ll +++ llvm/test/Verifier/diexpression-valid-entry-value.ll @@ -1,5 +1,7 @@ ; RUN: opt -S < %s 2>&1 | FileCheck %s -!named = !{!0} +!named = !{!0, !1, !2} ; CHECK-NOT: invalid expression !0 = !DIExpression(DW_OP_LLVM_entry_value, 1) +!1 = !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 3, DW_OP_stack_value) +!2 = !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_constu, 9, DW_OP_minus, DW_OP_stack_value)