From 34cadf26ba9a680f30e153748c2d519037e48cc8 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 9 May 2025 03:34:12 -0700 Subject: [PATCH 1/2] [libspirv][remangler] Remangle pointer address space when target's default addrspace is private For target where default address space is private, pointer address space mangling in libclc is not compatible with SYCL mangling. Take spir64 target as example, OpenCL mangling: _Z17__spirv_ocl_fractfPU3AS4f(float, ptr addrspace(4)) _Z17__spirv_ocl_fractfPf(float, ptr) SYCL mangling: _Z17__spirv_ocl_fractfPf(float, ptr addrspace(4)) _Z17__spirv_ocl_fractfPU3AS0f(float, ptr) This leads to issue when linking libclc built-ins to SYCL device code. This PR fixes the issue by remangling libclc built-ins to align with SYCL: Remangle _Z17__spirv_ocl_fractfPU3AS4f to _Z17__spirv_ocl_fractfPf. Remangle _Z17__spirv_ocl_fractfPf to _Z17__spirv_ocl_fractfPU3AS0f. Relates to https://github.com/intel/llvm/issues/16703 --- libclc/cmake/modules/AddLibclc.cmake | 1 + .../libclc-remangler/LibclcRemangler.cpp | 77 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/libclc/cmake/modules/AddLibclc.cmake b/libclc/cmake/modules/AddLibclc.cmake index da5c1f3d4a7b4..da2f305e78f15 100644 --- a/libclc/cmake/modules/AddLibclc.cmake +++ b/libclc/cmake/modules/AddLibclc.cmake @@ -494,6 +494,7 @@ function(add_libclc_builtin_set) COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBCLC_LIBRARY_OUTPUT_INTDIR} COMMAND ${libclc-remangler_exe} -o "${builtins_remangle_path}" + --triple=${ARG_TRIPLE} --long-width=${long_width} --char-signedness=${signedness} --input-ir=${builtins_lib} diff --git a/libclc/utils/libclc-remangler/LibclcRemangler.cpp b/libclc/utils/libclc-remangler/LibclcRemangler.cpp index 84e14cd328093..f231438fabc0c 100644 --- a/libclc/utils/libclc-remangler/LibclcRemangler.cpp +++ b/libclc/utils/libclc-remangler/LibclcRemangler.cpp @@ -33,6 +33,15 @@ // char, signed char)`), is not defined. The remangler creates a clone // of the renamed function,`_Z1fxaa`, to this permutation, `_Z1fxca`. // +// Remangled Pointer Address Space Example: +// If libclc defined a function `f(int *)`, the mangled name is +// `_Z1fPU3AS4i` for a target when generic address space is 4. The +// remangler would rename this function to `_Z1fPi`, to be +// consistent with SYCL device code mangling for the target. If libclc +// defined a function `f(private int *)`, the mangled name is +// `_Z1fPi` when default address space is private. The remangler would +// rename it to `_Z1fPU3AS0i`. +// //===----------------------------------------------------------------------===// #include "clang/AST/Mangle.h" @@ -62,6 +71,8 @@ enum class SupportedLongWidth { L32, L64 }; static ExitOnError ExitOnErr; +static StringRef TmpSuffix = ".tmp"; + // Apply a custom category to all command-line options so that they are the // only ones displayed. static llvm::cl::OptionCategory @@ -72,6 +83,8 @@ static cl::opt cl::cat(LibCLCRemanglerToolCategory)); static cl::opt OutputFilename("o", cl::init("-"), cl::desc("Output filename")); +static cl::opt TargetTriple("triple", cl::init(""), + cl::desc("Device target triple")); static cl::opt LongWidth("long-width", cl::values(clEnumValN(SupportedLongWidth::L32, "l32", @@ -271,6 +284,7 @@ class Remangler { : AST(AST), Root(Root), TypeReplacements(TypeReplacements) { MangleContext.reset( ItaniumMangleContext::create(*AST, AST->getDiagnostics())); + TargetGenericAddrSpace = AST->getTargetAddressSpace(LangAS::Default); } bool hasFailed() { return Failed; } @@ -628,7 +642,15 @@ class Remangler { for (auto I = PossibleKinds.rbegin(); I != PossibleKinds.rend(); ++I) { switch (I->K) { case Node::Kind::KPointerType: { - Res = AST->getPointerType(Res); + if (TargetGenericAddrSpace != 0 && Res.hasAddressSpace() && + toTargetAddressSpace(Res.getAddressSpace()) == + TargetGenericAddrSpace) + Res = AST->getPointerType(AST->removeAddrSpaceQualType(Res)); + else if (TargetGenericAddrSpace != 0 && !Res.hasAddressSpace()) + Res = AST->getPointerType( + AST->getAddrSpaceQualType(Res, LangAS::opencl_private)); + else + Res = AST->getPointerType(Res); break; } case Node::Kind::KVectorType: { @@ -709,6 +731,8 @@ class Remangler { std::map NestedNamesQTMap{}; NamespaceDecl *SpvNamespace = nullptr; + + unsigned TargetGenericAddrSpace; }; class TargetTypeReplacements { @@ -865,7 +889,7 @@ class LibCLCRemangler : public ASTConsumer { Remangler R{ASTCtx, FunctionTree, Replacements.getParameterTypeReplacements()}; - std::string const RemangledName = R.remangle(); + std::string RemangledName = R.remangle(); if (R.hasFailed()) return false; @@ -883,6 +907,16 @@ class LibCLCRemangler : public ASTConsumer { errs() << "Test run failure!\n"; return false; } + // When TargetGenericAddrSpace is not 0, there is a possibility that + // RemangledName may already exist. For instance, the function name + // _Z1fPU3AS4i would be remangled to _Z1fPi, which is a valid variant and + // might already be present. Since we cannot alter the name of an existing + // variant function that may not have been processed yet, we append a + // temporary suffix to RemangledName to prevent a name clash. This + // temporary suffix will be removed during the post-processing stage, once + // all functions have been handled. + if (M->getFunction(RemangledName)) + RemangledName += TmpSuffix; Func.setName(RemangledName); // Make a clone of a suitable function using the old name if there is a @@ -894,6 +928,31 @@ class LibCLCRemangler : public ASTConsumer { return true; } + // When TargetGenericAddrSpace is not 0, post-processing is necessary after + // all functions have been processed. During this stage, the temporary suffix + // is removed from the remangled name. + void postProcessRemoveTmpSuffix(llvm::Module *M) { + if (TestRun) + return; + for (auto &F : *M) { + StringRef Name = F.getName(); + if (!Name.consume_back(TmpSuffix)) + continue; + // If a name clash persists, the old function is renamed. For example, + // _Z1fPi is remangled to _Z1fPU3AS0i, and the remangler clones + // _Z1fPU3AS0i to _Z1fPi to preserve the original implementation. + // Subsequently, _Z1fPU3AS4i is remangled to _Z1fPi, and the remangled + // name is temporarily changed to _Z1fPi$TmpSuffix. When attempting to + // revert _Z1fPi$TmpSuffix back to _Z1fPi, a clash occurs because _Z1fPi + // still exists. Since _Z1fPi is no longer useful, it is renamed to + // _Z1fPi.old, + if (auto *Func = M->getFunction(Name)) + Func->setName(Twine(Name) + ".old"); + // Complete the mangling process from _Z1fPU3AS4i to _Z1fPi. + F.setName(Name); + } + } + void handleModule(llvm::Module *M) { std::error_code EC; std::unique_ptr Out( @@ -919,6 +978,7 @@ class LibCLCRemangler : public ASTConsumer { bool Success = true; for (auto *Func : FuncList) Success &= remangleFunction(*Func, M); + postProcessRemoveTmpSuffix(M); // Only fail after all to give as much context as possible. if (!Success) { errs() << "Failed to remangle all mangled functions in module.\n"; @@ -967,7 +1027,18 @@ int main(int argc, const char **argv) { // Use a default Compilation DB instead of the build one, as it might contain // toolchain specific options, not compatible with clang. - FixedCompilationDatabase Compilations(".", std::vector()); + // Configure the triple to ensure that clang correctly sets up TargetInfo + // which is essential for querying the target address space. This allows the + // remangler to have the same target address space mapping as the mangling + // performed in the SYCL device code compilation. + std::vector CommandLine; + CommandLine.push_back("-cc1"); + CommandLine.push_back("-triple"); + CommandLine.push_back(TargetTriple); + // Workaround error `unknown argument resource-dir` + CommandLine.push_back("-resource-dir"); + CommandLine.push_back("."); + FixedCompilationDatabase Compilations(".", CommandLine); ClangTool Tool(Compilations, ExpectedParser->getSourcePathList()); LibCLCRemanglerActionFactory LRAF{}; From 51cdef4fc438488a8e7240067002383f93ac86fe Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 9 May 2025 17:01:59 -0700 Subject: [PATCH 2/2] refine --- .../utils/libclc-remangler/LibclcRemangler.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libclc/utils/libclc-remangler/LibclcRemangler.cpp b/libclc/utils/libclc-remangler/LibclcRemangler.cpp index f231438fabc0c..8f44701c4db4b 100644 --- a/libclc/utils/libclc-remangler/LibclcRemangler.cpp +++ b/libclc/utils/libclc-remangler/LibclcRemangler.cpp @@ -642,15 +642,15 @@ class Remangler { for (auto I = PossibleKinds.rbegin(); I != PossibleKinds.rend(); ++I) { switch (I->K) { case Node::Kind::KPointerType: { - if (TargetGenericAddrSpace != 0 && Res.hasAddressSpace() && - toTargetAddressSpace(Res.getAddressSpace()) == - TargetGenericAddrSpace) - Res = AST->getPointerType(AST->removeAddrSpaceQualType(Res)); - else if (TargetGenericAddrSpace != 0 && !Res.hasAddressSpace()) - Res = AST->getPointerType( - AST->getAddrSpaceQualType(Res, LangAS::opencl_private)); - else - Res = AST->getPointerType(Res); + if (TargetGenericAddrSpace != 0) { + if (Res.hasAddressSpace() && + toTargetAddressSpace(Res.getAddressSpace()) == + TargetGenericAddrSpace) + Res = AST->removeAddrSpaceQualType(Res); + else if (!Res.hasAddressSpace()) + Res = AST->getAddrSpaceQualType(Res, LangAS::opencl_private); + } + Res = AST->getPointerType(Res); break; } case Node::Kind::KVectorType: {