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: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -641,7 +641,7 @@ /// does have a constant value. DIExpression *createConstantValueExpression(uint64_t Val) { return DIExpression::get( - VMContext, {dwarf::DW_OP_constu, Val, dwarf::DW_OP_stack_value}); + VMContext, {dwarf::DW_OP_constu, Val, dwarf::DW_OP_stack_value}, {}); } /// Create a new descriptor for the specified subprogram. Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -25,6 +25,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/TrackingMDRef.h" #include "llvm/Support/Casting.h" #include #include @@ -2344,26 +2345,28 @@ friend class MDNode; std::vector Elements; + std::vector ElementsMD; - DIExpression(LLVMContext &C, StorageType Storage, ArrayRef Elements) + DIExpression(LLVMContext &C, StorageType Storage, ArrayRef Elements, ArrayRef ElementsMD) : MDNode(C, DIExpressionKind, Storage, None), - Elements(Elements.begin(), Elements.end()) {} + Elements(Elements.begin(), Elements.end()), ElementsMD(ElementsMD.begin(), ElementsMD.end()) {} ~DIExpression() = default; - static DIExpression *getImpl(LLVMContext &Context, - ArrayRef Elements, StorageType Storage, + ArrayRef Elements, ArrayRef ElementsMD, + StorageType Storage, bool ShouldCreate = true); TempDIExpression cloneImpl() const { - return getTemporary(getContext(), getElements()); + return getTemporary(getContext(), getElements(), getElementsMD()); } public: - DEFINE_MDNODE_GET(DIExpression, (ArrayRef Elements), (Elements)) + DEFINE_MDNODE_GET(DIExpression, (ArrayRef Elements, ArrayRef ElementsMD), (Elements, ElementsMD)) TempDIExpression clone() const { return cloneImpl(); } ArrayRef getElements() const { return Elements; } + ArrayRef getElementsMD() const { return ElementsMD; } unsigned getNumElements() const { return Elements.size(); } @@ -2376,9 +2379,12 @@ bool isConstant() const; using element_iterator = ArrayRef::iterator; + using type_iterator = ArrayRef::iterator; element_iterator elements_begin() const { return getElements().begin(); } element_iterator elements_end() const { return getElements().end(); } + type_iterator types_begin() const { return getElementsMD().begin(); } + type_iterator types_end() const { return getElementsMD().end(); } /// A lightweight wrapper around an expression operand. /// @@ -2386,12 +2392,14 @@ /// range of these. class ExprOperand { const uint64_t *Op = nullptr; + const TrackingMDNodeRef *Md = nullptr; public: ExprOperand() = default; - explicit ExprOperand(const uint64_t *Op) : Op(Op) {} + explicit ExprOperand(const uint64_t *Op, const TrackingMDNodeRef *Md) : Op(Op), Md(Md) {} const uint64_t *get() const { return Op; } + const TrackingMDNodeRef *getType() const { return Md; } /// Get the operand code. uint64_t getOp() const { return *Op; } @@ -2400,6 +2408,7 @@ /// /// Never returns the operand itself. uint64_t getArg(unsigned I) const { return Op[I + 1]; } + TrackingMDNodeRef getTypeArg() const {return Md[0]; } unsigned getNumArgs() const { return getSize() - 1; } @@ -2412,6 +2421,12 @@ void appendToVector(SmallVectorImpl &V) const { V.append(get(), get() + getSize()); } + + void appendToVector(SmallVectorImpl &V, SmallVectorImpl &V2) const { + V.append(get(), get() + getSize()); + if (getOp() == dwarf::DW_OP_convert) + V2.append(Md, Md + 1); + } }; /// An iterator for expression operands. @@ -2421,9 +2436,10 @@ public: expr_op_iterator() = default; - explicit expr_op_iterator(element_iterator I) : Op(I) {} + explicit expr_op_iterator(element_iterator EI, type_iterator TI) : Op(EI, TI) {} element_iterator getBase() const { return Op.get(); } + type_iterator getTypeBase() const { return Op.getType(); } const ExprOperand &operator*() const { return Op; } const ExprOperand *operator->() const { return &Op; } @@ -2452,7 +2468,7 @@ } private: - void increment() { Op = ExprOperand(getBase() + Op.getSize()); } + void increment() { Op = ExprOperand(getBase() + Op.getSize(), Op.getOp() == dwarf::DW_OP_convert ? getTypeBase() + 1 : getTypeBase()); } }; /// Visit the elements via ExprOperand wrappers. @@ -2464,10 +2480,10 @@ /// \pre \a isValid() gives \c true. /// @{ expr_op_iterator expr_op_begin() const { - return expr_op_iterator(elements_begin()); + return expr_op_iterator(getElements().begin(), getElementsMD().begin()); } expr_op_iterator expr_op_end() const { - return expr_op_iterator(elements_end()); + return expr_op_iterator(getElements().end(), getElementsMD().end()); } iterator_range expr_ops() const { return {expr_op_begin(), expr_op_end()}; @@ -2529,7 +2545,7 @@ /// returned expression is a stack value only if \p DIExpr is a stack value. /// If \p DIExpr describes a fragment, the returned expression will describe /// the same fragment. - static DIExpression *append(const DIExpression *Expr, ArrayRef Ops); + static DIExpression *append(const DIExpression *Expr, ArrayRef Ops, ArrayRef MDs = {}); /// Convert \p DIExpr into a stack value if it isn't one already by appending /// DW_OP_deref if needed, and appending \p Ops to the resulting expression. @@ -2538,6 +2554,9 @@ static DIExpression *appendToStack(const DIExpression *Expr, ArrayRef Ops); + static DIExpression *appendToStack(const DIExpression *Expr, + uint64_t Op, DIBasicType *Type); + /// Create a DIExpression to describe one part of an aggregate variable that /// is fragmented across multiple Values. The DW_OP_LLVM_fragment operation /// will be appended to the elements of \c Expr. If \c Expr already contains Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4816,6 +4816,7 @@ return true; SmallVector Elements; + SmallVector ElementsMD; if (Lex.getKind() != lltok::rparen) do { if (Lex.getKind() == lltok::DwarfOp) { @@ -4827,6 +4828,15 @@ return TokError(Twine("invalid DWARF op '") + Lex.getStrVal() + "'"); } + if (Lex.getKind() == lltok::exclaim) { + Lex.Lex(); + MDNode *N = nullptr; + if (ParseMDNodeID(N)) + return TokError("expected to parse MDNode"); + ElementsMD.push_back(TrackingMDNodeRef(N)); + continue; + } + if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned()) return TokError("expected unsigned integer"); @@ -4840,7 +4850,7 @@ if (ParseToken(lltok::rparen, "expected ')' here")) return true; - Result = GET_OR_DISTINCT(DIExpression, (Context, Elements)); + Result = GET_OR_DISTINCT(DIExpression, (Context, Elements, ElementsMD)); return false; } Index: lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- lib/Bitcode/Reader/MetadataLoader.cpp +++ lib/Bitcode/Reader/MetadataLoader.cpp @@ -493,7 +493,7 @@ if (auto *GV = dyn_cast_or_null(GVs->getOperand(I))) { auto *DGVE = DIGlobalVariableExpression::getDistinct( - Context, GV, DIExpression::get(Context, {})); + Context, GV, DIExpression::get(Context, {}, {})); GVs->replaceOperandWith(I, DGVE); } } @@ -506,7 +506,7 @@ for (auto *MD : MDs) if (auto *DGV = dyn_cast_or_null(MD)) { auto *DGVE = DIGlobalVariableExpression::getDistinct( - Context, DGV, DIExpression::get(Context, {})); + Context, DGV, DIExpression::get(Context, {}, {})); GV.addMetadata(LLVMContext::MD_dbg, *DGVE); } else GV.addMetadata(LLVMContext::MD_dbg, *MD); @@ -528,7 +528,7 @@ SmallVector Ops; Ops.append(std::next(DIExpr->elements_begin()), DIExpr->elements_end()); - auto *E = DIExpression::get(Context, Ops); + auto *E = DIExpression::get(Context, Ops, {}); DDI->setOperand(2, MetadataAsValue::get(Context, E)); } } @@ -1628,7 +1628,7 @@ } else if (auto *CI = dyn_cast(CMD->getValue())) { Expr = DIExpression::get(Context, {dwarf::DW_OP_constu, CI->getZExtValue(), - dwarf::DW_OP_stack_value}); + dwarf::DW_OP_stack_value}, {}); } else { Expr = nullptr; } @@ -1643,7 +1643,7 @@ DIGlobalVariableExpression *DGVE = nullptr; if (Attach || Expr) DGVE = DIGlobalVariableExpression::getDistinct( - Context, DGV, Expr ? Expr : DIExpression::get(Context, {})); + Context, DGV, Expr ? Expr : DIExpression::get(Context, {}, {})); if (Attach) Attach->addDebugInfo(DGVE); @@ -1711,7 +1711,7 @@ return Err; MetadataList.assignValue( - GET_OR_DISTINCT(DIExpression, (Context, Elts)), NextMetadataNo); + GET_OR_DISTINCT(DIExpression, (Context, Elts, {})), NextMetadataNo); NextMetadataNo++; break; } @@ -1722,7 +1722,7 @@ IsDistinct = Record[0]; Metadata *Expr = getMDOrNull(Record[2]); if (!Expr) - Expr = DIExpression::get(Context, {}); + Expr = DIExpression::get(Context, {}, {}); MetadataList.assignValue( GET_OR_DISTINCT(DIGlobalVariableExpression, (Context, getMDOrNull(Record[1]), Expr)), 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 @@ -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,16 @@ assert(CurFn == nullptr); assert(CurMI == nullptr); + for (const auto &P : CUMap) { + auto &CU = *P.second; + for (auto *MD : MarkusNodes) { + DIE *Die = CU.getOrCreateTypeDIE(MD); + assert(Die); + Die->Label = Asm->createTempSymbol("base_type"); + TypeTblLabels.push_back(Die->Label); + } + } + // 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 +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,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 +2182,7 @@ Asm->EmitLabelDifference(Entry.EndSym, Base, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); continue; } @@ -2103,7 +2203,7 @@ Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(CU, Entry); } if (IsLocLists) { @@ -2139,7 +2239,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.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.h +++ lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -46,8 +46,8 @@ End = Expr->expr_op_end(); } - DIExpressionCursor(ArrayRef Expr) - : Start(Expr.begin()), End(Expr.end()) {} + DIExpressionCursor(ArrayRef Expr, ArrayRef Type = {}) + : Start(Expr.begin(), Type.begin()), End(Expr.end(), Type.end()) {} DIExpressionCursor(const DIExpressionCursor &) = default; Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -20,9 +20,15 @@ #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 +390,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.push_back(Op->getTypeArg()); + break; + } case dwarf::DW_OP_stack_value: LocationKind = Implicit; break; Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -1687,7 +1687,7 @@ if (expectAndConsume(MIToken::rparen)) return true; - Expr = DIExpression::get(MF.getFunction().getContext(), Elements); + Expr = DIExpression::get(MF.getFunction().getContext(), Elements, {}); return false; } Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2123,8 +2123,15 @@ 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_convert) { + const MDNode *N2 = I->getTypeArg(); + Out << FS; + writeMetadataAsOperand(Out, N2, TypePrinter, Machine, Context); + } + 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/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -732,7 +732,7 @@ } DIExpression *DIBuilder::createExpression(ArrayRef Addr) { - return DIExpression::get(VMContext, Addr); + return DIExpression::get(VMContext, Addr, {}); } DIExpression *DIBuilder::createExpression(ArrayRef Signed) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -806,9 +806,10 @@ DIExpression *DIExpression::getImpl(LLVMContext &Context, ArrayRef Elements, + ArrayRef ElementsMD, StorageType Storage, bool ShouldCreate) { - DEFINE_GETIMPL_LOOKUP(DIExpression, (Elements)); - DEFINE_GETIMPL_STORE_NO_OPS(DIExpression, (Elements)); + DEFINE_GETIMPL_LOOKUP(DIExpression, (Elements, ElementsMD)); + DEFINE_GETIMPL_STORE_NO_OPS(DIExpression, (Elements, ElementsMD)); } unsigned DIExpression::ExprOperand::getSize() const { @@ -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: @@ -964,29 +966,34 @@ } if (StackValue) Ops.push_back(dwarf::DW_OP_stack_value); - return DIExpression::get(Expr->getContext(), Ops); + return DIExpression::get(Expr->getContext(), Ops, {}); } DIExpression *DIExpression::append(const DIExpression *Expr, - ArrayRef Ops) { + ArrayRef Ops, + ArrayRef MDs) { assert(Expr && !Ops.empty() && "Can't append ops to this expression"); // Copy Expr's current op list. SmallVector NewOps; + SmallVector NewMDs; for (auto Op : Expr->expr_ops()) { // Append new opcodes before DW_OP_{stack_value, LLVM_fragment}. if (Op.getOp() == dwarf::DW_OP_stack_value || Op.getOp() == dwarf::DW_OP_LLVM_fragment) { NewOps.append(Ops.begin(), Ops.end()); + NewMDs.append(MDs.begin(), MDs.end()); // Ensure that the new opcodes are only appended once. Ops = None; + MDs = None; } - Op.appendToVector(NewOps); + Op.appendToVector(NewOps, NewMDs); } NewOps.append(Ops.begin(), Ops.end()); - return DIExpression::get(Expr->getContext(), NewOps); + NewMDs.append(MDs.begin(), MDs.end()); + return DIExpression::get(Expr->getContext(), NewOps, NewMDs); } DIExpression *DIExpression::appendToStack(const DIExpression *Expr, @@ -1022,6 +1029,33 @@ return DIExpression::append(Expr, NewOps); } +DIExpression *DIExpression::appendToStack(const DIExpression *Expr, + uint64_t Op, DIBasicType *Type) { + assert(Expr && "Can't append ops to this expression"); + + // Append a DW_OP_deref after Expr's current op list if it's non-empty and + // has no DW_OP_stack_value. + // + // Match .* DW_OP_stack_value (DW_OP_LLVM_fragment A B)?. + Optional FI = Expr->getFragmentInfo(); + unsigned DropUntilStackValue = FI.hasValue() ? 3 : 0; + ArrayRef ExprOpsBeforeFragment = + Expr->getElements().drop_back(DropUntilStackValue); + bool NeedsDeref = (Expr->getNumElements() > DropUntilStackValue) && + (ExprOpsBeforeFragment.back() != dwarf::DW_OP_stack_value); + bool NeedsStackValue = NeedsDeref || ExprOpsBeforeFragment.empty(); + + // Append a DW_OP_deref after Expr's current op list if needed, then append + // the new ops, and finally ensure that a single DW_OP_stack_value is present. + SmallVector NewOps; + if (NeedsDeref) + NewOps.push_back(dwarf::DW_OP_deref); + NewOps.append({Op}); + if (NeedsStackValue) + NewOps.push_back(dwarf::DW_OP_stack_value); + return DIExpression::append(Expr, NewOps, {TrackingMDNodeRef(Type)}); +} + Optional DIExpression::createFragmentExpression( const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits) { SmallVector Ops; @@ -1055,7 +1089,7 @@ Ops.push_back(dwarf::DW_OP_LLVM_fragment); Ops.push_back(OffsetInBits); Ops.push_back(SizeInBits); - return DIExpression::get(Expr->getContext(), Ops); + return DIExpression::get(Expr->getContext(), Ops, {}); } bool DIExpression::isConstant() const { Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -974,12 +974,14 @@ template <> struct MDNodeKeyImpl { ArrayRef Elements; + ArrayRef ElementsMD; - MDNodeKeyImpl(ArrayRef Elements) : Elements(Elements) {} - MDNodeKeyImpl(const DIExpression *N) : Elements(N->getElements()) {} + MDNodeKeyImpl(ArrayRef Elements) : Elements(Elements) {} //TODO:FIXME: Should be removed + MDNodeKeyImpl(ArrayRef Elements, ArrayRef ElementsMD) : Elements(Elements), ElementsMD(ElementsMD) {} + MDNodeKeyImpl(const DIExpression *N) : Elements(N->getElements()) {} //TODO:FIXME: Should be removed bool isKeyOf(const DIExpression *RHS) const { - return Elements == RHS->getElements(); + return Elements == RHS->getElements(); //TODO:FIXME: add ElementsMD } unsigned getHashValue() const { Index: lib/IR/Metadata.cpp =================================================================== --- lib/IR/Metadata.cpp +++ lib/IR/Metadata.cpp @@ -1484,7 +1484,7 @@ Elements[0] = dwarf::DW_OP_plus_uconst; Elements[1] = Offset; llvm::copy(OrigElements, Elements.begin() + 2); - E = DIExpression::get(getContext(), Elements); + E = DIExpression::get(getContext(), Elements, {}); Attachment = DIGlobalVariableExpression::get(getContext(), GV, E); } addMetadata(MD.first, *Attachment); 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); } + + //TODO:FIXME: Unless we add the type MDs to a named Metadata they disappear. + NamedMDNode *ConvertTypeTbl = M.getOrInsertNamedMetadata("dbg.dwarf5.type.tbl"); + ConvertTypeTbl->addOperand(dyn_cast(ToBT)); + ConvertTypeTbl->addOperand(dyn_cast(FromBT)); + + return DIExpression::appendToStack(DIExpression::appendToStack(DII.getExpression(), dwarf::DW_OP_convert, ToBT), dwarf::DW_OP_convert, FromBT); }; 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, [[OP0:[0-9]+]], DW_OP_convert, [[OP1:[0-9]+]], 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);