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 @@ -290,6 +290,8 @@ /// List of all labels used in aranges generation. std::vector ArangeLabels; + std::vector TypeTblLabels; + /// Size of each symbol emitted (for those symbols that have a specific size). DenseMap SymSize; @@ -681,11 +683,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 { Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -751,6 +751,8 @@ // address table (.debug_addr) header. AddrPool.setLabel(Asm->createTempSymbol("addr_table_base")); + NamedMDNode *Dwarf5TypeTbl = M->getNamedMetadata("dbg.dwarf5.type.tbl"); + 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 @@ -762,11 +764,22 @@ if (!HasNonLocalImportedEntities && CUNode->getEnumTypes().empty() && CUNode->getRetainedTypes().empty() && - CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty()) + CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty() && + !Dwarf5TypeTbl) continue; DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(CUNode); + if (Dwarf5TypeTbl) { + for (unsigned I = 0, E = Dwarf5TypeTbl->getNumOperands(); I != E; ++I) { + MDNode *MD = Dwarf5TypeTbl->getOperand(I); + DIE *Die = CU.getOrCreateTypeDIE(MD); + assert(Die); + Die->Label = Asm->createTempSymbol("type_tbl"); + TypeTblLabels.push_back(Die->Label); + } + } + // Global Variables. for (auto *GVE : CUNode->getGlobalVariables()) { // Don't bother adding DIGlobalVariableExpressions listed in the CU if we @@ -1911,13 +1924,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(TypeTblLabels[ULEB128Value], CU->getLabelBegin()); + State = Idle; + } + break; + } + + if (EmitByte) + Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); + } } static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, @@ -1975,14 +2071,14 @@ DwarfExpr.finalize(); } -void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { +void DwarfDebug::emitDebugLocEntryLocation(const DwarfCompileUnit *CU, const DebugLocStream::Entry &Entry) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); Asm->emitInt16(DebugLocs.getBytes(Entry).size()); // Emit the entry. APByteStreamer Streamer(*Asm); - emitDebugLocEntry(Streamer, Entry); + emitDebugLocEntry(Streamer, CU, Entry); } // Emit the common part of the DWARF 5 range/locations list tables header. @@ -2082,7 +2178,7 @@ Asm->EmitLabelDifference(Entry.EndSym, Base, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); continue; } @@ -2103,7 +2199,7 @@ Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); } if (IsLocLists) { @@ -2139,7 +2235,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 @@ -384,6 +384,14 @@ assert(LocationKind != Register); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_convert: { + emitOp(dwarf::DW_OP_convert); + // XXX: Simply emit the "dbg.dwarf5.type.tbl" index into the raw byte + // stream as ULEB128, DwarfDebug::emitDebugLocEntry has been fitted with + // means to extract it later. + emitUnsigned(Op->getArg(0)); + break; + } case dwarf::DW_OP_stack_value: LocationKind = Implicit; break; Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -816,6 +816,7 @@ case dwarf::DW_OP_LLVM_fragment: return 3; case dwarf::DW_OP_constu: + case dwarf::DW_OP_convert: case dwarf::DW_OP_plus_uconst: return 2; default: @@ -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 @@ -1849,20 +1849,22 @@ 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); + DIBuilder DBuilder(M); + DIBasicType *FromBT, *ToBT; + if (Signed) { + ToBT = DBuilder.createBasicType("s" + std::to_string(ToBits), ToBits, dwarf::DW_ATE_signed); + FromBT = DBuilder.createBasicType("s" + std::to_string(FromBits), FromBits, dwarf::DW_ATE_signed); } 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); + ToBT = DBuilder.createBasicType("u" + std::to_string(ToBits), ToBits, dwarf::DW_ATE_unsigned); + FromBT = DBuilder.createBasicType("u" + std::to_string(FromBits), FromBits, dwarf::DW_ATE_unsigned); } + + NamedMDNode *ConvertTypeTbl = M.getOrInsertNamedMetadata("dbg.dwarf5.type.tbl"); + unsigned Idx = ConvertTypeTbl->getNumOperands(); + SmallVector Ops({dwarf::DW_OP_convert, Idx, dwarf::DW_OP_convert, Idx + 1 }); + ConvertTypeTbl->addOperand(dyn_cast(ToBT)); + ConvertTypeTbl->addOperand(dyn_cast(FromBT)); + 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_begin1 # 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, 0, DW_OP_convert, 1, 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, 10, DW_OP_convert, 11, + 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, 8, + DW_OP_convert, 9, 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, 6, + DW_OP_convert, 7, 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, 4, DW_OP_convert, 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, 2, + DW_OP_convert, 3, DW_OP_stack_value, + DW_OP_LLVM_fragment, 0, 8})); + + EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_convert, 0, + DW_OP_convert, 1, DW_OP_stack_value, + DW_OP_LLVM_fragment, 0, 8})); verifyModule(*M, &errs(), &BrokenDebugInfo); ASSERT_FALSE(BrokenDebugInfo);