Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -682,6 +682,7 @@ explicit DIE(dwarf::Tag Tag) : Tag(Tag) {} public: + MCSymbol *Label = nullptr; DIE() = delete; DIE(const DIE &RHS) = delete; DIE(DIE &&RHS) = delete; Index: lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -230,6 +230,9 @@ } void AsmPrinter::emitDwarfDIE(const DIE &Die) const { + if (Die.Label) + OutStreamer->EmitLabel(Die.Label); + // Emit the code (index) for the abbreviation. if (isVerbose()) OutStreamer->AddComment("Abbrev [" + Twine(Die.getAbbrevNumber()) + "] 0x" + 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, nullptr, Entry); } // Hash an individual attribute \param Attr based on the type of attribute and Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -56,6 +56,7 @@ DwarfFile *DWU) : DwarfUnit(dwarf::DW_TAG_compile_unit, Node, A, DW, DWU), UniqueID(UID) { insertDIE(Node, &getUnitDie()); + LabelBegin = Asm->createTempSymbol("cu_begin"); MacroLabelBegin = Asm->createTempSymbol("cu_macro_begin"); } @@ -935,7 +936,6 @@ void DwarfCompileUnit::emitHeader(bool UseOffsets) { // Don't bother labeling the .dwo unit, as its offset isn't used. if (!Skeleton && !DD->useSectionsAsReferences()) { - LabelBegin = Asm->createTempSymbol("cu_begin"); Asm->OutStreamer->EmitLabel(LabelBegin); } Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -681,11 +681,11 @@ /// 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, + void emitDebugLocEntry(ByteStreamer &Streamer, const DwarfCompileUnit *CU, const DebugLocStream::Entry &Entry); /// Emit the location for a debug loc entry, including the size header. - void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry); + void emitDebugLocEntryLocation(const DwarfCompileUnit *CU, const DebugLocStream::Entry &Entry); /// Find the MDNode for the given reference. template T *resolve(TypedDINodeRef Ref) const { @@ -732,6 +732,14 @@ const MCSymbol *getSectionLabel(const MCSection *S); }; +struct BaseTypeRef { + BaseTypeRef(unsigned ByteSize, unsigned Encoding) : + ByteSize(ByteSize), Encoding(Encoding) {} + unsigned ByteSize; + unsigned Encoding; + MCSymbol *Label = nullptr; +}; + } // end namespace llvm #endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -79,6 +79,8 @@ using namespace llvm; +extern std::vector MarkusNodes; + #define DEBUG_TYPE "dwarfdebug" static cl::opt @@ -751,6 +753,7 @@ // address table (.debug_addr) header. AddrPool.setLabel(Asm->createTempSymbol("addr_table_base")); + for (DICompileUnit *CUNode : M->debug_compile_units()) { // FIXME: Move local imported entities into a list attached to the // subprogram, then this search won't be needed and a @@ -940,6 +943,14 @@ assert(CurFn == nullptr); assert(CurMI == nullptr); + for (const auto &P : CUMap) { + auto &CU = *P.second; + for (auto &Btr : MarkusNodes) { + DIE *Die = CU.createBaseTypeDIE(Btr.ByteSize, Btr.Encoding); + Btr.Label = Die->Label = Asm->createTempSymbol("base_type"); + } + } + // If we aren't actually generating debug info (check beginModule - // conditionalized on !DisableDebugInfoPrinting and the presence of the // llvm.dbg.cu metadata node) @@ -1911,13 +1922,96 @@ StringOffsetsSection, /* UseRelativeOffsets = */ true); } -void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, +void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const DwarfCompileUnit *CU, const DebugLocStream::Entry &Entry) { 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; + 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; + State = BaseTypeFromULEB128; + break; + } + break; + + case SkipLEB128: + if (!(Byte & 0x80) && --NumSkipLEB128s == 0) + State = Idle; + break; + case BaseTypeFromULEB128: + EmitByte = false; + ULEB128Value |= (Byte & 0x7f); + if (Byte & 0x80) + ULEB128Value <<= 7; + else { + Asm->EmitLabelDifferenceAsULEB128(MarkusNodes[ULEB128Value].Label, CU->getLabelBegin()); + State = Idle; + } + break; + } + + if (EmitByte) + Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); + } } static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, @@ -1975,14 +2069,18 @@ DwarfExpr.finalize(); } -void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { +void DwarfDebug::emitDebugLocEntryLocation(const DwarfCompileUnit *CU, const DebugLocStream::Entry &Entry) { // Emit the size. + MCSymbol *Begin = Asm->createTempSymbol("debug_loc_begin"); + MCSymbol *End = Asm->createTempSymbol("debug_loc_end"); Asm->OutStreamer->AddComment("Loc expr size"); - Asm->emitInt16(DebugLocs.getBytes(Entry).size()); + Asm->EmitLabelDifference(End, Begin, 2); // Emit the entry. APByteStreamer Streamer(*Asm); - emitDebugLocEntry(Streamer, Entry); + Asm->OutStreamer->EmitLabel(Begin); + emitDebugLocEntry(Streamer, CU, Entry); + Asm->OutStreamer->EmitLabel(End); } // Emit the common part of the DWARF 5 range/locations list tables header. @@ -2082,7 +2180,7 @@ Asm->EmitLabelDifference(Entry.EndSym, Base, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); continue; } @@ -2103,7 +2201,7 @@ Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); } if (IsLocLists) { @@ -2139,7 +2237,7 @@ Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(nullptr, Entry); } Asm->emitInt8(dwarf::DW_LLE_end_of_list); } Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -11,18 +11,27 @@ //===----------------------------------------------------------------------===// #include "DwarfExpression.h" +#include "DwarfDebug.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/Support/ErrorHandling.h" #include #include #include +#include using namespace llvm; +//TODO:FIXME: Obvious hack should have a proper name and be placed in +//DwarfDebug class. A simple std::vector is maybe not the best alternative +//either. Need to think about this. + +std::vector MarkusNodes; + void DwarfExpression::emitConstu(uint64_t Value) { if (Value < 32) emitOp(dwarf::DW_OP_lit0 + Value); @@ -384,6 +393,15 @@ assert(LocationKind != Register); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_convert: { + 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. + emitUnsigned(MarkusNodes.size()); + MarkusNodes.emplace_back(Op->getArg(0) / 8, Op->getArg(1)); + break; + } case dwarf::DW_OP_stack_value: LocationKind = Implicit; break; Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -236,6 +236,7 @@ void applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, bool SkipSPAttributes = false); + DIE *createBaseTypeDIE(unsigned ByteSize, unsigned Encoding); /// Find existing DIE or create new DIE for the given type. DIE *getOrCreateTypeDIE(const MDNode *TyNode); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -618,6 +618,16 @@ return &TyDIE; } +DIE *DwarfUnit::createBaseTypeDIE(unsigned ByteSize, unsigned Encoding) { + DIE &Die = getUnitDie().addChild(DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type)); + // TODO:FIXME: It appears that gdb does not accept un-named base types. + // According to the spec the DW_AT_name is optional. Is this a gdb bug? + addString(Die, dwarf::DW_AT_name, "tmp"); + addUInt(Die, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Encoding); + addUInt(Die, dwarf::DW_AT_byte_size, None, ByteSize); + return &Die; +} + DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) { if (!TyNode) return nullptr; 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_convert: case dwarf::DW_OP_LLVM_fragment: return 3; case dwarf::DW_OP_constu: @@ -858,6 +859,7 @@ break; } case dwarf::DW_OP_constu: + case dwarf::DW_OP_convert: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1848,21 +1848,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); - } + uint64_t Encoding = Signed ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned; + SmallVector Ops({dwarf::DW_OP_convert, ToBits, Encoding, + dwarf::DW_OP_convert, FromBits, Encoding}); + return DIExpression::appendToStack(DII.getExpression(), Ops); }; return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt); } Index: test/DebugInfo/X86/dwarf-pubnames-split.ll =================================================================== --- test/DebugInfo/X86/dwarf-pubnames-split.ll +++ test/DebugInfo/X86/dwarf-pubnames-split.ll @@ -9,7 +9,7 @@ ; CHECK: .LpubTypes_begin0: ; CHECK-NEXT: .short 2 # DWARF Version -; CHECK-NEXT: .long .Lcu_begin0 # Offset of Compilation Unit Info +; CHECK-NEXT: .long .Lcu_begin{{[0-9]+}} # Offset of Compilation Unit Info ; Function Attrs: nounwind uwtable define i32 @main() #0 !dbg !4 { 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_convert, 16, 5, DW_OP_convert, 32, 5, 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,29 @@ }; // 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_convert, 32, 5, DW_OP_convert, 64, 5, + 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_convert, + 32, 5, DW_OP_convert, 64, 5, 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_convert, 32, 5, + DW_OP_convert, 64, 5, 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_convert, 32, 5, DW_OP_convert, 64, 5, + DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); + + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, DW_OP_convert, + 32, 5, DW_OP_convert, 64, 5, DW_OP_stack_value, + DW_OP_LLVM_fragment, 0, 8})); + + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_convert, 32, 5, + DW_OP_convert, 64, 5, DW_OP_stack_value, + DW_OP_LLVM_fragment, 0, 8})); verifyModule(*M, &errs(), &BrokenDebugInfo); ASSERT_FALSE(BrokenDebugInfo);