diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index eb55b47dfde2b..840f2637d9564 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -33,7 +33,6 @@ #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MachineLocation.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/NVPTXAddrSpace.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -76,26 +75,6 @@ static dwarf::Tag GetCompileUnitType(UnitKind Kind, DwarfDebug *DW) { return dwarf::DW_TAG_compile_unit; } -/// Translate NVVM IR address space code to DWARF correspondent value -static unsigned translateToNVVMDWARFAddrSpace(unsigned AddrSpace) { - switch (AddrSpace) { - case NVPTXAS::ADDRESS_SPACE_GENERIC: - return NVPTXAS::DWARF_ADDR_generic_space; - case NVPTXAS::ADDRESS_SPACE_GLOBAL: - return NVPTXAS::DWARF_ADDR_global_space; - case NVPTXAS::ADDRESS_SPACE_SHARED: - return NVPTXAS::DWARF_ADDR_shared_space; - case NVPTXAS::ADDRESS_SPACE_CONST: - return NVPTXAS::DWARF_ADDR_const_space; - case NVPTXAS::ADDRESS_SPACE_LOCAL: - return NVPTXAS::DWARF_ADDR_local_space; - default: - llvm_unreachable( - "Cannot translate unknown address space to DWARF address space"); - return AddrSpace; - } -} - DwarfCompileUnit::DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU, UnitKind Kind) @@ -245,8 +224,9 @@ void DwarfCompileUnit::addLocationAttribute( DIE *VariableDIE, const DIGlobalVariable *GV, ArrayRef GlobalExprs) { bool addToAccelTable = false; DIELoc *Loc = nullptr; - std::optional NVPTXAddressSpace; + std::optional TargetAddrSpace; std::unique_ptr DwarfExpr; + const GlobalVariable *LastGlobal = nullptr; for (const auto &GE : GlobalExprs) { const GlobalVariable *Global = GE.Var; const DIExpression *Expr = GE.Expr; @@ -285,18 +265,7 @@ void DwarfCompileUnit::addLocationAttribute( } if (Expr) { - // cuda-gdb special requirement. See NVPTXAS::DWARF_AddressSpace - // Decode DW_OP_constu DW_OP_swap DW_OP_xderef - // sequence to specify corresponding address space. - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - unsigned LocalNVPTXAddressSpace; - const DIExpression *NewExpr = - DIExpression::extractAddressClass(Expr, LocalNVPTXAddressSpace); - if (NewExpr != Expr) { - Expr = NewExpr; - NVPTXAddressSpace = LocalNVPTXAddressSpace; - } - } + Expr = DD->adjustExpressionForTarget(Expr, TargetAddrSpace); DwarfExpr->addFragmentOffset(Expr); } @@ -381,10 +350,7 @@ void DwarfCompileUnit::addLocationAttribute( DD->addArangeLabel(SymbolCU(this, Sym)); addOpAddress(*Loc, Sym); } - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB() && - !NVPTXAddressSpace) - NVPTXAddressSpace = - translateToNVVMDWARFAddrSpace(Global->getType()->getAddressSpace()); + LastGlobal = Global; } // Global variables attached to symbols are memory locations. // It would be better if this were unconditional, but malformed input that @@ -394,11 +360,9 @@ void DwarfCompileUnit::addLocationAttribute( DwarfExpr->setMemoryLocationKind(); DwarfExpr->addExpression(Expr); } - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - // cuda-gdb special requirement. See NVPTXAS::DWARF_AddressSpace - addUInt(*VariableDIE, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, - NVPTXAddressSpace.value_or(NVPTXAS::DWARF_ADDR_global_space)); - } + DD->addTargetVariableAttributes(*this, *VariableDIE, TargetAddrSpace, + DwarfDebug::VariableLocationKind::Global, + LastGlobal); if (Loc) addBlock(*VariableDIE, dwarf::DW_AT_location, DwarfExpr->finalize()); @@ -815,13 +779,9 @@ DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, bool Abstract) { void DwarfCompileUnit::applyConcreteDbgVariableAttributes( const Loc::Single &Single, const DbgVariable &DV, DIE &VariableDie) { const DbgValueLoc *DVal = &Single.getValueLoc(); - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB() && - !Single.getExpr()) { - // cuda-gdb special requirement. See NVPTXAS::DWARF_AddressSpace - // Lack of expression means it is a register. - addUInt(VariableDie, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, - NVPTXAS::DWARF_ADDR_reg_space); - } + if (!Single.getExpr()) + DD->addTargetVariableAttributes(*this, VariableDie, std::nullopt, + DwarfDebug::VariableLocationKind::Register); if (!DVal->isVariadic()) { const DbgValueLocEntry *Entry = DVal->getLocEntries().begin(); if (Entry->isLocation()) { @@ -931,7 +891,7 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes( void DwarfCompileUnit::applyConcreteDbgVariableAttributes(const Loc::MMI &MMI, const DbgVariable &DV, DIE &VariableDie) { - std::optional NVPTXAddressSpace; + std::optional TargetAddrSpace; DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); for (const auto &Fragment : MMI.getFrameIndexExprs()) { @@ -946,18 +906,7 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(const Loc::MMI &MMI, SmallVector Ops; TRI->getOffsetOpcodes(Offset, Ops); - // cuda-gdb special requirement. See NVPTXAS::DWARF_AddressSpace. - // Decode DW_OP_constu DW_OP_swap - // DW_OP_xderef sequence to specify address space. - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - unsigned LocalNVPTXAddressSpace; - const DIExpression *NewExpr = - DIExpression::extractAddressClass(Expr, LocalNVPTXAddressSpace); - if (NewExpr != Expr) { - Expr = NewExpr; - NVPTXAddressSpace = LocalNVPTXAddressSpace; - } - } + Expr = DD->adjustExpressionForTarget(Expr, TargetAddrSpace); if (Expr) Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); @@ -969,11 +918,8 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(const Loc::MMI &MMI, *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); DwarfExpr.addExpression(std::move(Cursor)); } - if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { - // cuda-gdb special requirement. See NVPTXAS::DWARF_AddressSpace. - addUInt(VariableDie, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, - NVPTXAddressSpace.value_or(NVPTXAS::DWARF_ADDR_local_space)); - } + DD->addTargetVariableAttributes(*this, VariableDie, TargetAddrSpace, + DwarfDebug::VariableLocationKind::FrameIndex); addBlock(VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); if (DwarfExpr.TagOffset) addUInt(VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index aaff5c13050c1..72022fcddf316 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -352,7 +352,7 @@ DwarfDebug::DwarfDebug(AsmPrinter *A) DebuggerTuning = DebuggerKind::GDB; if (DwarfInlinedStrings == Default) - UseInlineStrings = TT.isNVPTX() || tuneForDBX(); + UseInlineStrings = tuneForDBX(); else UseInlineStrings = DwarfInlinedStrings == Enable; @@ -373,9 +373,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A) unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion; unsigned DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber : MMI->getModule()->getDwarfVersion(); - // Use dwarf 4 by default if nothing is requested. For NVPTX, use dwarf 2. - DwarfVersion = - TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION); + if (!DwarfVersion) + DwarfVersion = dwarf::DWARF_VERSION; bool Dwarf64 = DwarfVersion >= 3 && // DWARF64 was introduced in DWARFv3. TT.isArch64Bit(); // DWARF64 requires 64-bit relocations. @@ -393,12 +392,9 @@ DwarfDebug::DwarfDebug(AsmPrinter *A) if (!Dwarf64 && TT.isArch64Bit() && TT.isOSBinFormatXCOFF()) report_fatal_error("XCOFF requires DWARF64 for 64-bit mode!"); - UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX(); + UseRangesSection = !NoDwarfRangesSection; - // Use sections as references. Force for NVPTX. - if (DwarfSectionsAsReferences == Default) - UseSectionsAsReferences = TT.isNVPTX(); - else + if (DwarfSectionsAsReferences != Default) UseSectionsAsReferences = DwarfSectionsAsReferences == Enable; // Don't generate type units for unsupported object file formats. @@ -1406,11 +1402,7 @@ void DwarfDebug::finalizeModuleInfo() { DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; if (unsigned NumRanges = TheCU.getRanges().size()) { - // PTX does not support subtracting labels from the code section in the - // debug_loc section. To work around this, the NVPTX backend needs the - // compile unit to have no low_pc in order to have a zero base_address - // when handling debug_loc in cuda-gdb. - if (!(Asm->TM.getTargetTriple().isNVPTX() && tuneForGDB())) { + if (shouldAttachCompileUnitRanges()) { if (NumRanges > 1 && useRangesSection()) // A DW_AT_low_pc attribute may also be specified in combination with // DW_AT_ranges to specify the default base address for use in @@ -3435,15 +3427,8 @@ emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R, bool BaseIsSet = false; for (const auto &P : SectionRanges) { auto *Base = CUBase; - if ((Asm->TM.getTargetTriple().isNVPTX() && DD.tuneForGDB()) || + if (DD.shouldResetBaseAddress(*P.first) || (DD.useSplitDwarf() && UseDwarf5 && P.first->isLinkerRelaxable())) { - // PTX does not support subtracting labels from the code section in the - // debug_loc section. To work around this, the NVPTX backend needs the - // compile unit to have no low_pc in order to have a zero base_address - // when handling debug_loc in cuda-gdb. Additionally, cuda-gdb doesn't - // seem to handle setting a per-variable base to zero. To make cuda-gdb - // happy, just emit labels with no base while having no compile unit - // low_pc. BaseIsSet = false; Base = nullptr; } else if (!Base && ShouldUseBaseAddress) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index ae1f29144cce7..449f644c5b273 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -52,6 +52,7 @@ class DwarfCompileUnit; class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; +class GlobalVariable; class LexicalScope; class MachineFunction; class MCSection; @@ -719,9 +720,17 @@ class DwarfDebug : public DebugHandlerBase { void skippedNonDebugFunction() override; /// Target-specific debug info initialization at function start. - /// Default implementation is empty, overridden by NVPTX target. virtual void initializeTargetDebugInfo(const MachineFunction &MF) {} + /// Setters for target-specific DWARF configuration overrides. + /// Called from target DwarfDebug subclass constructors. + void setUseInlineStrings(bool V) { UseInlineStrings = V; } + void setUseRangesSection(bool V) { UseRangesSection = V; } + void setUseSectionsAsReferences(bool V) { UseSectionsAsReferences = V; } + + /// Whether to attach ranges/low_pc to the compile unit DIE in endModule. + virtual bool shouldAttachCompileUnitRanges() const { return true; } + /// Target-specific source line recording. virtual void recordTargetSourceLine(const DebugLoc &DL, unsigned Flags); @@ -730,6 +739,35 @@ class DwarfDebug : public DebugHandlerBase { } public: + //===--------------------------------------------------------------------===// + // Target hooks for debug info customization. + // + + /// Whether the target requires resetting the base address in range/loc lists. + virtual bool shouldResetBaseAddress(const MCSection &Section) const { + return false; + } + + /// Describes the storage kind of a debug variable for target hooks. + enum class VariableLocationKind { Global, Register, FrameIndex }; + + /// Extract target-specific address space information from a DIExpression. + /// Targets may strip address-space-encoding ops from the expression and + /// return the address space via \p TargetAddrSpace. + virtual const DIExpression * + adjustExpressionForTarget(const DIExpression *Expr, + std::optional &TargetAddrSpace) const { + return Expr; + } + + /// Add target-specific attributes to a variable DIE (e.g. + /// DW_AT_address_class). + virtual void + addTargetVariableAttributes(DwarfCompileUnit &CU, DIE &Die, + std::optional TargetAddrSpace, + VariableLocationKind VarLocKind, + const GlobalVariable *GV = nullptr) const {} + //===--------------------------------------------------------------------===// // Main entry points. // diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index d6b06b83207c7..79a5bc208f1fb 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -105,7 +105,7 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, DwarfRegs.push_back(Register::createRegister(-1, nullptr)); return true; } - // Try getting dwarf register for virtual register anyway, eg. for NVPTX. + // Try getting dwarf register for targets that use virtual registers. int64_t Reg = TRI.getDwarfRegNumForVirtReg(MachineReg, false); if (Reg > 0) { DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); diff --git a/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.cpp b/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.cpp index b79c7d32cea3d..2a4b450c38784 100644 --- a/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.cpp @@ -13,14 +13,17 @@ #include "NVPTXDwarfDebug.h" #include "NVPTXSubtarget.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/NVPTXAddrSpace.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -33,7 +36,15 @@ static cl::opt LineInfoWithInlinedAt( cl::desc("Emit line with inlined_at enhancement for NVPTX"), cl::init(true), cl::Hidden); -NVPTXDwarfDebug::NVPTXDwarfDebug(AsmPrinter *A) : DwarfDebug(A) {} +NVPTXDwarfDebug::NVPTXDwarfDebug(AsmPrinter *A) : DwarfDebug(A) { + // PTX emits debug strings inline (no .debug_str section), does not support + // .debug_ranges, and uses sections as references (no temp symbols inside + // DWARF sections). DWARF v2 is the default for NVPTX. + setUseInlineStrings(true); + setUseRangesSection(false); + setUseSectionsAsReferences(true); + Asm->OutStreamer->getContext().setDwarfVersion(2); +} /// NVPTX-specific source line recording with inlined_at support. /// @@ -172,6 +183,90 @@ void NVPTXDwarfDebug::recordTargetSourceLine(const DebugLoc &DL, /// NVPTX-specific debug info initialization. void NVPTXDwarfDebug::initializeTargetDebugInfo(const MachineFunction &MF) { - // Clear the set of emitted inlined_at locations for each new function. EmittedInlinedAtLocs.clear(); } + +// PTX does not support subtracting labels from the code section in the +// debug_loc section. To work around this, the NVPTX backend needs the +// compile unit to have no low_pc in order to have a zero base_address +// when handling debug_loc in cuda-gdb. +bool NVPTXDwarfDebug::shouldAttachCompileUnitRanges() const { + return !tuneForGDB(); +} + +// Same label-subtraction limitation as above: cuda-gdb doesn't handle +// setting a per-variable base to zero, so we emit labels with no base +// while having no compile unit low_pc. +bool NVPTXDwarfDebug::shouldResetBaseAddress(const MCSection &Section) const { + return tuneForGDB(); +} + +static unsigned translateToNVVMDWARFAddrSpace(unsigned AddrSpace) { + switch (AddrSpace) { + case NVPTXAS::ADDRESS_SPACE_GENERIC: + return NVPTXAS::DWARF_ADDR_generic_space; + case NVPTXAS::ADDRESS_SPACE_GLOBAL: + return NVPTXAS::DWARF_ADDR_global_space; + case NVPTXAS::ADDRESS_SPACE_SHARED: + return NVPTXAS::DWARF_ADDR_shared_space; + case NVPTXAS::ADDRESS_SPACE_CONST: + return NVPTXAS::DWARF_ADDR_const_space; + case NVPTXAS::ADDRESS_SPACE_LOCAL: + return NVPTXAS::DWARF_ADDR_local_space; + default: + llvm_unreachable( + "Cannot translate unknown address space to DWARF address space"); + return AddrSpace; + } +} + +// cuda-gdb requires DW_AT_address_class on variable DIEs. The address space +// is encoded in the DIExpression as a DW_OP_constu +// DW_OP_swap DW_OP_xderef sequence. We strip that sequence from the +// expression and return the address space so the caller can emit +// DW_AT_address_class separately. +const DIExpression *NVPTXDwarfDebug::adjustExpressionForTarget( + const DIExpression *Expr, std::optional &TargetAddrSpace) const { + if (!tuneForGDB()) + return Expr; + unsigned LocalAddrSpace; + const DIExpression *NewExpr = + DIExpression::extractAddressClass(Expr, LocalAddrSpace); + if (NewExpr != Expr) { + TargetAddrSpace = LocalAddrSpace; + return NewExpr; + } + return Expr; +} + +// Emit DW_AT_address_class for cuda-gdb. See NVPTXAS::DWARF_AddressSpace. +// +// The address class depends on the variable's storage kind: +// Global: from the expression (if encoded) or the IR address space +// Register: DWARF_ADDR_reg_space (no expression means register location) +// FrameIndex: from the expression (if encoded) or DWARF_ADDR_local_space +void NVPTXDwarfDebug::addTargetVariableAttributes( + DwarfCompileUnit &CU, DIE &Die, std::optional TargetAddrSpace, + VariableLocationKind VarLocKind, const GlobalVariable *GV) const { + if (!tuneForGDB()) + return; + + unsigned DefaultAddrSpace = NVPTXAS::DWARF_ADDR_global_space; + switch (VarLocKind) { + case VariableLocationKind::Global: + if (!TargetAddrSpace && GV) + TargetAddrSpace = + translateToNVVMDWARFAddrSpace(GV->getType()->getAddressSpace()); + DefaultAddrSpace = NVPTXAS::DWARF_ADDR_global_space; + break; + case VariableLocationKind::Register: + DefaultAddrSpace = NVPTXAS::DWARF_ADDR_reg_space; + break; + case VariableLocationKind::FrameIndex: + DefaultAddrSpace = NVPTXAS::DWARF_ADDR_local_space; + break; + } + + CU.addUInt(Die, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, + TargetAddrSpace.value_or(DefaultAddrSpace)); +} diff --git a/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.h b/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.h index 99d5b9a649c16..75fe78ec9b409 100644 --- a/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.h +++ b/llvm/lib/Target/NVPTX/NVPTXDwarfDebug.h @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// // -// This file declares helper classes and functions for NVPTX-specific debug -// information processing, particularly for inlined function call sites and +// This file declares the NVPTXDwarfDebug class, the NVPTX-specific subclass +// of DwarfDebug. It customizes DWARF emission for PTX: address space +// attributes, compile-unit range suppression, base address handling, and // enhanced line information with inlined_at directives. // //===----------------------------------------------------------------------===// @@ -20,9 +21,12 @@ namespace llvm { -/// NVPTXDwarfDebug - NVPTX-specific DwarfDebug implementation. -/// Inherits from DwarfDebug to provide enhanced line information with -/// inlined_at support. +/// NVPTX-specific DwarfDebug implementation. +/// +/// Customizes DWARF emission for PTX targets: DWARF v2 defaults, address +/// space attributes (DW_AT_address_class) for cuda-gdb, compile-unit range +/// suppression, range-list base address handling, and enhanced line +/// information with inlined_at directives. class NVPTXDwarfDebug : public DwarfDebug { private: /// Set of inlined_at locations that have already been emitted. @@ -30,14 +34,21 @@ class NVPTXDwarfDebug : public DwarfDebug { DenseSet EmittedInlinedAtLocs; public: - /// Constructor - Pass through to DwarfDebug constructor. NVPTXDwarfDebug(AsmPrinter *A); + bool shouldResetBaseAddress(const MCSection &Section) const override; + const DIExpression *adjustExpressionForTarget( + const DIExpression *Expr, + std::optional &TargetAddrSpace) const override; + void addTargetVariableAttributes( + DwarfCompileUnit &CU, DIE &Die, std::optional TargetAddrSpace, + VariableLocationKind VarLocKind, + const GlobalVariable *GV = nullptr) const override; + protected: - /// Override to collect inlined_at locations. void initializeTargetDebugInfo(const MachineFunction &MF) override; - /// Override to record source line information with inlined_at support. void recordTargetSourceLine(const DebugLoc &DL, unsigned Flags) override; + bool shouldAttachCompileUnitRanges() const override; }; } // end namespace llvm