Skip to content

Commit

Permalink
[NVPTX] add support for encoding PTX registers for DWARF (llvm#109495)
Browse files Browse the repository at this point in the history
This patch adds support for encoding PTX registers for DWARF, using the
encoding supported by nvcc and cuda-gcc.

There are some other features still needed for proper register debugging
that this patch does not address, such as DW_AT_address_class.

This PR is stacked on: llvm#109494
  • Loading branch information
willghatch authored Sep 26, 2024
1 parent 4822e9d commit 95eb3d4
Show file tree
Hide file tree
Showing 8 changed files with 1,281 additions and 1,143 deletions.
6 changes: 6 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ 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.
int64_t Reg = TRI.getDwarfRegNum(MachineReg, false);
if (Reg > 0) {
DwarfRegs.push_back(Register::createRegister(Reg, nullptr));
return true;
}
return false;
}

Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ void NVPTXAsmPrinter::emitFunctionEntryLabel() {
// Emit open brace for function body.
OutStreamer->emitRawText(StringRef("{\n"));
setAndEmitFunctionVirtualRegisters(*MF);
encodeDebugInfoRegisterNumbers(*MF);
// Emit initial .loc debug directive for correct relocation symbol data.
if (const DISubprogram *SP = MF->getFunction().getSubprogram()) {
assert(SP->getUnit());
Expand Down Expand Up @@ -1792,6 +1793,26 @@ void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters(
OutStreamer->emitRawText(O.str());
}

/// Translate virtual register numbers in DebugInfo locations to their printed
/// encodings, as used by CUDA-GDB.
void NVPTXAsmPrinter::encodeDebugInfoRegisterNumbers(
const MachineFunction &MF) {
const NVPTXSubtarget &STI = MF.getSubtarget<NVPTXSubtarget>();
const NVPTXRegisterInfo *registerInfo = STI.getRegisterInfo();

// Clear the old mapping, and add the new one. This mapping is used after the
// printing of the current function is complete, but before the next function
// is printed.
registerInfo->clearDebugRegisterMap();

for (auto &classMap : VRegMapping) {
for (auto &registerMapping : classMap.getSecond()) {
auto reg = registerMapping.getFirst();
registerInfo->addToDebugRegisterMap(reg, getVirtualRegisterName(reg));
}
}
}

void NVPTXAsmPrinter::printFPConstant(const ConstantFP *Fp, raw_ostream &O) {
APFloat APF = APFloat(Fp->getValueAPF()); // make a copy
bool ignored;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {
void emitVirtualRegister(unsigned int vr, raw_ostream &);
void emitFunctionParamList(const Function *, raw_ostream &O);
void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF);
void encodeDebugInfoRegisterNumbers(const MachineFunction &MF);
void printReturnValStr(const Function *, raw_ostream &O);
void printReturnValStr(const MachineFunction &MF, raw_ostream &O);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
Expand Down
45 changes: 45 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "NVPTXRegisterInfo.h"
#include "MCTargetDesc/NVPTXInstPrinter.h"
#include "NVPTX.h"
#include "NVPTXSubtarget.h"
#include "NVPTXTargetMachine.h"
Expand Down Expand Up @@ -141,3 +142,47 @@ NVPTXRegisterInfo::getFrameLocalRegister(const MachineFunction &MF) const {
static_cast<const NVPTXTargetMachine &>(MF.getTarget());
return TM.is64Bit() ? NVPTX::VRFrameLocal64 : NVPTX::VRFrameLocal32;
}

void NVPTXRegisterInfo::clearDebugRegisterMap() const {
debugRegisterMap.clear();
}

static uint64_t encodeRegisterForDwarf(std::string registerName) {
if (registerName.length() > 8) {
// The name is more than 8 characters long, and so won't fit into 64 bits.
return 0;
}

// Encode the name string into a DWARF register number using cuda-gdb's
// encoding. See cuda_check_dwarf2_reg_ptx_virtual_register in cuda-tdep.c,
// https://github.com/NVIDIA/cuda-gdb/blob/e5cf3bddae520ffb326f95b4d98ce5c7474b828b/gdb/cuda/cuda-tdep.c#L353
// IE the bytes of the string are concatenated in reverse into a single
// number, which is stored in ULEB128, but in practice must be no more than 8
// bytes (excluding null terminator, which is not included).
uint64_t result = 0;
for (int i = 0; i < registerName.length(); ++i) {
result = result << 8;
unsigned char c = registerName[i];
result |= c;
}
return result;
}

void NVPTXRegisterInfo::addToDebugRegisterMap(
uint64_t preEncodedVirtualRegister, std::string registerName) const {
uint64_t mapped = encodeRegisterForDwarf(registerName);
if (mapped == 0)
return;
debugRegisterMap.insert({preEncodedVirtualRegister, mapped});
}

int64_t NVPTXRegisterInfo::getDwarfRegNum(MCRegister RegNum, bool isEH) const {
if (Register::isPhysicalRegister(RegNum)) {
std::string name = NVPTXInstPrinter::getRegisterName(RegNum.id());
return encodeRegisterForDwarf(name);
}
uint64_t lookup = debugRegisterMap.lookup(RegNum.id());
if (lookup)
return lookup;
return -1;
}
16 changes: 16 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class NVPTXRegisterInfo : public NVPTXGenRegisterInfo {
// Hold Strings that can be free'd all together with NVPTXRegisterInfo
BumpPtrAllocator StrAlloc;
UniqueStringSaver StrPool;
// State for debug register mapping that can be mutated even through a const
// pointer so that we can get the proper dwarf register encoding during ASM
// emission.
mutable DenseMap<uint64_t, uint64_t> debugRegisterMap;

public:
NVPTXRegisterInfo();
Expand Down Expand Up @@ -56,6 +60,18 @@ class NVPTXRegisterInfo : public NVPTXGenRegisterInfo {
return getStrPool().save(O.str()).data();
}

// Manage the debugRegisterMap. PTX virtual registers for DebugInfo are
// encoded using the names used in the emitted text of the PTX assembly. This
// mapping must be managed during assembly emission.
//
// These are marked const because the interfaces used to access this
// RegisterInfo object are all const, but we need to communicate some state
// here, because the proper encoding for debug registers is available only
// temporarily during ASM emission.
void addToDebugRegisterMap(uint64_t preEncodedVirtualRegister,
std::string registerName) const;
void clearDebugRegisterMap() const;
int64_t getDwarfRegNum(MCRegister RegNum, bool isEH) const override;
};

std::string getNVPTXRegClassName(const TargetRegisterClass *RC);
Expand Down
36 changes: 25 additions & 11 deletions llvm/test/DebugInfo/NVPTX/cu-range-hole.ll
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ entry:
; CHECK-NEXT: .b8 3 // Abbreviation Code
; CHECK-NEXT: .b8 5 // DW_TAG_formal_parameter
; CHECK-NEXT: .b8 0 // DW_CHILDREN_no
; CHECK-NEXT: .b8 2 // DW_AT_location
; CHECK-NEXT: .b8 10 // DW_FORM_block1
; CHECK-NEXT: .b8 3 // DW_AT_name
; CHECK-NEXT: .b8 8 // DW_FORM_string
; CHECK-NEXT: .b8 58 // DW_AT_decl_file
Expand All @@ -145,12 +147,12 @@ entry:
; CHECK-NEXT: }
; CHECK-NEXT: .section .debug_info
; CHECK-NEXT: {
; CHECK-NEXT: .b32 183 // Length of Unit
; CHECK-NEXT: .b32 195 // Length of Unit
; CHECK-NEXT: .b8 2 // DWARF version number
; CHECK-NEXT: .b8 0
; CHECK-NEXT: .b32 .debug_abbrev // Offset Into Abbrev. Section
; CHECK-NEXT: .b8 8 // Address Size (in bytes)
; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xb0 DW_TAG_compile_unit
; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xbc DW_TAG_compile_unit
; CHECK-NEXT: .b8 99 // DW_AT_producer
; CHECK-NEXT: .b8 108
; CHECK-NEXT: .b8 97
Expand Down Expand Up @@ -223,7 +225,7 @@ entry:
; CHECK-NEXT: .b8 0
; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc
; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc
; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x27 DW_TAG_subprogram
; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x2d DW_TAG_subprogram
; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc
; CHECK-NEXT: .b64 $L__func_end0 // DW_AT_high_pc
; CHECK-NEXT: .b8 1 // DW_AT_frame_base
Expand All @@ -233,16 +235,22 @@ entry:
; CHECK-NEXT: .b8 1 // DW_AT_decl_file
; CHECK-NEXT: .b8 1 // DW_AT_decl_line
; CHECK-NEXT: .b8 1 // DW_AT_prototyped
; CHECK-NEXT: .b32 179 // DW_AT_type
; CHECK-NEXT: .b32 191 // DW_AT_type
; CHECK-NEXT: .b8 1 // DW_AT_external
; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0x9 DW_TAG_formal_parameter
; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0xf DW_TAG_formal_parameter
; CHECK-NEXT: .b8 5 // DW_AT_location
; CHECK-NEXT: .b8 144
; CHECK-NEXT: .b8 177
; CHECK-NEXT: .b8 228
; CHECK-NEXT: .b8 149
; CHECK-NEXT: .b8 1
; CHECK-NEXT: .b8 99 // DW_AT_name
; CHECK-NEXT: .b8 0
; CHECK-NEXT: .b8 1 // DW_AT_decl_file
; CHECK-NEXT: .b8 1 // DW_AT_decl_line
; CHECK-NEXT: .b32 179 // DW_AT_type
; CHECK-NEXT: .b32 191 // DW_AT_type
; CHECK-NEXT: .b8 0 // End Of Children Mark
; CHECK-NEXT: .b8 2 // Abbrev [2] 0x8c:0x27 DW_TAG_subprogram
; CHECK-NEXT: .b8 2 // Abbrev [2] 0x92:0x2d DW_TAG_subprogram
; CHECK-NEXT: .b64 $L__func_begin2 // DW_AT_low_pc
; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc
; CHECK-NEXT: .b8 1 // DW_AT_frame_base
Expand All @@ -252,16 +260,22 @@ entry:
; CHECK-NEXT: .b8 1 // DW_AT_decl_file
; CHECK-NEXT: .b8 3 // DW_AT_decl_line
; CHECK-NEXT: .b8 1 // DW_AT_prototyped
; CHECK-NEXT: .b32 179 // DW_AT_type
; CHECK-NEXT: .b32 191 // DW_AT_type
; CHECK-NEXT: .b8 1 // DW_AT_external
; CHECK-NEXT: .b8 3 // Abbrev [3] 0xa9:0x9 DW_TAG_formal_parameter
; CHECK-NEXT: .b8 3 // Abbrev [3] 0xaf:0xf DW_TAG_formal_parameter
; CHECK-NEXT: .b8 5 // DW_AT_location
; CHECK-NEXT: .b8 144
; CHECK-NEXT: .b8 177
; CHECK-NEXT: .b8 228
; CHECK-NEXT: .b8 149
; CHECK-NEXT: .b8 1
; CHECK-NEXT: .b8 101 // DW_AT_name
; CHECK-NEXT: .b8 0
; CHECK-NEXT: .b8 1 // DW_AT_decl_file
; CHECK-NEXT: .b8 3 // DW_AT_decl_line
; CHECK-NEXT: .b32 179 // DW_AT_type
; CHECK-NEXT: .b32 191 // DW_AT_type
; CHECK-NEXT: .b8 0 // End Of Children Mark
; CHECK-NEXT: .b8 4 // Abbrev [4] 0xb3:0x7 DW_TAG_base_type
; CHECK-NEXT: .b8 4 // Abbrev [4] 0xbf:0x7 DW_TAG_base_type
; CHECK-NEXT: .b8 105 // DW_AT_name
; CHECK-NEXT: .b8 110
; CHECK-NEXT: .b8 116
Expand Down
53 changes: 40 additions & 13 deletions llvm/test/DebugInfo/NVPTX/debug-addr-class.ll
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 5 // Abbreviation Code
; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter
; CHECK-NEXT:.b8 0 // DW_CHILDREN_no
; CHECK-NEXT:.b8 2 // DW_AT_location
; CHECK-NEXT:.b8 10 // DW_FORM_block1
; CHECK-NEXT:.b8 3 // DW_AT_name
; CHECK-NEXT:.b8 8 // DW_FORM_string
; CHECK-NEXT:.b8 58 // DW_AT_decl_file
Expand All @@ -171,6 +173,19 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 0 // EOM(1)
; CHECK-NEXT:.b8 0 // EOM(2)
; CHECK-NEXT:.b8 6 // Abbreviation Code
; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter
; CHECK-NEXT:.b8 0 // DW_CHILDREN_no
; CHECK-NEXT:.b8 3 // DW_AT_name
; CHECK-NEXT:.b8 8 // DW_FORM_string
; CHECK-NEXT:.b8 58 // DW_AT_decl_file
; CHECK-NEXT:.b8 11 // DW_FORM_data1
; CHECK-NEXT:.b8 59 // DW_AT_decl_line
; CHECK-NEXT:.b8 11 // DW_FORM_data1
; CHECK-NEXT:.b8 73 // DW_AT_type
; CHECK-NEXT:.b8 19 // DW_FORM_ref4
; CHECK-NEXT:.b8 0 // EOM(1)
; CHECK-NEXT:.b8 0 // EOM(2)
; CHECK-NEXT:.b8 7 // Abbreviation Code
; CHECK-NEXT:.b8 15 // DW_TAG_pointer_type
; CHECK-NEXT:.b8 0 // DW_CHILDREN_no
; CHECK-NEXT:.b8 73 // DW_AT_type
Expand All @@ -181,12 +196,12 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT: }
; CHECK-NEXT: .section .debug_info
; CHECK-NEXT: {
; CHECK-NEXT:.b32 240 // Length of Unit
; CHECK-NEXT:.b32 252 // Length of Unit
; CHECK-NEXT:.b8 2 // DWARF version number
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b32 .debug_abbrev // Offset Into Abbrev. Section
; CHECK-NEXT:.b8 8 // Address Size (in bytes)
; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xe9 DW_TAG_compile_unit
; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xf5 DW_TAG_compile_unit
; CHECK-NEXT:.b8 99 // DW_AT_producer
; CHECK-NEXT:.b8 108
; CHECK-NEXT:.b8 97
Expand Down Expand Up @@ -298,7 +313,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 9 // DW_AT_location
; CHECK-NEXT:.b8 3
; CHECK-NEXT:.b64 SHARED
; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x45 DW_TAG_subprogram
; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x51 DW_TAG_subprogram
; CHECK-NEXT:.b64 $L__func_begin0 // DW_AT_low_pc
; CHECK-NEXT:.b64 $L__func_end0 // DW_AT_high_pc
; CHECK-NEXT:.b8 1 // DW_AT_frame_base
Expand All @@ -316,32 +331,44 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b8 1 // DW_AT_external
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0xf DW_TAG_formal_parameter
; CHECK-NEXT:.b8 5 // DW_AT_location
; CHECK-NEXT:.b8 144
; CHECK-NEXT:.b8 177
; CHECK-NEXT:.b8 204
; CHECK-NEXT:.b8 149
; CHECK-NEXT:.b8 1
; CHECK-NEXT:.b8 97 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc9:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 241 // DW_AT_type
; CHECK-NEXT:.b8 6 // Abbrev [6] 0xcf:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 120 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 238 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xd2:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 250 // DW_AT_type
; CHECK-NEXT:.b8 6 // Abbrev [6] 0xd8:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 121 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 238 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xdb:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 250 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xe1:0xf DW_TAG_formal_parameter
; CHECK-NEXT:.b8 5 // DW_AT_location
; CHECK-NEXT:.b8 144
; CHECK-NEXT:.b8 177
; CHECK-NEXT:.b8 228
; CHECK-NEXT:.b8 149
; CHECK-NEXT:.b8 1
; CHECK-NEXT:.b8 105 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 127 // DW_AT_type
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT:.b8 3 // Abbrev [3] 0xe5:0x9 DW_TAG_base_type
; CHECK-NEXT:.b8 3 // Abbrev [3] 0xf1:0x9 DW_TAG_base_type
; CHECK-NEXT:.b8 102 // DW_AT_name
; CHECK-NEXT:.b8 108
; CHECK-NEXT:.b8 111
Expand All @@ -350,8 +377,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 4 // DW_AT_encoding
; CHECK-NEXT:.b8 4 // DW_AT_byte_size
; CHECK-NEXT:.b8 6 // Abbrev [6] 0xee:0x5 DW_TAG_pointer_type
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfa:0x5 DW_TAG_pointer_type
; CHECK-NEXT:.b32 241 // DW_AT_type
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT: }
; CHECK-NEXT: .section .debug_loc { }
Expand Down
Loading

0 comments on commit 95eb3d4

Please sign in to comment.