33
33
// char, signed char)`), is not defined. The remangler creates a clone
34
34
// of the renamed function,`_Z1fxaa`, to this permutation, `_Z1fxca`.
35
35
//
36
+ // Remangled Pointer Address Space Example:
37
+ // If libclc defined a function `f(int *)`, the mangled name is
38
+ // `_Z1fPU3AS4i` for a target when generic address space is 4. The
39
+ // remangler would rename this function to `_Z1fPi`, to be
40
+ // consistent with SYCL device code mangling for the target. If libclc
41
+ // defined a function `f(private int *)`, the mangled name is
42
+ // `_Z1fPi` when default address space is private. The remangler would
43
+ // rename it to `_Z1fPU3AS0i`.
44
+ //
36
45
// ===----------------------------------------------------------------------===//
37
46
38
47
#include " clang/AST/Mangle.h"
43
52
#include " llvm/Bitcode/BitcodeReader.h"
44
53
#include " llvm/Bitcode/BitcodeWriter.h"
45
54
#include " llvm/Demangle/ItaniumDemangle.h"
55
+ #include " llvm/IR/Constants.h"
46
56
#include " llvm/IR/DiagnosticInfo.h"
47
57
#include " llvm/IR/DiagnosticPrinter.h"
48
58
#include " llvm/IRReader/IRReader.h"
@@ -62,6 +72,8 @@ enum class SupportedLongWidth { L32, L64 };
62
72
63
73
static ExitOnError ExitOnErr;
64
74
75
+ static StringRef TmpSuffix = " .tmp" ;
76
+
65
77
// Apply a custom category to all command-line options so that they are the
66
78
// only ones displayed.
67
79
static llvm::cl::OptionCategory
@@ -72,6 +84,8 @@ static cl::opt<std::string>
72
84
cl::cat(LibCLCRemanglerToolCategory));
73
85
static cl::opt<std::string> OutputFilename (" o" , cl::init(" -" ),
74
86
cl::desc(" Output filename" ));
87
+ static cl::opt<std::string> TargetTriple (" triple" , cl::init(" " ),
88
+ cl::desc(" Device target triple" ));
75
89
static cl::opt<SupportedLongWidth>
76
90
LongWidth (" long-width" ,
77
91
cl::values (clEnumValN(SupportedLongWidth::L32, " l32" ,
@@ -271,6 +285,7 @@ class Remangler {
271
285
: AST(AST), Root(Root), TypeReplacements(TypeReplacements) {
272
286
MangleContext.reset (
273
287
ItaniumMangleContext::create (*AST, AST->getDiagnostics ()));
288
+ TargetDefaultAddrSpace = AST->getTargetAddressSpace (LangAS::Default);
274
289
}
275
290
276
291
bool hasFailed () { return Failed; }
@@ -628,6 +643,14 @@ class Remangler {
628
643
for (auto I = PossibleKinds.rbegin (); I != PossibleKinds.rend (); ++I) {
629
644
switch (I->K ) {
630
645
case Node::Kind::KPointerType: {
646
+ if (TargetDefaultAddrSpace != 0 ) {
647
+ if (Res.hasAddressSpace () &&
648
+ toTargetAddressSpace (Res.getAddressSpace ()) ==
649
+ TargetDefaultAddrSpace)
650
+ Res = AST->removeAddrSpaceQualType (Res);
651
+ else if (!Res.hasAddressSpace ())
652
+ Res = AST->getAddrSpaceQualType (Res, LangAS::opencl_private);
653
+ }
631
654
Res = AST->getPointerType (Res);
632
655
break ;
633
656
}
@@ -709,6 +732,8 @@ class Remangler {
709
732
710
733
std::map<std::string, clang::QualType> NestedNamesQTMap{};
711
734
NamespaceDecl *SpvNamespace = nullptr ;
735
+
736
+ unsigned TargetDefaultAddrSpace;
712
737
};
713
738
714
739
class TargetTypeReplacements {
@@ -872,7 +897,7 @@ class LibCLCRemangler : public ASTConsumer {
872
897
Remangler R{ASTCtx, FunctionTree,
873
898
Replacements.getParameterTypeReplacements ()};
874
899
875
- std::string const RemangledName = R.remangle ();
900
+ std::string RemangledName = R.remangle ();
876
901
877
902
if (R.hasFailed ())
878
903
return false ;
@@ -891,6 +916,18 @@ class LibCLCRemangler : public ASTConsumer {
891
916
return false ;
892
917
}
893
918
919
+ // When TargetDefaultAddrSpace is not 0, there is a possibility that
920
+ // RemangledName may already exist. For instance, the function name
921
+ // _Z1fPU3AS4i would be remangled to _Z1fPi, which is a valid variant and
922
+ // might already be present. Since we cannot alter the name of an existing
923
+ // variant function that may not have been processed yet, we append a
924
+ // temporary suffix to RemangledName to prevent a name clash. This
925
+ // temporary suffix will be removed during the post-processing stage, once
926
+ // all functions have been handled.
927
+ if (ASTCtx->getTargetAddressSpace (LangAS::Default) != 0 )
928
+ if (M->getFunction (RemangledName))
929
+ RemangledName += TmpSuffix;
930
+
894
931
// If the remangled name already exists in the module then we have to
895
932
// assume it does the right thing already. We're only going to end up
896
933
// creating a copy of that function without external users being able to
@@ -910,6 +947,32 @@ class LibCLCRemangler : public ASTConsumer {
910
947
return true ;
911
948
}
912
949
950
+ // When TargetDefaultAddrSpace is not 0, post-processing is necessary after
951
+ // all functions have been processed. During this stage, the temporary suffix
952
+ // is removed from the remangled name.
953
+ void postProcessRemoveTmpSuffix (llvm::Module *M) {
954
+ if (TestRun)
955
+ return ;
956
+ for (auto &F : *M) {
957
+ StringRef Name = F.getName ();
958
+ if (!Name.consume_back (TmpSuffix))
959
+ continue ;
960
+ // If a name clash persists, the old function is renamed. For example,
961
+ // _Z1fPi is remangled to _Z1fPU3AS0i, and the remangler clones
962
+ // _Z1fPU3AS0i to _Z1fPi to preserve the original implementation.
963
+ // Subsequently, _Z1fPU3AS4i is remangled to _Z1fPi, and the remangled
964
+ // name is temporarily changed to _Z1fPi$TmpSuffix. When attempting to
965
+ // revert _Z1fPi$TmpSuffix back to _Z1fPi, a clash occurs because _Z1fPi
966
+ // still exists. Delete the old _Z1fPi which is no longer useful.
967
+ if (auto *Func = M->getFunction (Name)) {
968
+ Func->replaceAllUsesWith (ConstantPointerNull::get (Func->getType ()));
969
+ Func->eraseFromParent ();
970
+ }
971
+ // Complete the mangling process from _Z1fPU3AS4i to _Z1fPi.
972
+ F.setName (Name);
973
+ }
974
+ }
975
+
913
976
void handleModule (llvm::Module *M) {
914
977
std::error_code EC;
915
978
std::unique_ptr<ToolOutputFile> Out (
@@ -935,6 +998,7 @@ class LibCLCRemangler : public ASTConsumer {
935
998
bool Success = true ;
936
999
for (auto *Func : FuncList)
937
1000
Success &= remangleFunction (*Func, M);
1001
+ postProcessRemoveTmpSuffix (M);
938
1002
// Only fail after all to give as much context as possible.
939
1003
if (!Success) {
940
1004
errs () << " Failed to remangle all mangled functions in module.\n " ;
@@ -983,7 +1047,18 @@ int main(int argc, const char **argv) {
983
1047
984
1048
// Use a default Compilation DB instead of the build one, as it might contain
985
1049
// toolchain specific options, not compatible with clang.
986
- FixedCompilationDatabase Compilations (" ." , std::vector<std::string>());
1050
+ // Configure the triple to ensure that clang correctly sets up TargetInfo
1051
+ // which is essential for querying the target address space. This allows the
1052
+ // remangler to have the same target address space mapping as the mangling
1053
+ // performed in the SYCL device code compilation.
1054
+ std::vector<std::string> CommandLine;
1055
+ CommandLine.push_back (" -cc1" );
1056
+ CommandLine.push_back (" -triple" );
1057
+ CommandLine.push_back (TargetTriple);
1058
+ // Workaround error: unknown argument -resource-dir=, which isn't a CC1Option.
1059
+ CommandLine.push_back (" -resource-dir" );
1060
+ CommandLine.push_back (" ." );
1061
+ FixedCompilationDatabase Compilations (" ." , CommandLine);
987
1062
ClangTool Tool (Compilations, ExpectedParser->getSourcePathList ());
988
1063
989
1064
LibCLCRemanglerActionFactory LRAF{};
0 commit comments