Skip to content

Commit 020fa86

Browse files
authored
[NVPTX] mangle symbols in debug info to conform to PTX restrictions. (#113216)
Until now debug info was printing the symbols names as-is and that resulted in invalid PTX when the symbols contained characters that are invalid for PTX. E.g. `__PRETTY_FUNCTION.something` Debug info is somewhat disconnected from the symbols themselves, so the regular "NVPTXAssignValidGlobalNames" pass can't easily fix them. As the "plan B" this patch catches printout of debug symbols and fixes them, as needed. One gotcha is that the same code path is used to print the names of debug info sections. Those section names do start with a '.debug'. The dot in those names is nominally illegal in PTX, but the debug section names with a dot are accepted as a special case. The downside of this change is that if someone ever has a `.debug*` symbol that needs to be referred to from the debug info, that label will be passed through as-is, and will still produce broken PTX output. If/when we run into a case where we need it to work, we could consider only passing through specific debug section names, or add a mechanism allowing us to tell section names apart from regular symbols. Fixes #58491
1 parent f1e59dc commit 020fa86

File tree

6 files changed

+81
-26
lines changed

6 files changed

+81
-26
lines changed

llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "NVPTXTargetStreamer.h"
14+
#include "NVPTXUtilities.h"
1415
#include "llvm/MC/MCAsmInfo.h"
1516
#include "llvm/MC/MCContext.h"
17+
#include "llvm/MC/MCExpr.h"
1618
#include "llvm/MC/MCObjectFileInfo.h"
19+
#include "llvm/MC/MCSymbol.h"
20+
#include "llvm/Support/Casting.h"
1721

1822
using namespace llvm;
1923

@@ -135,3 +139,16 @@ void NVPTXTargetStreamer::emitRawBytes(StringRef Data) {
135139
#endif
136140
}
137141

142+
void NVPTXTargetStreamer::emitValue(const MCExpr *Value) {
143+
if (Value->getKind() == MCExpr::SymbolRef) {
144+
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*Value);
145+
StringRef SymName = SRE.getSymbol().getName();
146+
if (!SymName.starts_with(".debug")) {
147+
Streamer.emitRawText(NVPTX::getValidPTXIdentifier(SymName));
148+
return;
149+
}
150+
// Fall through to the normal printing.
151+
}
152+
// Otherwise, print the Value normally.
153+
MCTargetStreamer::emitValue(Value);
154+
}

llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class NVPTXTargetStreamer : public MCTargetStreamer {
4848
///
4949
/// This is used to emit bytes in \p Data as sequence of .byte directives.
5050
void emitRawBytes(StringRef Data) override;
51+
/// Makes sure that labels are mangled the same way as the actual symbols.
52+
void emitValue(const MCExpr *Value) override;
5153
};
5254

5355
class NVPTXAsmTargetStreamer : public NVPTXTargetStreamer {

llvm/lib/Target/NVPTX/NVPTXAssignValidGlobalNames.cpp

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
//===----------------------------------------------------------------------===//
1818

1919
#include "NVPTX.h"
20-
#include "llvm/ADT/StringExtras.h"
20+
#include "NVPTXUtilities.h"
2121
#include "llvm/IR/Function.h"
2222
#include "llvm/IR/GlobalVariable.h"
2323
#include "llvm/IR/LegacyPassManager.h"
2424
#include "llvm/IR/Module.h"
25-
#include "llvm/Support/raw_ostream.h"
26-
#include <string>
2725

2826
using namespace llvm;
2927

@@ -35,11 +33,8 @@ class NVPTXAssignValidGlobalNames : public ModulePass {
3533
NVPTXAssignValidGlobalNames() : ModulePass(ID) {}
3634

3735
bool runOnModule(Module &M) override;
38-
39-
/// Clean up the name to remove symbols invalid in PTX.
40-
std::string cleanUpName(StringRef Name);
4136
};
42-
}
37+
} // namespace
4338

4439
char NVPTXAssignValidGlobalNames::ID = 0;
4540

@@ -58,34 +53,18 @@ bool NVPTXAssignValidGlobalNames::runOnModule(Module &M) {
5853
// Note: this does not create collisions - if setName is asked to set the
5954
// name to something that already exists, it adds a proper postfix to
6055
// avoid collisions.
61-
GV.setName(cleanUpName(GV.getName()));
56+
GV.setName(NVPTX::getValidPTXIdentifier(GV.getName()));
6257
}
6358
}
6459

6560
// Do the same for local functions.
6661
for (Function &F : M.functions())
6762
if (F.hasLocalLinkage())
68-
F.setName(cleanUpName(F.getName()));
63+
F.setName(NVPTX::getValidPTXIdentifier(F.getName()));
6964

7065
return true;
7166
}
7267

73-
std::string NVPTXAssignValidGlobalNames::cleanUpName(StringRef Name) {
74-
std::string ValidName;
75-
raw_string_ostream ValidNameStream(ValidName);
76-
for (char C : Name) {
77-
// While PTX also allows '%' at the start of identifiers, LLVM will throw a
78-
// fatal error for '%' in symbol names in MCSymbol::print. Exclude for now.
79-
if (isAlnum(C) || C == '_' || C == '$') {
80-
ValidNameStream << C;
81-
} else {
82-
ValidNameStream << "_$_";
83-
}
84-
}
85-
86-
return ValidNameStream.str();
87-
}
88-
8968
ModulePass *llvm::createNVPTXAssignValidGlobalNamesPass() {
9069
return new NVPTXAssignValidGlobalNames();
9170
}

llvm/lib/Target/NVPTX/NVPTXUtilities.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "NVPTXUtilities.h"
1414
#include "NVPTX.h"
1515
#include "NVPTXTargetMachine.h"
16+
#include "llvm/ADT/StringExtras.h"
1617
#include "llvm/ADT/StringRef.h"
1718
#include "llvm/IR/Constants.h"
1819
#include "llvm/IR/Function.h"
@@ -33,7 +34,7 @@
3334
namespace llvm {
3435

3536
namespace {
36-
typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
37+
typedef std::map<std::string, std::vector<unsigned>> key_val_pair_t;
3738
typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
3839

3940
struct AnnotationCache {

llvm/lib/Target/NVPTX/NVPTXUtilities.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_LIB_TARGET_NVPTX_NVPTXUTILITIES_H
1515

1616
#include "NVPTX.h"
17+
#include "llvm/ADT/StringExtras.h"
1718
#include "llvm/CodeGen/ValueTypes.h"
1819
#include "llvm/IR/Function.h"
1920
#include "llvm/IR/GlobalVariable.h"
@@ -84,6 +85,19 @@ bool shouldEmitPTXNoReturn(const Value *V, const TargetMachine &TM);
8485
bool Isv2x16VT(EVT VT);
8586

8687
namespace NVPTX {
88+
inline std::string getValidPTXIdentifier(StringRef Name) {
89+
std::string ValidName;
90+
ValidName.reserve(Name.size() + 4);
91+
for (char C : Name)
92+
// While PTX also allows '%' at the start of identifiers, LLVM will throw a
93+
// fatal error for '%' in symbol names in MCSymbol::print. Exclude for now.
94+
if (isAlnum(C) || C == '_' || C == '$')
95+
ValidName.push_back(C);
96+
else
97+
ValidName.append({'_', '$', '_'});
98+
99+
return ValidName;
100+
}
87101

88102
inline std::string OrderingToString(Ordering Order) {
89103
switch (Order) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
; RUN: llc < %s -march=nvptx64 -mcpu=sm_60 | FileCheck %s
2+
; RUN: %if ptxas %{ llc < %s -march=nvptx64 -mcpu=sm_60 | %ptxas-verify %}
3+
target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64"
4+
target triple = "nvptx64-nvidia-cuda"
5+
6+
; Verify that the symbols with the characters illegal in PTX get appropriately mangled.
7+
@__PRETTY_FUNCTION__._Z3foov = private unnamed_addr constant [11 x i8] c"void foo()\00", align 1, !dbg !0
8+
; '.' gets replaced with `_$_`.
9+
; CHECK: .global .align 1 .b8 __PRETTY_FUNCTION___$__Z3foov[11] = {118, 111, 105, 100, 32, 102, 111, 111, 40, 41};
10+
11+
; .debug* section names are special and are allowed to have the leading dot.
12+
; CHECK-DAG: .section .debug_abbrev
13+
; CHECK-DAG: .section .debug_info
14+
; CHECK-DAG: .b32 .debug_abbrev
15+
; CHECK-DAG: .b32 .debug_line
16+
; CHECK-DAG: .section .debug_macinfo
17+
18+
; .. but the symbol name must be mangled the same way here as it was at the definition point.
19+
; CHECK-DAG: .b64 __PRETTY_FUNCTION___$__Z3foov
20+
;
21+
22+
!llvm.dbg.cu = !{!8}
23+
!llvm.module.flags = !{!10, !11, !12}
24+
25+
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
26+
!1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 1, type: !3, isLocal: true, isDefinition: true)
27+
!2 = !DIFile(filename: "<stdin>", directory: "/usr/local/google/home/tra/work/llvm/build/release+assert+zapcc/dbg-dot")
28+
!3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 88, elements: !6)
29+
!4 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5)
30+
!5 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
31+
!6 = !{!7}
32+
!7 = !DISubrange(count: 11)
33+
!8 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !2, producer: "clang version 20.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false, nameTableKind: None)
34+
!9 = !{!0}
35+
!10 = !{i32 2, !"Debug Info Version", i32 3}
36+
!11 = !{i32 1, !"wchar_size", i32 4}
37+
!12 = !{i32 4, !"nvvm-reflect-ftz", i32 0}
38+
!13 = !{!"clang version 20.0.0git"}
39+
!14 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !2, file: !2, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8)
40+
!15 = !DISubroutineType(types: !16)
41+
!16 = !{null}
42+
!17 = !DILocation(line: 1, column: 56, scope: !14)

0 commit comments

Comments
 (0)