Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -4666,6 +4666,10 @@ here, respectively) of the variable fragment from the working expression. Note that contrary to DW_OP_bit_piece, the offset is describing the location within the described source variable. +- ``DW_OP_LLVM_convert, 16, DW_ATE_signed`` specifies a bit size and encoding + (``16`` and ``DW_ATE_signed`` here, respectively) to which the top of the + expression stack is to be converted. Maps into a ``DW_OP_convert`` operation + that references a base type constructed from the supplied values. - ``DW_OP_swap`` swaps top two stack entries. - ``DW_OP_xderef`` provides extended dereference mechanism. The entry at the top of the stack is treated as an address. The second stack entry is treated as an Index: include/llvm/BinaryFormat/Dwarf.h =================================================================== --- include/llvm/BinaryFormat/Dwarf.h +++ include/llvm/BinaryFormat/Dwarf.h @@ -129,7 +129,8 @@ #include "llvm/BinaryFormat/Dwarf.def" DW_OP_lo_user = 0xe0, DW_OP_hi_user = 0xff, - DW_OP_LLVM_fragment = 0x1000 ///< Only used in LLVM metadata. + DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. + DW_OP_LLVM_convert = 0x1001 ///< Only used in LLVM metadata. }; enum TypeKind : uint8_t { Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -510,7 +510,7 @@ void EmitSLEB128(int64_t Value, const char *Desc = nullptr) const; /// Emit the specified unsigned leb128 value. - void EmitULEB128(uint64_t Value, const char *Desc = nullptr) const; + void EmitULEB128(uint64_t Value, const char *Desc = nullptr, unsigned PadTo = 0) const; /// Emit a .byte 42 directive that corresponds to an encoding. If verbose /// assembly output is enabled, we output comments describing the encoding. Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -38,6 +38,7 @@ class AsmPrinter; class DIE; class DIEUnit; +class DwarfCompileUnit; class MCExpr; class MCSection; class MCSymbol; @@ -229,6 +230,23 @@ void print(raw_ostream &O) const; }; +//===--------------------------------------------------------------------===// +/// A BaseTypeRef DIE. +class DIEBaseTypeRef { + const DwarfCompileUnit *CU; + const uint64_t Index; + static constexpr unsigned ULEB128PadSize = 4; + +public: + explicit DIEBaseTypeRef(const DwarfCompileUnit *TheCU, uint64_t Idx) + : CU(TheCU), Index(Idx) {} + + void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const; + unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const; + + void print(raw_ostream &O) const; +}; + //===--------------------------------------------------------------------===// /// A simple label difference DIE. /// @@ -349,7 +367,7 @@ /// should be stored by reference instead of by value. using ValTy = AlignedCharArrayUnion; + DIELoc *, DIELocList, DIEBaseTypeRef *>; static_assert(sizeof(ValTy) <= sizeof(uint64_t) || sizeof(ValTy) <= sizeof(void *), @@ -501,6 +519,18 @@ } Last = &N; } + + void push_front(Node &N) { + assert(N.Next.getPointer() == &N && "Expected unlinked node"); + assert(N.Next.getInt() == true && "Expected unlinked node"); + + if (Last) { + N.Next.setPointerAndInt(Last->Next.getPointer(), false); + Last->Next.setPointerAndInt(&N, true); + } else { + Last = &N; + } + } }; template class IntrusiveBackList : IntrusiveBackListBase { @@ -508,8 +538,15 @@ using IntrusiveBackListBase::empty; void push_back(T &N) { IntrusiveBackListBase::push_back(N); } + void push_front(T &N) { IntrusiveBackListBase::push_front(N); } T &back() { return *static_cast(Last); } const T &back() const { return *static_cast(Last); } + T &front() { + return *static_cast(Last ? Last->Next.getPointer() : nullptr); + } + const T &front() const { + return *static_cast(Last ? Last->Next.getPointer() : nullptr); + } class const_iterator; class iterator @@ -772,6 +809,13 @@ return Children.back(); } + DIE &addChildFront(DIE *Child) { + assert(!Child->getParent() && "Child should be orphaned"); + Child->Owner = this; + Children.push_front(*Child); + return Children.front(); + } + /// Find a value in the DIE with the attribute given. /// /// Returns a default-constructed DIEValue (where \a DIEValue::getType() Index: include/llvm/CodeGen/DIEValue.def =================================================================== --- include/llvm/CodeGen/DIEValue.def +++ include/llvm/CodeGen/DIEValue.def @@ -34,6 +34,7 @@ HANDLE_DIEVALUE_SMALL(String) HANDLE_DIEVALUE_SMALL(Expr) HANDLE_DIEVALUE_SMALL(Label) +HANDLE_DIEVALUE_SMALL(BaseTypeRef) HANDLE_DIEVALUE_LARGE(Delta) HANDLE_DIEVALUE_SMALL(Entry) HANDLE_DIEVALUE_LARGE(Block) Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -634,7 +634,7 @@ /// Special case of EmitULEB128Value that avoids the client having to /// pass in a MCExpr for constant integers. - void EmitULEB128IntValue(uint64_t Value); + void EmitULEB128IntValue(uint64_t Value, unsigned PadTo = 0); /// Special case of EmitSLEB128Value that avoids the client having to /// pass in a MCExpr for constant integers. Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4835,6 +4835,15 @@ return TokError(Twine("invalid DWARF op '") + Lex.getStrVal() + "'"); } + if (Lex.getKind() == lltok::DwarfAttEncoding) { + if (unsigned Op = dwarf::getAttributeEncoding(Lex.getStrVal())) { + Lex.Lex(); + Elements.push_back(Op); + continue; + } + return TokError(Twine("invalid DWARF attribute encoding '") + Lex.getStrVal() + "'"); + } + if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned()) return TokError("expected unsigned integer"); Index: lib/BinaryFormat/Dwarf.cpp =================================================================== --- lib/BinaryFormat/Dwarf.cpp +++ lib/BinaryFormat/Dwarf.cpp @@ -143,6 +143,8 @@ case DW_OP_##NAME: \ return "DW_OP_" #NAME; #include "llvm/BinaryFormat/Dwarf.def" + case DW_OP_LLVM_convert: + return "DW_OP_LLVM_convert"; case DW_OP_LLVM_fragment: return "DW_OP_LLVM_fragment"; } @@ -153,6 +155,7 @@ #define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) \ .Case("DW_OP_" #NAME, DW_OP_##NAME) #include "llvm/BinaryFormat/Dwarf.def" + .Case("DW_OP_LLVM_convert", DW_OP_LLVM_convert) .Case("DW_OP_LLVM_fragment", DW_OP_LLVM_fragment) .Default(0); } Index: lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -42,11 +42,11 @@ OutStreamer->EmitSLEB128IntValue(Value); } -void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc) const { +void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc, unsigned PadTo) const { if (isVerbose() && Desc) OutStreamer->AddComment(Desc); - OutStreamer->EmitULEB128IntValue(Value); + OutStreamer->EmitULEB128IntValue(Value, PadTo); } /// Emit something like ".uleb128 Hi-Lo". Index: lib/CodeGen/AsmPrinter/ByteStreamer.h =================================================================== --- lib/CodeGen/AsmPrinter/ByteStreamer.h +++ lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -31,7 +31,7 @@ // For now we're just handling the calls we need for dwarf emission/hashing. virtual void EmitInt8(uint8_t Byte, const Twine &Comment = "") = 0; virtual void EmitSLEB128(uint64_t DWord, const Twine &Comment = "") = 0; - virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "") = 0; + virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "", unsigned PadTo = 0) = 0; }; class APByteStreamer final : public ByteStreamer { @@ -48,7 +48,7 @@ AP.OutStreamer->AddComment(Comment); AP.EmitSLEB128(DWord); } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { AP.OutStreamer->AddComment(Comment); AP.EmitULEB128(DWord); } @@ -65,7 +65,7 @@ void EmitSLEB128(uint64_t DWord, const Twine &Comment) override { Hash.addSLEB128(DWord); } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { Hash.addULEB128(DWord); } }; @@ -102,9 +102,9 @@ } } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { raw_svector_ostream OSE(Buffer); - unsigned Length = encodeULEB128(DWord, OSE); + unsigned Length = encodeULEB128(DWord, OSE, PadTo); if (GenerateComments) { Comments.push_back(Comment.str()); // Add some empty comments to keep the Buffer and Comments vectors aligned Index: lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -505,6 +505,27 @@ LLVM_DUMP_METHOD void DIELabel::print(raw_ostream &O) const { O << "Lbl: " << Label->getName(); } +//===----------------------------------------------------------------------===// +// DIEBaseTypeRef Implementation +//===----------------------------------------------------------------------===// + +/// EmitValue - Emit base type reference. +/// +void DIEBaseTypeRef::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { + uint64_t Offset = CU->ExprRefedBaseTypes[Index].Die->getOffset(); + assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); + AP->EmitULEB128(Offset, nullptr, ULEB128PadSize); +} + +/// SizeOf - Determine size of the base type reference in bytes. +/// +unsigned DIEBaseTypeRef::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { + return ULEB128PadSize; +} + +LLVM_DUMP_METHOD +void DIEBaseTypeRef::print(raw_ostream &O) const { O << "BaseTypeRef: " << Index; } + //===----------------------------------------------------------------------===// // DIEDelta Implementation //===----------------------------------------------------------------------===// Index: lib/CodeGen/AsmPrinter/DIEHash.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIEHash.cpp +++ lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -225,7 +225,7 @@ DwarfDebug &DD = *AP->getDwarfDebug(); const DebugLocStream &Locs = DD.getDebugLocs(); for (const auto &Entry : Locs.getEntries(Locs.getList(LocList.getValue()))) - DD.emitDebugLocEntry(Streamer, Entry); + DD.emitDebugLocEntry(Streamer, Entry, nullptr); } // Hash an individual attribute \param Attr based on the type of attribute and @@ -309,6 +309,7 @@ // FIXME: It's uncertain whether or not we should handle this at the moment. case DIEValue::isExpr: case DIEValue::isLabel: + case DIEValue::isBaseTypeRef: case DIEValue::isDelta: llvm_unreachable("Add support for additional value types."); } Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -148,8 +148,10 @@ } /// Lower this entry into a DWARF expression. - void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, - const DIBasicType *BT); + void finalize(const AsmPrinter &AP, + DebugLocStream::ListBuilder &List, + const DIBasicType *BT, + DwarfCompileUnit &TheCU); }; /// Compare two Values for equality. Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -124,6 +124,16 @@ const DIExpression *Expr; }; + struct BaseTypeRef { + BaseTypeRef(unsigned BitSize, dwarf::TypeKind Encoding) : + BitSize(BitSize), Encoding(Encoding) {} + unsigned BitSize; + dwarf::TypeKind Encoding; + DIE *Die = nullptr; + }; + + std::vector ExprRefedBaseTypes; + /// Get or create global variable DIE. DIE * getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, @@ -199,6 +209,8 @@ SmallVectorImpl &Children, bool *HasNonScopeChildren = nullptr); + void createBaseTypeDIEs(); + /// Construct a DIE for this subprogram scope. DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope); @@ -313,6 +325,8 @@ void setDWOId(uint64_t DwoId) { DWOId = DwoId; } bool hasDwarfPubSections() const; + + void addBaseTypeRef(DIEValueList &Die, int64_t Idx); }; } // end namespace llvm Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -17,6 +17,7 @@ #include "DwarfUnit.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -1185,3 +1186,27 @@ : dwarf::DW_AT_GNU_addr_base, Label, TLOF.getDwarfAddrSection()->getBeginSymbol()); } + +void DwarfCompileUnit::addBaseTypeRef(DIEValueList &Die, int64_t Idx) { + Die.addValue(DIEValueAllocator, (dwarf::Attribute)0, dwarf::DW_FORM_udata, + DIEBaseTypeRef(this, Idx)); +} + +void DwarfCompileUnit::createBaseTypeDIEs() { + // Insert the base type DIEs directly after the CU. Maintain order by + // iterating backwards and inserting to the front of CU child list. + for (std::vector::reverse_iterator + I = ExprRefedBaseTypes.rbegin(), E = ExprRefedBaseTypes.rend(); + I != E; ++I ) { + auto &Btr = *I; + DIE &Die = getUnitDie().addChildFront( + DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type)); + Twine T(dwarf::AttributeEncodingString(Btr.Encoding) + "_" + Twine(Btr.BitSize)); + SmallString<32> Str; + addString(Die, dwarf::DW_AT_name, T.toStringRef(Str)); + addUInt(Die, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Btr.Encoding); + addUInt(Die, dwarf::DW_AT_byte_size, None, Btr.BitSize / 8); + + Btr.Die = &Die; + } +} Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -682,10 +682,12 @@ /// Emit an entry for the debug loc section. This can be used to /// handle an entry that's going to be emitted into the debug loc section. void emitDebugLocEntry(ByteStreamer &Streamer, - const DebugLocStream::Entry &Entry); + const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU); /// Emit the location for a debug loc entry, including the size header. - void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry); + void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU); /// Find the MDNode for the given reference. template T *resolve(TypedDINodeRef Ref) const { Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -161,6 +161,7 @@ static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "writer"; static const char *const DbgTimerDescription = "DWARF Debug Writer"; +static constexpr unsigned ULEB128PadSize = 4; void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) { BS.EmitInt8( @@ -176,6 +177,11 @@ BS.EmitULEB128(Value, Twine(Value)); } +void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { + assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit"); + BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize); +} + bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) { // This information is not available while emitting .debug_loc entries. @@ -940,6 +946,11 @@ assert(CurFn == nullptr); assert(CurMI == nullptr); + for (const auto &P : CUMap) { + auto &CU = *P.second; + CU.createBaseTypeDIEs(); + } + // If we aren't actually generating debug info (check beginModule - // conditionalized on !DisableDebugInfoPrinting and the presence of the // llvm.dbg.cu metadata node) @@ -1369,7 +1380,7 @@ // Finalize the entry by lowering it into a DWARF bytestream. for (auto &Entry : Entries) - Entry.finalize(*Asm, List, BT); + Entry.finalize(*Asm, List, BT, TheCU); } // For each InlinedEntity collected from DBG_LABEL instructions, convert to @@ -1911,13 +1922,108 @@ StringOffsetsSection, /* UseRelativeOffsets = */ true); } -void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, - const DebugLocStream::Entry &Entry) { +void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const + DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU) { auto &&Comments = DebugLocs.getComments(Entry); auto Comment = Comments.begin(); auto End = Comments.end(); - for (uint8_t Byte : DebugLocs.getBytes(Entry)) - Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); + + enum {Idle, SkipLEB128, BaseTypeFromULEB128} State = Idle; + uint64_t ULEB128Value; + uint64_t ULEB128Shift; + unsigned NumSkipLEB128s; + for (uint8_t Byte : DebugLocs.getBytes(Entry)) { + bool EmitByte = true; + // XXX: This is admittedly pretty stupid but sadly appears to be the + // easiest way to pass custom values as the expressions are inserted into a + // byte stream rather early (see DwarfExpression::addExpression). + switch (State) { + case Idle: + switch (Byte) { + default: + if (dwarf::DW_OP_breg0 <= Byte && Byte <= dwarf::DW_OP_breg0 + 31) { + NumSkipLEB128s = 1; + State = SkipLEB128; + } else if ((dwarf::DW_OP_lit0 <= Byte && Byte <= dwarf::DW_OP_lit0 + 31) || + (dwarf::DW_OP_reg0 <= Byte && Byte <= dwarf::DW_OP_reg0 + 31)) { + // Do nothing. + } else { + llvm_unreachable("unhandled opcode found in expression"); + } + break; + // Ops with 0 arguments. + case dwarf::DW_OP_and: + case dwarf::DW_OP_deref: + case dwarf::DW_OP_div: + case dwarf::DW_OP_dup: + case dwarf::DW_OP_minus: + case dwarf::DW_OP_mod: + case dwarf::DW_OP_mul: + case dwarf::DW_OP_not: + case dwarf::DW_OP_or: + case dwarf::DW_OP_plus: + case dwarf::DW_OP_shl: + case dwarf::DW_OP_shr: + case dwarf::DW_OP_shra: + case dwarf::DW_OP_stack_value: + case dwarf::DW_OP_swap: + case dwarf::DW_OP_xderef: + case dwarf::DW_OP_xor: + // Do nothing. + break; + // Ops with 2 [SU]LEB128 arguments. + case dwarf::DW_OP_bit_piece: + case dwarf::DW_OP_bregx: + NumSkipLEB128s = 2; + State = SkipLEB128; + break; + // Ops with 1 [SU]LEB128 arguments. + case dwarf::DW_OP_consts: + case dwarf::DW_OP_constu: + case dwarf::DW_OP_fbreg: + case dwarf::DW_OP_piece: + case dwarf::DW_OP_plus_uconst: + case dwarf::DW_OP_regx: + NumSkipLEB128s = 1; + State = SkipLEB128; + break; + case dwarf::DW_OP_convert: + ULEB128Value = 0; + ULEB128Shift = 0; + State = BaseTypeFromULEB128; + break; + } + break; + + case SkipLEB128: + if (!(Byte & 0x80) && --NumSkipLEB128s == 0) + State = Idle; + break; + case BaseTypeFromULEB128: + EmitByte = false; + ULEB128Value |= (Byte & 0x7f) << ULEB128Shift; + if (Byte & 0x80) + ULEB128Shift += 7; + else { + if (CU) { + uint64_t Offset = CU->ExprRefedBaseTypes[ULEB128Value].Die->getOffset(); + assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); + Asm->EmitULEB128(Offset, nullptr, ULEB128PadSize); + } else { + // Emit a reference to the 'generic type'. + Asm->EmitULEB128(0); + } + State = Idle; + } + if (Comment != End) + Comment++; + break; + } + + if (EmitByte) + Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); + } } static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, @@ -1951,11 +2057,12 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, - const DIBasicType *BT) { + const DIBasicType *BT, + DwarfCompileUnit &TheCU) { assert(Begin != End && "unexpected location list entry with empty range"); DebugLocStream::EntryBuilder Entry(List, Begin, End); BufferByteStreamer Streamer = Entry.getStreamer(); - DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer); + DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer, TheCU); const DebugLocEntry::Value &Value = Values[0]; if (Value.isFragment()) { // Emit all fragments that belong to the same variable and range. @@ -1975,7 +2082,8 @@ DwarfExpr.finalize(); } -void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { +void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); if (getDwarfVersion() >= 5) @@ -1984,7 +2092,7 @@ Asm->emitInt16(DebugLocs.getBytes(Entry).size()); // Emit the entry. APByteStreamer Streamer(*Asm); - emitDebugLocEntry(Streamer, Entry); + emitDebugLocEntry(Streamer, Entry, CU); } // Emit the common part of the DWARF 5 range/locations list tables header. @@ -2084,7 +2192,7 @@ Asm->EmitLabelDifference(Entry.EndSym, Base, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, CU); continue; } @@ -2105,7 +2213,7 @@ Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, CU); } if (IsLocLists) { @@ -2141,7 +2249,7 @@ Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, List.CU); } Asm->emitInt8(dwarf::DW_LLE_end_of_list); } Index: lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.h +++ lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -27,7 +27,7 @@ class AsmPrinter; class APInt; class ByteStreamer; -class DwarfUnit; +class DwarfCompileUnit; class DIELoc; class TargetRegisterInfo; @@ -104,6 +104,8 @@ const char *Comment; }; + DwarfCompileUnit &CU; + /// The register location, if any. SmallVector DwarfRegs; @@ -137,6 +139,8 @@ /// Emit a raw unsigned value. virtual void emitUnsigned(uint64_t Value) = 0; + virtual void emitBaseTypeRef(uint64_t Idx) = 0; + /// Emit a normalized unsigned constant. void emitConstu(uint64_t Value); @@ -199,7 +203,8 @@ ~DwarfExpression() = default; public: - DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {} + DwarfExpression(unsigned DwarfVersion, DwarfCompileUnit &CU) + : CU(CU), DwarfVersion(DwarfVersion) {} /// This needs to be called last to commit any pending changes. void finalize(); @@ -247,6 +252,9 @@ /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to /// the fragment described by \c Expr. void addFragmentOffset(const DIExpression *Expr); + + void emitLegacySExt(unsigned FromBits); + void emitLegacyZExt(unsigned FromBits); }; /// DwarfExpression implementation for .debug_loc entries. @@ -256,27 +264,28 @@ void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; + void emitBaseTypeRef(uint64_t Idx) override; bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; public: - DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS) - : DwarfExpression(DwarfVersion), BS(BS) {} + DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS, DwarfCompileUnit &CU) + : DwarfExpression(DwarfVersion, CU), BS(BS) {} }; /// DwarfExpression implementation for singular DW_AT_location. class DIEDwarfExpression final : public DwarfExpression { const AsmPrinter &AP; - DwarfUnit &DU; DIELoc &DIE; void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; + void emitBaseTypeRef(uint64_t Idx) override; bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; public: - DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE); + DIEDwarfExpression(const AsmPrinter &AP, DwarfCompileUnit &CU, DIELoc &DIE); DIELoc *finalize() { DwarfExpression::finalize(); Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "DwarfExpression.h" +#include "DwarfCompileUnit.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -23,6 +24,11 @@ using namespace llvm; +static cl::opt GenerateTypedDwarfExpr( + "generate-typed-dwarf5-expr", cl::Hidden, + cl::desc("Generate typed DWARF5 expressions regardless of DWARF version targeted."), + cl::init(false)); + void DwarfExpression::emitConstu(uint64_t Value) { if (Value < 32) emitOp(dwarf::DW_OP_lit0 + Value); @@ -318,6 +324,8 @@ if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment)) maskSubRegister(); + Optional PrevConvertOp = None; + while (ExprCursor) { auto Op = ExprCursor.take(); switch (Op->getOp()) { @@ -384,6 +392,37 @@ assert(LocationKind != Register); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_LLVM_convert: { + unsigned BitSize = Op->getArg(0); + dwarf::TypeKind Encoding = static_cast(Op->getArg(1)); + if (DwarfVersion >= 5 || GenerateTypedDwarfExpr) { + emitOp(dwarf::DW_OP_convert); + // XXX: Simply emit the index into the raw byte stream as ULEB128, + // DwarfDebug::emitDebugLocEntry has been fitted with means to extract it + // later. + unsigned I = 0, E = CU.ExprRefedBaseTypes.size(); + for (; I != E; ++I) + if (CU.ExprRefedBaseTypes[I].BitSize == BitSize && + CU.ExprRefedBaseTypes[I].Encoding == Encoding) + break; + + if (I == E) + CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding); + + emitBaseTypeRef(I); + } else { + if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) { + if (Encoding == dwarf::DW_ATE_signed) + emitLegacySExt(PrevConvertOp->getArg(0)); + else if (Encoding == dwarf::DW_ATE_unsigned) + emitLegacyZExt(PrevConvertOp->getArg(0)); + PrevConvertOp = None; + } else { + PrevConvertOp = Op; + } + } + break; + } case dwarf::DW_OP_stack_value: LocationKind = Implicit; break; @@ -436,3 +475,25 @@ addOpPiece(FragmentOffset - OffsetInBits); OffsetInBits = FragmentOffset; } + +void DwarfExpression::emitLegacySExt(unsigned FromBits) { + // (((X >> (FromBits - 1)) * (~0)) << FromBits) | X + emitOp(dwarf::DW_OP_dup); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits - 1); + emitOp(dwarf::DW_OP_shr); + emitOp(dwarf::DW_OP_lit0); + emitOp(dwarf::DW_OP_not); + emitOp(dwarf::DW_OP_mul); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits); + emitOp(dwarf::DW_OP_shl); + emitOp(dwarf::DW_OP_or); +} + +void DwarfExpression::emitLegacyZExt(unsigned FromBits) { + // (X & (1 << FromBits - 1)) + emitOp(dwarf::DW_OP_constu); + emitUnsigned((1ULL << FromBits) - 1); + emitOp(dwarf::DW_OP_and); +} Index: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -147,7 +147,7 @@ void emitUnits(bool UseOffsets); /// Emit the given unit to its section. - void emitUnit(DwarfUnit *U, bool UseOffsets); + void emitUnit(DwarfUnit *TheU, bool UseOffsets); /// Emit a set of abbreviations to the specific section. void emitAbbrevs(MCSection *); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -46,21 +46,26 @@ #define DEBUG_TYPE "dwarfdebug" -DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, +DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, + DwarfCompileUnit &CU, DIELoc &DIE) - : DwarfExpression(AP.getDwarfVersion()), AP(AP), DU(DU), + : DwarfExpression(AP.getDwarfVersion(), CU), AP(AP), DIE(DIE) {} void DIEDwarfExpression::emitOp(uint8_t Op, const char* Comment) { - DU.addUInt(DIE, dwarf::DW_FORM_data1, Op); + CU.addUInt(DIE, dwarf::DW_FORM_data1, Op); } void DIEDwarfExpression::emitSigned(int64_t Value) { - DU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); + CU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); } void DIEDwarfExpression::emitUnsigned(uint64_t Value) { - DU.addUInt(DIE, dwarf::DW_FORM_udata, Value); + CU.addUInt(DIE, dwarf::DW_FORM_udata, Value); +} + +void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) { + CU.addBaseTypeRef(DIE, Idx); } bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, Index: lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFExpression.cpp +++ lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -96,6 +96,7 @@ 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_convert] = Desc(Op::Dwarf4, Op::SizeLEB); return Descriptions; } Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2123,8 +2123,13 @@ assert(!OpStr.empty() && "Expected valid opcode"); Out << FS << OpStr; - for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A) - Out << FS << I->getArg(A); + if (I->getOp() == dwarf::DW_OP_LLVM_convert) { + Out << FS << I->getArg(0); + Out << FS << dwarf::AttributeEncodingString(I->getArg(1)); + } else { + for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A) + Out << FS << I->getArg(A); + } } } else { for (const auto &I : N->getElements()) Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -813,6 +813,7 @@ unsigned DIExpression::ExprOperand::getSize() const { switch (getOp()) { + case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_fragment: return 3; case dwarf::DW_OP_constu: @@ -857,6 +858,7 @@ return false; break; } + case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -135,10 +135,10 @@ /// EmitULEB128IntValue - Special case of EmitULEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. -void MCStreamer::EmitULEB128IntValue(uint64_t Value) { +void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned PadTo) { SmallString<128> Tmp; raw_svector_ostream OSE(Tmp); - encodeULEB128(Value, OSE); + encodeULEB128(Value, OSE, PadTo); EmitBytes(OSE.str()); } Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1860,21 +1860,10 @@ return None; bool Signed = *Signedness == DIBasicType::Signedness::Signed; - - if (!Signed) { - // In the unsigned case, assume that a debugger will initialize the - // high bits to 0 and do a no-op conversion. - return Identity(DII); - } else { - // In the signed case, the high bits are given by sign extension, i.e: - // (To >> (ToBits - 1)) * ((2 ^ FromBits) - 1) - // Calculate the high bits and OR them together with the low bits. - SmallVector Ops({dwarf::DW_OP_dup, dwarf::DW_OP_constu, - (ToBits - 1), dwarf::DW_OP_shr, - dwarf::DW_OP_lit0, dwarf::DW_OP_not, - dwarf::DW_OP_mul, dwarf::DW_OP_or}); - return DIExpression::appendToStack(DII.getExpression(), Ops); - } + dwarf::TypeKind TK = Signed ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned; + SmallVector Ops({dwarf::DW_OP_LLVM_convert, ToBits, TK, + dwarf::DW_OP_LLVM_convert, FromBits, TK}); + return DIExpression::appendToStack(DII.getExpression(), Ops); }; return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt); } Index: test/Assembler/diexpression.ll =================================================================== --- test/Assembler/diexpression.ll +++ test/Assembler/diexpression.ll @@ -8,9 +8,10 @@ ; CHECK-SAME: !DIExpression(DW_OP_LLVM_fragment, 3, 7), ; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7), ; CHECK-SAME: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef), -; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, 3)} +; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, 3) +; CHECK-SAME: !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed)} -!named = !{!0, !1, !2, !3, !4, !5, !6} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7} !0 = !DIExpression() !1 = !DIExpression(DW_OP_deref) @@ -19,3 +20,4 @@ !4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7) !5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef) !6 = !DIExpression(DW_OP_plus_uconst, 3) +!7 = !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed) Index: test/DebugInfo/Generic/convert-debugloc.ll =================================================================== --- /dev/null +++ test/DebugInfo/Generic/convert-debugloc.ll @@ -0,0 +1,167 @@ +; RUN: llc -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --check-prefix=DW5-CHECK +; RUN: llc -dwarf-version=4 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --check-prefix=DW4-CHECK + +; DW5-CHECK: .debug_info contents: +; DW5-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000005c version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000060) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000000c: DW_TAG_compile_unit +; DW5-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)") +; DW5-CHECK-NEXT: DW_AT_language (DW_LANG_C99) +; DW5-CHECK-NEXT: DW_AT_name ("dbg.c") +; DW5-CHECK-NEXT: DW_AT_str_offsets_base (0x00000008) +; DW5-CHECK-NEXT: DW_AT_stmt_list (0x00000000) +; DW5-CHECK-NEXT: DW_AT_comp_dir ("/tmp") +; DW5-CHECK-NEXT: DW_AT_addr_base (0x00000008) +; DW5-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) +; DW5-CHECK-NEXT: DW_AT_high_pc (0x000000000000000c) +; DW5-CHECK-NEXT: DW_AT_loclists_base (0x0000000c) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000027: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x01) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000002b: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000002f: DW_TAG_subprogram +; DW5-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) +; DW5-CHECK-NEXT: DW_AT_high_pc (0x000000000000000c) +; DW5-CHECK-NEXT: DW_AT_frame_base (DW_OP_reg6 RBP) +; DW5-CHECK-NEXT: DW_AT_name ("foo") +; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW5-CHECK-NEXT: DW_AT_decl_line (1) +; DW5-CHECK-NEXT: DW_AT_prototyped (true) +; DW5-CHECK-NEXT: DW_AT_type (0x00000057 "signed char") +; DW5-CHECK-NEXT: DW_AT_external (true) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000003e: DW_TAG_formal_parameter +; DW5-CHECK-NEXT: DW_AT_location (0x0000000c +; DW5-CHECK-NEXT: [0x0000000000000000, 0x000000000000000a): DW_OP_reg0 RAX) +; DW5-CHECK-NEXT: DW_AT_name ("x") +; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW5-CHECK-NEXT: DW_AT_decl_line (1) +; DW5-CHECK-NEXT: DW_AT_type (0x00000057 "signed char") +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000004a: DW_TAG_variable +; DW5-CHECK-NEXT: DW_AT_location (0x00000012 +; DW5-CHECK-NEXT: [0x0000000000000007, 0x000000000000000a): DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert 0x27, DW_OP_convert 0x2b, DW_OP_stack_value) +; DW5-CHECK-NEXT: DW_AT_name ("y") +; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW5-CHECK-NEXT: DW_AT_decl_line (3) +; DW5-CHECK-NEXT: DW_AT_type (0x0000005b "int") +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000056: NULL +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000057: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("signed char") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed_char) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x01) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000005b: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("int") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000005f: NULL + + +; DW4-CHECK: .debug_info contents: +; DW4-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000006d version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000071) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x0000000b: DW_TAG_compile_unit +; DW4-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)") +; DW4-CHECK-NEXT: DW_AT_language (DW_LANG_C99) +; DW4-CHECK-NEXT: DW_AT_name ("dbg.c") +; DW4-CHECK-NEXT: DW_AT_stmt_list (0x00000000) +; DW4-CHECK-NEXT: DW_AT_comp_dir ("/tmp") +; DW4-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) +; DW4-CHECK-NEXT: DW_AT_high_pc (0x000000000000000c) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x0000002a: DW_TAG_subprogram +; DW4-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) +; DW4-CHECK-NEXT: DW_AT_high_pc (0x000000000000000c) +; DW4-CHECK-NEXT: DW_AT_frame_base (DW_OP_reg6 RBP) +; DW4-CHECK-NEXT: DW_AT_name ("foo") +; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW4-CHECK-NEXT: DW_AT_decl_line (1) +; DW4-CHECK-NEXT: DW_AT_prototyped (true) +; DW4-CHECK-NEXT: DW_AT_type (0x00000062 "signed char") +; DW4-CHECK-NEXT: DW_AT_external (true) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000043: DW_TAG_formal_parameter +; DW4-CHECK-NEXT: DW_AT_location (0x00000000 +; DW4-CHECK-NEXT: [0x0000000000000000, 0x000000000000000a): DW_OP_reg0 RAX) +; DW4-CHECK-NEXT: DW_AT_name ("x") +; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW4-CHECK-NEXT: DW_AT_decl_line (1) +; DW4-CHECK-NEXT: DW_AT_type (0x00000062 "signed char") +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000052: DW_TAG_variable +; DW4-CHECK-NEXT: DW_AT_location (0x00000023 +; DW4-CHECK-NEXT: [0x0000000000000007, 0x000000000000000a): DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_dup, DW_OP_constu 0x7, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_constu 0x8, DW_OP_shl, DW_OP_or, DW_OP_stack_value) +; DW4-CHECK-NEXT: DW_AT_name ("y") +; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW4-CHECK-NEXT: DW_AT_decl_line (3) +; DW4-CHECK-NEXT: DW_AT_type (0x00000069 "int") +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000061: NULL +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000062: DW_TAG_base_type +; DW4-CHECK-NEXT: DW_AT_name ("signed char") +; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed_char) +; DW4-CHECK-NEXT: DW_AT_byte_size (0x01) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000069: DW_TAG_base_type +; DW4-CHECK-NEXT: DW_AT_name ("int") +; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW4-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000070: NULL + + +; ModuleID = 'dbg.ll' +source_filename = "dbg.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline nounwind uwtable +define dso_local signext i8 @foo(i8 signext %x) #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i8 %x, metadata !11, metadata !DIExpression()), !dbg !12 + call void @llvm.dbg.value(metadata i8 %x, metadata !13, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !15 + ret i8 %x, !dbg !16 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "dbg.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "2a034da6937f5b9cf6dd2d89127f57fd") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char) +!11 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DILocation(line: 1, column: 29, scope: !7) +!13 = !DILocalVariable(name: "y", scope: !7, file: !1, line: 3, type: !14) +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DILocation(line: 3, column: 14, scope: !7) +!16 = !DILocation(line: 4, column: 3, scope: !7) Index: test/DebugInfo/Generic/convert-inlined.ll =================================================================== --- /dev/null +++ test/DebugInfo/Generic/convert-inlined.ll @@ -0,0 +1,87 @@ +; RUN: llc -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --check-prefix=DW5-CHECK +; RUN: llc -dwarf-version=4 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --check-prefix=DW4-CHECK + +; DW5-CHECK: .debug_info contents: +; DW5-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000003e version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000042) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000000c: DW_TAG_compile_unit +; DW5-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)") +; DW5-CHECK-NEXT: DW_AT_language (DW_LANG_C99) +; DW5-CHECK-NEXT: DW_AT_name ("dbg.c") +; DW5-CHECK-NEXT: DW_AT_str_offsets_base (0x00000008) +; DW5-CHECK-NEXT: DW_AT_stmt_list (0x00000000) +; DW5-CHECK-NEXT: DW_AT_comp_dir ("/tmp") +; DW5-CHECK-NEXT: DW_AT_addr_base (0x00000008) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000001e: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x01) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000022: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000026: DW_TAG_variable +; DW5-CHECK-NEXT: DW_AT_name ("global") +; DW5-CHECK-NEXT: DW_AT_type (0x0000003d "int") +; DW5-CHECK-NEXT: DW_AT_external (true) +; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW5-CHECK-NEXT: DW_AT_decl_line (1) +; DW5-CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0, DW_OP_deref, DW_OP_convert 0x1e, DW_OP_convert 0x22, DW_OP_stack_value) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x0000003d: DW_TAG_base_type +; DW5-CHECK-NEXT: DW_AT_name ("int") +; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW5-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW5-CHECK-EMPTY: +; DW5-CHECK-NEXT: 0x00000041: NULL + + +; DW4-CHECK: .debug_info contents: +; DW4-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x00000044 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000048) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x0000000b: DW_TAG_compile_unit +; DW4-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)") +; DW4-CHECK-NEXT: DW_AT_language (DW_LANG_C99) +; DW4-CHECK-NEXT: DW_AT_name ("dbg.c") +; DW4-CHECK-NEXT: DW_AT_stmt_list (0x00000000) +; DW4-CHECK-NEXT: DW_AT_comp_dir ("/tmp") +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x0000001e: DW_TAG_variable +; DW4-CHECK-NEXT: DW_AT_name ("global") +; DW4-CHECK-NEXT: DW_AT_type (0x00000040 "int") +; DW4-CHECK-NEXT: DW_AT_external (true) +; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c") +; DW4-CHECK-NEXT: DW_AT_decl_line (1) +; DW4-CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0, DW_OP_deref, DW_OP_dup, DW_OP_constu 0x7, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_constu 0x8, DW_OP_shl, DW_OP_or, DW_OP_stack_value) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000040: DW_TAG_base_type +; DW4-CHECK-NEXT: DW_AT_name ("int") +; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; DW4-CHECK-NEXT: DW_AT_byte_size (0x04) +; DW4-CHECK-EMPTY: +; DW4-CHECK-NEXT: 0x00000047: NULL + +source_filename = "dbg.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@global = dso_local global i32 255, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_deref, DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)) +!1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dbg.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "7c731722dd7304ccb8e366ae80269b82") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 5} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)"} Index: test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll =================================================================== --- test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll +++ test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll @@ -14,7 +14,7 @@ ; ; The high 16 bits of the original 'and' require sign-extending the new 16-bit and: ; CHECK-NEXT: call void @llvm.dbg.value(metadata i16 [[and]], metadata [[C:![0-9]+]], - ; CHECK-SAME: metadata !DIExpression(DW_OP_dup, DW_OP_constu, 15, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value) + ; CHECK-SAME: metadata !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value) %D = trunc i32 %C to i16, !dbg !42 call void @llvm.dbg.value(metadata i16 %D, metadata !38, metadata !DIExpression()), !dbg !42 Index: unittests/Transforms/Utils/LocalTest.cpp =================================================================== --- unittests/Transforms/Utils/LocalTest.cpp +++ unittests/Transforms/Utils/LocalTest.cpp @@ -788,31 +788,35 @@ }; // Case 1: The original expr is empty, so no deref is needed. - EXPECT_TRUE(hasADbgVal({DW_OP_dup, DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0, - DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value})); + EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed, + DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value})); // Case 2: Perform an address calculation with the original expr, deref it, // then sign-extend the result. - EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, DW_OP_dup, - DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0, DW_OP_not, - DW_OP_mul, DW_OP_or, DW_OP_stack_value})); + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, + DW_OP_LLVM_convert, 32, DW_ATE_signed, + DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value})); // Case 3: Insert the sign-extension logic before the DW_OP_stack_value. - EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_dup, DW_OP_constu, 31, - DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or, - DW_OP_stack_value})); + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32, + DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value})); // Cases 4-6: Just like cases 1-3, but preserve the fragment at the end. - EXPECT_TRUE(hasADbgVal({DW_OP_dup, DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0, - DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value, - DW_OP_LLVM_fragment, 0, 8})); - EXPECT_TRUE( - hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, DW_OP_dup, DW_OP_constu, - 31, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or, - DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); - EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_dup, DW_OP_constu, 31, - DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or, - DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); + EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed, + DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); + + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, + DW_OP_LLVM_convert, 32, DW_ATE_signed, + DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); + + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32, + DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, + DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); verifyModule(*M, &errs(), &BrokenDebugInfo); ASSERT_FALSE(BrokenDebugInfo);