1 | //===-- NVPTXAssignValidGlobalNames.cpp - Assign valid names to globals ---===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Clean up the names of global variables in the module to not contain symbols |
10 | // that are invalid in PTX. |
11 | // |
12 | // Currently NVPTX, like other backends, relies on generic symbol name |
13 | // sanitizing done by MC. However, the ptxas assembler is more stringent and |
14 | // disallows some additional characters in symbol names. This pass makes sure |
15 | // such names do not reach MC at all. |
16 | // |
17 | //===----------------------------------------------------------------------===// |
18 | |
19 | #include "NVPTX.h" |
20 | #include "llvm/ADT/StringExtras.h" |
21 | #include "llvm/IR/Function.h" |
22 | #include "llvm/IR/GlobalVariable.h" |
23 | #include "llvm/IR/LegacyPassManager.h" |
24 | #include "llvm/IR/Module.h" |
25 | #include "llvm/Support/raw_ostream.h" |
26 | #include <string> |
27 | |
28 | using namespace llvm; |
29 | |
30 | namespace { |
31 | /// NVPTXAssignValidGlobalNames |
32 | class NVPTXAssignValidGlobalNames : public ModulePass { |
33 | public: |
34 | static char ID; |
35 | NVPTXAssignValidGlobalNames() : ModulePass(ID) {} |
36 | |
37 | bool runOnModule(Module &M) override; |
38 | |
39 | /// Clean up the name to remove symbols invalid in PTX. |
40 | std::string cleanUpName(StringRef Name); |
41 | }; |
42 | } |
43 | |
44 | char NVPTXAssignValidGlobalNames::ID = 0; |
45 | |
46 | namespace llvm { |
47 | void initializeNVPTXAssignValidGlobalNamesPass(PassRegistry &); |
48 | } |
49 | |
50 | INITIALIZE_PASS(NVPTXAssignValidGlobalNames, "nvptx-assign-valid-global-names" , |
51 | "Assign valid PTX names to globals" , false, false) |
52 | |
53 | bool NVPTXAssignValidGlobalNames::runOnModule(Module &M) { |
54 | for (GlobalVariable &GV : M.globals()) { |
55 | // We are only allowed to rename local symbols. |
56 | if (GV.hasLocalLinkage()) { |
57 | // setName doesn't do extra work if the name does not change. |
58 | // Note: this does not create collisions - if setName is asked to set the |
59 | // name to something that already exists, it adds a proper postfix to |
60 | // avoid collisions. |
61 | GV.setName(cleanUpName(Name: GV.getName())); |
62 | } |
63 | } |
64 | |
65 | // Do the same for local functions. |
66 | for (Function &F : M.functions()) |
67 | if (F.hasLocalLinkage()) |
68 | F.setName(cleanUpName(Name: F.getName())); |
69 | |
70 | return true; |
71 | } |
72 | |
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 | |
89 | ModulePass *llvm::createNVPTXAssignValidGlobalNamesPass() { |
90 | return new NVPTXAssignValidGlobalNames(); |
91 | } |
92 | |