Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -4729,6 +4729,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 the ``LiveDebugValues`` pass. + 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 the ``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: llvm/trunk/include/llvm/BinaryFormat/Dwarf.def =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/Dwarf.def +++ llvm/trunk/include/llvm/BinaryFormat/Dwarf.def @@ -633,6 +633,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: llvm/trunk/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/trunk/include/llvm/IR/DebugInfoMetadata.h +++ llvm/trunk/include/llvm/IR/DebugInfoMetadata.h @@ -2482,11 +2482,12 @@ ApplyOffset = 0, DerefBefore = 1 << 0, DerefAfter = 1 << 1, - StackValue = 1 << 2 + StackValue = 1 << 2, + EntryValue = 1 << 3 }; /// 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, uint8_t Flags, int64_t Offset = 0); @@ -2494,7 +2495,8 @@ /// 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. @@ -2558,6 +2560,13 @@ return true; return fragmentCmp(Other) == 0; } + + /// Check if the expression consists of exactly one entry value operand. + /// (This is the only configuration of entry values that is supported.) + bool isEntryValue() const { + return getNumElements() > 0 && + getElement(0) == dwarf::DW_OP_entry_value; + } }; inline bool operator==(const DIExpression::FragmentInfo &A, Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -41,6 +41,10 @@ static Register isDescribedByReg(const MachineInstr &MI) { assert(MI.isDebugValue()); assert(MI.getNumOperands() == 4); + // If the location of variable is an 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() : Register(); Index: llvm/trunk/lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -66,6 +66,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 DbgValueLoc &, const DbgValueLoc &); friend bool operator<(const DbgValueLoc &, const DbgValueLoc &); Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -52,6 +52,7 @@ class DebugLocEntry; class DIE; class DwarfCompileUnit; +class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; class LexicalScope; @@ -735,6 +736,10 @@ void addSectionLabel(const MCSymbol *Sym); const MCSymbol *getSectionLabel(const MCSection *S); + + static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DbgValueLoc &Value, + DwarfExpression &DwarfExpr); }; } // end namespace llvm Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1999,9 +1999,9 @@ } } -static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - const DbgValueLoc &Value, - DwarfExpression &DwarfExpr) { +void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DbgValueLoc &Value, + DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); @@ -2017,6 +2017,12 @@ if (Location.isIndirect()) DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor(DIExpr); + + if (DIExpr->isEntryValue()) { + DwarfExpr.setEntryValueFlag(); + DwarfExpr.addEntryValueExpression(Cursor); + } + const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; @@ -2048,11 +2054,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: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -119,6 +119,9 @@ /// The kind of location description being produced. enum { Unknown = 0, Register, Memory, Implicit }; + /// The flags of location description being produced. + enum { EntryValue = 1 }; + unsigned LocationKind : 3; unsigned LocationFlags : 2; unsigned DwarfVersion : 4; @@ -140,6 +143,10 @@ return LocationKind == Implicit; } + bool isEntryValue() const { + return LocationFlags & EntryValue; + } + Optional TagOffset; protected: @@ -252,6 +259,11 @@ LocationKind = Memory; } + /// Lock this down to become an entry value location. + void setEntryValueFlag() { + LocationFlags |= EntryValue; + } + /// Emit a machine register location. As an optimization this may also consume /// the prefix of a DwarfExpression if a more efficient representation for /// combining the register location and the first operation exists. @@ -266,6 +278,9 @@ DIExpressionCursor &Expr, unsigned MachineReg, unsigned FragmentOffsetInBits = 0); + /// Emit entry value dwarf operation. + void addEntryValueExpression(DIExpressionCursor &ExprCursor); + /// Emit all remaining operations in the DIExpressionCursor. /// /// \param FragmentOffsetInBits If this is one fragment out of multiple Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -248,6 +248,10 @@ addReg(Reg.DwarfRegNo, Reg.Comment); addOpPiece(Reg.Size); } + + if (isEntryValue() && DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + DwarfRegs.clear(); return true; } @@ -296,6 +300,19 @@ return true; } +void DwarfExpression::addEntryValueExpression(DIExpressionCursor &ExprCursor) { + auto Op = ExprCursor.take(); + assert(Op && Op->getOp() == dwarf::DW_OP_entry_value); + assert(!isMemoryLocation() && + "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)); +} + /// Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?". static bool isMemoryLocation(DIExpressionCursor ExprCursor) { while (ExprCursor) { Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ llvm/trunk/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; } @@ -275,7 +277,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]); } } @@ -284,6 +287,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(); @@ -291,6 +295,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: llvm/trunk/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/trunk/lib/IR/DebugInfoMetadata.cpp +++ llvm/trunk/lib/IR/DebugInfoMetadata.cpp @@ -836,6 +836,7 @@ case dwarf::DW_OP_deref_size: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_LLVM_tag_offset: + case dwarf::DW_OP_entry_value: return 2; default: return 1; @@ -876,6 +877,13 @@ 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 && + getNumElements() == 2; + } case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_constu: @@ -994,15 +1002,24 @@ Ops.push_back(dwarf::DW_OP_deref); bool StackValue = Flags & DIExpression::StackValue; + bool EntryValue = Flags & DIExpression::EntryValue; - 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; Index: llvm/trunk/test/Verifier/diexpression-entry-value.ll =================================================================== --- llvm/trunk/test/Verifier/diexpression-entry-value.ll +++ llvm/trunk/test/Verifier/diexpression-entry-value.ll @@ -0,0 +1,7 @@ +; RUN: not opt -S < %s 2>&1 | FileCheck %s + +!named = !{!0, !1, !2} +; CHECK: invalid expression +!0 = !DIExpression(DW_OP_entry_value, 4, DW_OP_constu, 0, DW_OP_stack_value) +!1 = !DIExpression(DW_OP_constu, 0, DW_OP_entry_value, 1, DW_OP_constu, 0) +!2 = !DIExpression(DW_OP_entry_value, 100, DW_OP_constu, 0) Index: llvm/trunk/test/Verifier/diexpression-valid-entry-value.ll =================================================================== --- llvm/trunk/test/Verifier/diexpression-valid-entry-value.ll +++ llvm/trunk/test/Verifier/diexpression-valid-entry-value.ll @@ -0,0 +1,5 @@ +; RUN: opt -S < %s 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK-NOT: invalid expression +!0 = !DIExpression(DW_OP_entry_value, 1) Index: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s =================================================================== --- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s +++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s @@ -0,0 +1,59 @@ +# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | llvm-dwarfdump - | FileCheck %s +# +# CHECK: DW_TAG_variable +# CHECK-NEXT: DW_AT_name ("a") +# CHECK-NEXT: DW_AT_location +# CHECK-NEXT: DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value) + + .section .debug_str,"MS",@progbits,1 +.Linfo_producer: + .asciz "hand-written DWARF" +.Lname_a: + .asciz "a" + + .section .debug_loc,"",@progbits +.Ldebug_loc0: + .quad 0 + .quad 1 + .short .Lloc0_end-.Lloc0_start # Loc expr size +.Lloc0_start: + .byte 243 # DW_OP_GNU_entry_value + .byte 1 # 1 + .byte 85 # super-register DW_OP_reg5 + .byte 159 # DW_OP_stack_value +.Lloc0_end: + .quad 0 + .quad 0 + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Lcu_end0-.Lcu_start0 # Length of Unit +.Lcu_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_producer # DW_AT_producer + .byte 5 # Abbrev [5] DW_TAG_variable + .long .Lname_a # DW_AT_name + .long .Ldebug_loc0 # DW_AT_location + .byte 0 # End Of Children Mark +.Lcu_end0: Index: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s =================================================================== --- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s +++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s @@ -0,0 +1,59 @@ +# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | llvm-dwarfdump - | FileCheck %s +# +# CHECK: DW_TAG_variable +# CHECK-NEXT: DW_AT_name ("a") +# CHECK-NEXT: DW_AT_location +# CHECK-NEXT: DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value) + + .section .debug_str,"MS",@progbits,1 +.Linfo_producer: + .asciz "hand-written DWARF" +.Lname_a: + .asciz "a" + + .section .debug_loc,"",@progbits +.Ldebug_loc0: + .quad 0 + .quad 1 + .short .Lloc0_end-.Lloc0_start # Loc expr size +.Lloc0_start: + .byte 163 # DW_OP_entry_value + .byte 1 # 1 + .byte 85 # super-register DW_OP_reg5 + .byte 159 # DW_OP_stack_value +.Lloc0_end: + .quad 0 + .quad 0 + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Lcu_end0-.Lcu_start0 # Length of Unit +.Lcu_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_producer # DW_AT_producer + .byte 5 # Abbrev [5] DW_TAG_variable + .long .Lname_a # DW_AT_name + .long .Ldebug_loc0 # DW_AT_location + .byte 0 # End Of Children Mark +.Lcu_end0: