Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -4693,6 +4693,17 @@ of the stack is treated as an address. The second stack entry is treated as an address space identifier. - ``DW_OP_stack_value`` marks a constant value. +- If an expression is marked with ``DW_OP_entry_value`` all register and + memory read operations refer to the respective value at the function entry. + The first operand of ``DW_OP_entry_value`` is the size of following + DWARF expression. + ``DW_OP_entry_value`` may appear after ``LiveDebugValues`` pass. + At this point LLVM only supports entry values for function parameters + that are unmodified throughout a function and that are described as + simple register location descriptions. + ``DW_OP_entry_value`` may also appear after ``AsmPrinter`` pass when + a call site parameter value (``DW_AT_call_site_parameter_value``) + is represented as entry value of the parameter. DWARF specifies three kinds of simple location descriptions: Register, memory, and implicit location descriptions. Note that a location description is Index: include/llvm/BinaryFormat/Dwarf.def =================================================================== --- include/llvm/BinaryFormat/Dwarf.def +++ include/llvm/BinaryFormat/Dwarf.def @@ -632,6 +632,8 @@ // Vendor extensions: // Extensions for GNU-style thread-local storage. HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU) +// The GNU entry value extension. +HANDLE_DW_OP(0xf3, GNU_entry_value, 0, GNU) // Extensions for Fission proposal. HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU) HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU) Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -2525,19 +2525,21 @@ unsigned &AddrClass); /// Constants for DIExpression::prepend. - enum { NoDeref = false, WithDeref = true, WithStackValue = true }; + enum { NoDeref = false, WithDeref = true, WithStackValue = true, + WithEntryValue = true }; /// Prepend \p DIExpr with a deref and offset operation and optionally turn it - /// into a stack value. + /// into a stack value or/and an entry value. static DIExpression *prepend(const DIExpression *Expr, bool DerefBefore, int64_t Offset = 0, bool DerefAfter = false, - bool StackValue = false); + bool StackValue = false, bool EntryValue = false); /// Prepend \p DIExpr with the given opcodes and optionally turn it into a /// stack value. static DIExpression *prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, - bool StackValue = false); + bool StackValue = false, + bool EntryValue = false); /// Append the opcodes \p Ops to \p DIExpr. Unlike \ref appendToStack, the /// returned expression is a stack value only if \p DIExpr is a stack value. @@ -2591,6 +2593,12 @@ return true; return fragmentCmp(Other) == 0; } + + /// Check if the expression contains entry value operand. + bool isEntryValue() const { + return getNumElements() > 0 && + getElement(0) == dwarf::DW_OP_entry_value; + } }; /// Global variables. Index: lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -41,6 +41,10 @@ static unsigned isDescribedByReg(const MachineInstr &MI) { assert(MI.isDebugValue()); assert(MI.getNumOperands() == 4); + // If location of variable is entry value (DW_OP_entry_value) + // do not consider it as a register location. + if (MI.getDebugExpression()->isEntryValue()) + return 0; // If location of variable is described using a register (directly or // indirectly), this register is always a first operand. return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -73,6 +73,7 @@ const ConstantInt *getConstantInt() const { return Constant.CIP; } MachineLocation getLoc() const { return Loc; } bool isFragment() const { return getExpression()->isFragment(); } + bool isEntryVal() const { return getExpression()->isEntryValue(); } const DIExpression *getExpression() const { return Expression; } friend bool operator==(const Value &, const Value &); friend bool operator<(const Value &, const Value &); Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -269,8 +269,8 @@ // It would be better if this were unconditional, but malformed input that // mixes non-fragments and fragments for the same variable is too expensive // to detect in the verifier. - if (DwarfExpr->isUnknownLocation()) - DwarfExpr->setMemoryLocationKind(); + if (DwarfExpr->isLocationUnknown()) + DwarfExpr->setMemoryLocationFlag(); DwarfExpr->addExpression(Expr); } if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { @@ -674,7 +674,7 @@ if (Expr) Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) addOpAddress(*Loc, FrameSymbol); else @@ -1105,7 +1105,7 @@ DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); DIExpressionCursor Cursor({}); const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); @@ -1129,7 +1129,7 @@ const DIExpression *DIExpr = DV.getSingleExpression(); DwarfExpr.addFragmentOffset(DIExpr); if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); DIExpressionCursor Cursor(DIExpr); const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -14,6 +14,7 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H #include "AddressPool.h" +#include "DebugLocEntry.h" #include "DebugLocStream.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" @@ -51,6 +52,7 @@ class DebugLocEntry; class DIE; class DwarfCompileUnit; +class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; class LexicalScope; @@ -732,6 +734,10 @@ void addSectionLabel(const MCSymbol *Sym); const MCSymbol *getSectionLabel(const MCSection *S); + + static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr); }; } // end namespace llvm Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1954,9 +1954,9 @@ } } -static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - const DebugLocEntry::Value &Value, - DwarfExpression &DwarfExpr) { +void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); @@ -1969,9 +1969,16 @@ DwarfExpr.addUnsignedConstant(Value.getInt()); } else if (Value.isLocation()) { MachineLocation Location = Value.getLoc(); - if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor(DIExpr); + if (Location.isIndirect()) + DwarfExpr.setMemoryLocationFlag(); + + if (DIExpr->isEntryValue()) { + DwarfExpr.setEntryValueLocationFlag(); + if (!DwarfExpr.addEntryValueExpression(Cursor)) + return; + } + const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; @@ -2003,11 +2010,11 @@ "fragments are expected to be sorted"); for (auto Fragment : Values) - emitDebugLocValue(AP, BT, Fragment, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - emitDebugLocValue(AP, BT, Value, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); } Index: lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.h +++ lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -117,9 +117,38 @@ unsigned SubRegisterSizeInBits = 0; unsigned SubRegisterOffsetInBits = 0; - /// The kind of location description being produced. - enum { Unknown = 0, Register, Memory, Implicit } LocationKind = Unknown; + /// The flags of location description being produced. + enum LocationFlags { + Unknown = 0, + Register = 1, + Memory = 1 << 1, + Implicit = 1 << 2, + EntryValueExpr = 1 << 3 + }; + + uint8_t LocationFlags = 0; + +public: + bool isLocationUnknown() { + return LocationFlags == Unknown; + } + + bool isLocationRegister() { + return LocationFlags & Register; + } + + bool isLocationMemory() { + return LocationFlags & Memory; + } + bool isLocationImplicit() { + return LocationFlags & Implicit; + } + + bool isLocationEntryValueExpr() { + return LocationFlags & EntryValueExpr; + } +protected: /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed /// to represent a subregister. void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) { @@ -218,13 +247,15 @@ /// Emit an unsigned constant. void addUnsignedConstant(const APInt &Value); - bool isMemoryLocation() const { return LocationKind == Memory; } - bool isUnknownLocation() const { return LocationKind == Unknown; } - /// Lock this down to become a memory location description. - void setMemoryLocationKind() { - assert(LocationKind == Unknown); - LocationKind = Memory; + void setMemoryLocationFlag() { + assert(isLocationUnknown() || isLocationEntryValueExpr()); + LocationFlags |= Memory; + } + + /// Lock this down to become an entry value location. + void setEntryValueLocationFlag() { + LocationFlags |= EntryValueExpr; } /// Emit a machine register location. As an optimization this may also consume @@ -241,6 +272,9 @@ DIExpressionCursor &Expr, unsigned MachineReg, unsigned FragmentOffsetInBits = 0); + /// Emit entry value dwarf operation. + bool addEntryValueExpression(DIExpressionCursor &ExprCursor); + /// Emit all remaining operations in the DIExpressionCursor. /// /// \param FragmentOffsetInBits If this is one fragment out of multiple Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -40,9 +40,10 @@ void DwarfExpression::addReg(int DwarfReg, const char *Comment) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert((LocationKind == Unknown || LocationKind == Register) && + assert((isLocationUnknown() || isLocationRegister() || + isLocationEntryValueExpr()) && "location description already locked down"); - LocationKind = Register; + LocationFlags |= Register; if (DwarfReg < 32) { emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment); } else { @@ -53,7 +54,7 @@ void DwarfExpression::addBReg(int DwarfReg, int Offset) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert(LocationKind != Register && "location description already locked down"); + assert(!isLocationRegister() && "location description already locked down"); if (DwarfReg < 32) { emitOp(dwarf::DW_OP_breg0 + DwarfReg); } else { @@ -184,21 +185,24 @@ } void DwarfExpression::addSignedConstant(int64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr()); + LocationFlags |= Implicit; emitOp(dwarf::DW_OP_consts); emitSigned(Value); } void DwarfExpression::addUnsignedConstant(uint64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr()); + LocationFlags |= Implicit; emitConstu(Value); } void DwarfExpression::addUnsignedConstant(const APInt &Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr()); + LocationFlags |= Implicit; unsigned Size = Value.getBitWidth(); const uint64_t *Data = Value.getRawData(); @@ -222,7 +226,7 @@ unsigned FragmentOffsetInBits) { auto Fragment = ExprCursor.getFragmentInfo(); if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) { - LocationKind = Unknown; + LocationFlags = Unknown; return false; } @@ -237,17 +241,21 @@ // operation to multiple DW_OP_pieces. if (HasComplexExpression && DwarfRegs.size() > 1) { DwarfRegs.clear(); - LocationKind = Unknown; + LocationFlags = Unknown; return false; } // Handle simple register locations. - if (LocationKind != Memory && !HasComplexExpression) { + if (!isLocationMemory() && !HasComplexExpression) { for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) addReg(Reg.DwarfRegNo, Reg.Comment); addOpPiece(Reg.Size); } + + if (isLocationEntryValueExpr() && DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + DwarfRegs.clear(); return true; } @@ -258,7 +266,7 @@ return Op.getOp() == dwarf::DW_OP_stack_value; })) { DwarfRegs.clear(); - LocationKind = Unknown; + LocationFlags = Unknown; return false; } @@ -311,6 +319,21 @@ return true; } +bool DwarfExpression::addEntryValueExpression(DIExpressionCursor &ExprCursor) { + auto Op = ExprCursor.take(); + assert(Op && Op->getOp() == dwarf::DW_OP_entry_value); + assert(!isLocationMemory() && + "We don't support entry values of memory locations yet"); + + if (DwarfVersion >= 5) + emitOp(dwarf::DW_OP_entry_value); + else + emitOp(dwarf::DW_OP_GNU_entry_value); + emitUnsigned(Op->getArg(0)); + + return true; +} + void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, unsigned FragmentOffsetInBits) { // If we need to mask out a subregister, do it now, unless the next @@ -343,18 +366,18 @@ SizeInBits = std::min(SizeInBits, SubRegisterSizeInBits); // Emit a DW_OP_stack_value for implicit location descriptions. - if (LocationKind == Implicit) + if (isLocationImplicit()) addStackValue(); // Emit the DW_OP_piece. addOpPiece(SizeInBits, SubRegisterOffsetInBits); setSubRegisterPiece(0, 0); // Reset the location description kind. - LocationKind = Unknown; + LocationFlags = Unknown; return; } case dwarf::DW_OP_plus_uconst: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -375,16 +398,16 @@ emitOp(Op->getOp()); break; case dwarf::DW_OP_deref: - assert(LocationKind != Register); - if (LocationKind != Memory && ::isMemoryLocation(ExprCursor)) + assert(!isLocationRegister()); + if (!isLocationMemory() && isMemoryLocation(ExprCursor)) // Turning this into a memory location description makes the deref // implicit. - LocationKind = Memory; + LocationFlags |= Memory; else emitOp(dwarf::DW_OP_deref); break; case dwarf::DW_OP_constu: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitConstu(Op->getArg(0)); break; case dwarf::DW_OP_LLVM_convert: { @@ -424,14 +447,14 @@ break; } case dwarf::DW_OP_stack_value: - LocationKind = Implicit; + LocationFlags |= Implicit; break; case dwarf::DW_OP_swap: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_swap); break; case dwarf::DW_OP_xderef: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_xderef); break; default: @@ -439,7 +462,7 @@ } } - if (LocationKind == Implicit) + if (isLocationImplicit()) // Turn this into an implicit location description. addStackValue(); } Index: lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFExpression.cpp +++ lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -97,8 +97,10 @@ Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); + Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); return Descriptions; } @@ -271,7 +273,8 @@ } else { if (Signed) OS << format(" %+" PRId64, (int64_t)Operands[Operand]); - else + else if (Opcode != DW_OP_entry_value && + Opcode != DW_OP_GNU_entry_value) OS << format(" 0x%" PRIx64, Operands[Operand]); } } @@ -280,6 +283,7 @@ void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U, bool IsEH) const { + uint32_t EntryValExprSize = 0; for (auto &Op : *this) { if (!Op.print(OS, this, RegInfo, U, IsEH)) { uint32_t FailOffset = Op.getEndOffset(); @@ -287,6 +291,20 @@ OS << format(" %02x", Data.getU8(&FailOffset)); return; } + + if (Op.getCode() == DW_OP_entry_value || + Op.getCode() == DW_OP_GNU_entry_value) { + OS << "("; + EntryValExprSize = Op.getRawOperand(0); + continue; + } + + if (EntryValExprSize) { + EntryValExprSize--; + if (EntryValExprSize == 0) + OS << ")"; + } + if (Op.getEndOffset() < Data.getData().size()) OS << ", "; } Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -834,6 +834,7 @@ return 3; case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: + case dwarf::DW_OP_entry_value: return 2; default: return 1; @@ -874,6 +875,12 @@ return false; break; } + case dwarf::DW_OP_entry_value: + // An entry value operator must appear at the begin and the size + // of following expression should be 1, because we support only + // entry values of a simple register location. + return I->get() == expr_op_begin()->get() && + I->getArg(0) == 1; case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: @@ -966,7 +973,7 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, bool DerefBefore, int64_t Offset, bool DerefAfter, - bool StackValue) { + bool StackValue, bool EntryValue) { SmallVector Ops; if (DerefBefore) Ops.push_back(dwarf::DW_OP_deref); @@ -975,14 +982,21 @@ if (DerefAfter) Ops.push_back(dwarf::DW_OP_deref); - return prependOpcodes(Expr, Ops, StackValue); + return prependOpcodes(Expr, Ops, StackValue, EntryValue); } DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, - bool StackValue) { + bool StackValue, bool EntryValue) { assert(Expr && "Can't prepend ops to this expression"); + if (EntryValue) { + Ops.push_back(dwarf::DW_OP_entry_value); + // Add size info needed for entry value expression. + // Add plus one for target register operand. + Ops.push_back(Expr->getNumElements() + 1); + } + // If there are no ops to prepend, do not even add the DW_OP_stack_value. if (Ops.empty()) StackValue = false;