diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -771,192 +771,197 @@ } // Add variable address. - - if (auto *Multi = std::get_if(&DV)) { - addLocationList(*VariableDie, dwarf::DW_AT_location, - Multi->getDebugLocListIndex()); - auto TagOffset = Multi->getDebugLocListTagOffset(); - if (TagOffset) - addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, - *TagOffset); - return VariableDie; - } - - // Check if variable has a single location description. - if (const auto *Single = std::get_if(&DV)) { - const DbgValueLoc *DVal = &Single->getValueLoc(); - if (!DVal->isVariadic()) { - const DbgValueLocEntry *Entry = DVal->getLocEntries().begin(); - if (Entry->isLocation()) { - addVariableAddress(DV, *VariableDie, Entry->getLoc()); - } else if (Entry->isInt()) { - auto *Expr = Single->getExpr(); - if (Expr && Expr->getNumElements()) { - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - // If there is an expression, emit raw unsigned bytes. - DwarfExpr.addFragmentOffset(Expr); - DwarfExpr.addUnsignedConstant(Entry->getInt()); - DwarfExpr.addExpression(Expr); - addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); - if (DwarfExpr.TagOffset) - addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, - dwarf::DW_FORM_data1, *DwarfExpr.TagOffset); - } else - addConstantValue(*VariableDie, Entry->getInt(), DV.getType()); - } else if (Entry->isConstantFP()) { - addConstantFPValue(*VariableDie, Entry->getConstantFP()); - } else if (Entry->isConstantInt()) { - addConstantValue(*VariableDie, Entry->getConstantInt(), DV.getType()); - } else if (Entry->isTargetIndexLocation()) { - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - const DIBasicType *BT = dyn_cast( - static_cast(DV.getVariable()->getType())); - DwarfDebug::emitDebugLocValue(*Asm, BT, *DVal, DwarfExpr); - addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); - } - return VariableDie; - } - // If any of the location entries are registers with the value 0, then the - // location is undefined. - if (any_of(DVal->getLocEntries(), [](const DbgValueLocEntry &Entry) { - return Entry.isLocation() && !Entry.getLoc().getReg(); - })) - return VariableDie; - const DIExpression *Expr = Single->getExpr(); - assert(Expr && "Variadic Debug Value must have an Expression."); - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - DwarfExpr.addFragmentOffset(Expr); - DIExpressionCursor Cursor(Expr); - const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); - - auto AddEntry = [&](const DbgValueLocEntry &Entry, - DIExpressionCursor &Cursor) { - if (Entry.isLocation()) { - if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, - Entry.getLoc().getReg())) - return false; - } else if (Entry.isInt()) { - // If there is an expression, emit raw unsigned bytes. - DwarfExpr.addUnsignedConstant(Entry.getInt()); - } else if (Entry.isConstantFP()) { - // DwarfExpression does not support arguments wider than 64 bits - // (see PR52584). - // TODO: Consider chunking expressions containing overly wide - // arguments into separate pointer-sized fragment expressions. - APInt RawBytes = Entry.getConstantFP()->getValueAPF().bitcastToAPInt(); - if (RawBytes.getBitWidth() > 64) - return false; - DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); - } else if (Entry.isConstantInt()) { - APInt RawBytes = Entry.getConstantInt()->getValue(); - if (RawBytes.getBitWidth() > 64) - return false; - DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); - } else if (Entry.isTargetIndexLocation()) { - TargetIndexLocation Loc = Entry.getTargetIndexLocation(); - // TODO TargetIndexLocation is a target-independent. Currently only the - // WebAssembly-specific encoding is supported. - assert(Asm->TM.getTargetTriple().isWasm()); - DwarfExpr.addWasmLocation(Loc.Index, static_cast(Loc.Offset)); - } else { - llvm_unreachable("Unsupported Entry type."); - } - return true; - }; - - if (!DwarfExpr.addExpression( - std::move(Cursor), - [&](unsigned Idx, DIExpressionCursor &Cursor) -> bool { - return AddEntry(DVal->getLocEntries()[Idx], Cursor); - })) - return VariableDie; - - // Now attach the location information to the DIE. - addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); - if (DwarfExpr.TagOffset) - addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, - *DwarfExpr.TagOffset); - - return VariableDie; - } - - if (auto *EntryValue = std::get_if(&DV)) { - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - // Emit each expression as: EntryValue(Register) . - for (auto [Register, Expr] : EntryValue->EntryValues) { - DwarfExpr.addFragmentOffset(&Expr); - DIExpressionCursor Cursor(Expr.getElements()); - DwarfExpr.beginEntryValueExpression(Cursor); - DwarfExpr.addMachineRegExpression( - *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, Register); - DwarfExpr.addExpression(std::move(Cursor)); - } - addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); - return VariableDie; - } - - // .. else use frame index. - if (!DV.holds()) - return VariableDie; - - std::optional NVPTXAddressSpace; - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - for (const auto &Fragment : DV.get().getFrameIndexExprs()) { - Register FrameReg; - const DIExpression *Expr = Fragment.Expr; - const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); - StackOffset Offset = - TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); - DwarfExpr.addFragmentOffset(Expr); - - auto *TRI = Asm->MF->getSubtarget().getRegisterInfo(); - SmallVector Ops; - TRI->getOffsetOpcodes(Offset, Ops); - - // According to - // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf - // cuda-gdb requires DW_AT_address_class for all variables to be able to - // correctly interpret address space of the variable address. - // Decode DW_OP_constu DW_OP_swap DW_OP_xderef - // sequence for the NVPTX + gdb target. - unsigned LocalNVPTXAddressSpace; - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - const DIExpression *NewExpr = - DIExpression::extractAddressClass(Expr, LocalNVPTXAddressSpace); - if (NewExpr != Expr) { - Expr = NewExpr; - NVPTXAddressSpace = LocalNVPTXAddressSpace; - } - } - if (Expr) - Ops.append(Expr->elements_begin(), Expr->elements_end()); - DIExpressionCursor Cursor(Ops); - DwarfExpr.setMemoryLocationKind(); - if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) - addOpAddress(*Loc, FrameSymbol); - else - DwarfExpr.addMachineRegExpression( - *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); - DwarfExpr.addExpression(std::move(Cursor)); - } - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - // According to - // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf - // cuda-gdb requires DW_AT_address_class for all variables to be able to - // correctly interpret address space of the variable address. - const unsigned NVPTX_ADDR_local_space = 6; - addUInt(*VariableDie, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, - NVPTXAddressSpace.value_or(NVPTX_ADDR_local_space)); - } - addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); - if (DwarfExpr.TagOffset) - addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, - *DwarfExpr.TagOffset); + std::visit( + makeVisitor( + [=, &DV](const Loc::Single &Single) { + const DbgValueLoc *DVal = &Single.getValueLoc(); + if (!DVal->isVariadic()) { + const DbgValueLocEntry *Entry = DVal->getLocEntries().begin(); + if (Entry->isLocation()) { + addVariableAddress(DV, *VariableDie, Entry->getLoc()); + } else if (Entry->isInt()) { + auto *Expr = Single.getExpr(); + if (Expr && Expr->getNumElements()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + // If there is an expression, emit raw unsigned bytes. + DwarfExpr.addFragmentOffset(Expr); + DwarfExpr.addUnsignedConstant(Entry->getInt()); + DwarfExpr.addExpression(Expr); + addBlock(*VariableDie, dwarf::DW_AT_location, + DwarfExpr.finalize()); + if (DwarfExpr.TagOffset) + addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, + dwarf::DW_FORM_data1, *DwarfExpr.TagOffset); + } else + addConstantValue(*VariableDie, Entry->getInt(), DV.getType()); + } else if (Entry->isConstantFP()) { + addConstantFPValue(*VariableDie, Entry->getConstantFP()); + } else if (Entry->isConstantInt()) { + addConstantValue(*VariableDie, Entry->getConstantInt(), + DV.getType()); + } else if (Entry->isTargetIndexLocation()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + const DIBasicType *BT = dyn_cast( + static_cast(DV.getVariable()->getType())); + DwarfDebug::emitDebugLocValue(*Asm, BT, *DVal, DwarfExpr); + addBlock(*VariableDie, dwarf::DW_AT_location, + DwarfExpr.finalize()); + } + return; + } + // If any of the location entries are registers with the value 0, + // then the location is undefined. + if (any_of(DVal->getLocEntries(), + [](const DbgValueLocEntry &Entry) { + return Entry.isLocation() && !Entry.getLoc().getReg(); + })) + return; + const DIExpression *Expr = Single.getExpr(); + assert(Expr && "Variadic Debug Value must have an Expression."); + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + DwarfExpr.addFragmentOffset(Expr); + DIExpressionCursor Cursor(Expr); + const TargetRegisterInfo &TRI = + *Asm->MF->getSubtarget().getRegisterInfo(); + + auto AddEntry = [&](const DbgValueLocEntry &Entry, + DIExpressionCursor &Cursor) { + if (Entry.isLocation()) { + if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, + Entry.getLoc().getReg())) + return false; + } else if (Entry.isInt()) { + // If there is an expression, emit raw unsigned bytes. + DwarfExpr.addUnsignedConstant(Entry.getInt()); + } else if (Entry.isConstantFP()) { + // DwarfExpression does not support arguments wider than 64 bits + // (see PR52584). + // TODO: Consider chunking expressions containing overly wide + // arguments into separate pointer-sized fragment expressions. + APInt RawBytes = + Entry.getConstantFP()->getValueAPF().bitcastToAPInt(); + if (RawBytes.getBitWidth() > 64) + return false; + DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); + } else if (Entry.isConstantInt()) { + APInt RawBytes = Entry.getConstantInt()->getValue(); + if (RawBytes.getBitWidth() > 64) + return false; + DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); + } else if (Entry.isTargetIndexLocation()) { + TargetIndexLocation Loc = Entry.getTargetIndexLocation(); + // TODO TargetIndexLocation is a target-independent. Currently + // only the WebAssembly-specific encoding is supported. + assert(Asm->TM.getTargetTriple().isWasm()); + DwarfExpr.addWasmLocation(Loc.Index, + static_cast(Loc.Offset)); + } else { + llvm_unreachable("Unsupported Entry type."); + } + return true; + }; + + if (!DwarfExpr.addExpression( + std::move(Cursor), + [&](unsigned Idx, DIExpressionCursor &Cursor) -> bool { + return AddEntry(DVal->getLocEntries()[Idx], Cursor); + })) + return; + + // Now attach the location information to the DIE. + addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); + if (DwarfExpr.TagOffset) + addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, + dwarf::DW_FORM_data1, *DwarfExpr.TagOffset); + }, + [=](const Loc::Multi &Multi) { + addLocationList(*VariableDie, dwarf::DW_AT_location, + Multi.getDebugLocListIndex()); + auto TagOffset = Multi.getDebugLocListTagOffset(); + if (TagOffset) + addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, + dwarf::DW_FORM_data1, *TagOffset); + }, + [=](const Loc::MMI &MMI) { + std::optional NVPTXAddressSpace; + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + for (const auto &Fragment : MMI.getFrameIndexExprs()) { + Register FrameReg; + const DIExpression *Expr = Fragment.Expr; + const TargetFrameLowering *TFI = + Asm->MF->getSubtarget().getFrameLowering(); + StackOffset Offset = + TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); + DwarfExpr.addFragmentOffset(Expr); + + auto *TRI = Asm->MF->getSubtarget().getRegisterInfo(); + SmallVector Ops; + TRI->getOffsetOpcodes(Offset, Ops); + + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be + // able to correctly interpret address space of the variable + // address. Decode DW_OP_constu DW_OP_swap + // DW_OP_xderef sequence for the NVPTX + gdb target. + unsigned LocalNVPTXAddressSpace; + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + const DIExpression *NewExpr = DIExpression::extractAddressClass( + Expr, LocalNVPTXAddressSpace); + if (NewExpr != Expr) { + Expr = NewExpr; + NVPTXAddressSpace = LocalNVPTXAddressSpace; + } + } + if (Expr) + Ops.append(Expr->elements_begin(), Expr->elements_end()); + DIExpressionCursor Cursor(Ops); + DwarfExpr.setMemoryLocationKind(); + if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) + addOpAddress(*Loc, FrameSymbol); + else + DwarfExpr.addMachineRegExpression( + *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, + FrameReg); + DwarfExpr.addExpression(std::move(Cursor)); + } + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be + // able to correctly interpret address space of the variable + // address. + const unsigned NVPTX_ADDR_local_space = 6; + addUInt(*VariableDie, dwarf::DW_AT_address_class, + dwarf::DW_FORM_data1, + NVPTXAddressSpace.value_or(NVPTX_ADDR_local_space)); + } + addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); + if (DwarfExpr.TagOffset) + addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, + dwarf::DW_FORM_data1, *DwarfExpr.TagOffset); + }, + [=](const Loc::EntryValue &EntryValue) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + // Emit each expression as: EntryValue(Register) + // . + for (auto [Register, Expr] : EntryValue.EntryValues) { + DwarfExpr.addFragmentOffset(&Expr); + DIExpressionCursor Cursor(Expr.getElements()); + DwarfExpr.beginEntryValueExpression(Cursor); + DwarfExpr.addMachineRegExpression( + *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, Register); + DwarfExpr.addExpression(std::move(Cursor)); + } + addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); + }, + [](const std::monostate &) {}), + DV.asVariant()); return VariableDie; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -186,6 +186,9 @@ EntryValues.insert({Reg, **NonVariadicExpr}); } }; +/// Alias for the std::variant specialization base class of DbgVariable. +using Variant = std::variant; } // namespace Loc //===----------------------------------------------------------------------===// @@ -209,11 +212,16 @@ /// DebugLocListIndex and (optionally) \c DebugLocListTagOffset, while those /// with a single location hold a \c Loc::Single alternative which use \c /// ValueLoc and (optionally) a single \c Expr. -class DbgVariable : public DbgEntity, - public std::variant { +class DbgVariable : public DbgEntity, public Loc::Variant { public: + /// To workaround P2162R0 https://github.com/cplusplus/papers/issues/873 the + /// base class subobject needs to be passed directly to std::visit, so expose + /// it directly here. + Loc::Variant &asVariant() { return *static_cast(this); } + const Loc::Variant &asVariant() const { + return *static_cast(this); + } /// Member shorthand for std::holds_alternative template bool holds() const { return std::holds_alternative(*this);