3333// char, signed char)`), is not defined. The remangler creates a clone
3434// of the renamed function,`_Z1fxaa`, to this permutation, `_Z1fxca`.
3535//
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+ //
3645// ===----------------------------------------------------------------------===//
3746
3847#include " clang/AST/Mangle.h"
4352#include " llvm/Bitcode/BitcodeReader.h"
4453#include " llvm/Bitcode/BitcodeWriter.h"
4554#include " llvm/Demangle/ItaniumDemangle.h"
55+ #include " llvm/IR/Constants.h"
4656#include " llvm/IR/DiagnosticInfo.h"
4757#include " llvm/IR/DiagnosticPrinter.h"
4858#include " llvm/IRReader/IRReader.h"
@@ -62,6 +72,8 @@ enum class SupportedLongWidth { L32, L64 };
6272
6373static ExitOnError ExitOnErr;
6474
75+ static StringRef TmpSuffix = " .tmp" ;
76+
6577// Apply a custom category to all command-line options so that they are the
6678// only ones displayed.
6779static llvm::cl::OptionCategory
@@ -72,6 +84,8 @@ static cl::opt<std::string>
7284 cl::cat(LibCLCRemanglerToolCategory));
7385static cl::opt<std::string> OutputFilename (" o" , cl::init(" -" ),
7486 cl::desc(" Output filename" ));
87+ static cl::opt<std::string> TargetTriple (" triple" , cl::init(" " ),
88+ cl::desc(" Device target triple" ));
7589static cl::opt<SupportedLongWidth>
7690 LongWidth (" long-width" ,
7791 cl::values (clEnumValN(SupportedLongWidth::L32, " l32" ,
@@ -271,6 +285,7 @@ class Remangler {
271285 : AST(AST), Root(Root), TypeReplacements(TypeReplacements) {
272286 MangleContext.reset (
273287 ItaniumMangleContext::create (*AST, AST->getDiagnostics ()));
288+ TargetDefaultAddrSpace = AST->getTargetAddressSpace (LangAS::Default);
274289 }
275290
276291 bool hasFailed () { return Failed; }
@@ -628,6 +643,14 @@ class Remangler {
628643 for (auto I = PossibleKinds.rbegin (); I != PossibleKinds.rend (); ++I) {
629644 switch (I->K ) {
630645 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+ }
631654 Res = AST->getPointerType (Res);
632655 break ;
633656 }
@@ -709,6 +732,8 @@ class Remangler {
709732
710733 std::map<std::string, clang::QualType> NestedNamesQTMap{};
711734 NamespaceDecl *SpvNamespace = nullptr ;
735+
736+ unsigned TargetDefaultAddrSpace;
712737};
713738
714739class TargetTypeReplacements {
@@ -872,7 +897,7 @@ class LibCLCRemangler : public ASTConsumer {
872897 Remangler R{ASTCtx, FunctionTree,
873898 Replacements.getParameterTypeReplacements ()};
874899
875- std::string const RemangledName = R.remangle ();
900+ std::string RemangledName = R.remangle ();
876901
877902 if (R.hasFailed ())
878903 return false ;
@@ -891,6 +916,18 @@ class LibCLCRemangler : public ASTConsumer {
891916 return false ;
892917 }
893918
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+
894931 // If the remangled name already exists in the module then we have to
895932 // assume it does the right thing already. We're only going to end up
896933 // creating a copy of that function without external users being able to
@@ -910,6 +947,32 @@ class LibCLCRemangler : public ASTConsumer {
910947 return true ;
911948 }
912949
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+
913976 void handleModule (llvm::Module *M) {
914977 std::error_code EC;
915978 std::unique_ptr<ToolOutputFile> Out (
@@ -935,6 +998,7 @@ class LibCLCRemangler : public ASTConsumer {
935998 bool Success = true ;
936999 for (auto *Func : FuncList)
9371000 Success &= remangleFunction (*Func, M);
1001+ postProcessRemoveTmpSuffix (M);
9381002 // Only fail after all to give as much context as possible.
9391003 if (!Success) {
9401004 errs () << " Failed to remangle all mangled functions in module.\n " ;
@@ -983,7 +1047,18 @@ int main(int argc, const char **argv) {
9831047
9841048 // Use a default Compilation DB instead of the build one, as it might contain
9851049 // 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);
9871062 ClangTool Tool (Compilations, ExpectedParser->getSourcePathList ());
9881063
9891064 LibCLCRemanglerActionFactory LRAF{};
0 commit comments