Skip to content

Commit 781b312

Browse files
authored
[libspirv][remangler] Remangle pointer address space when target's default addrspace is private (#18383)
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 #16703 This PR is for targets whose default addrspace is private, such as spir64/spirv. In intel/llvm repo, currently there is no such libspirv target. In our downstream repo, we have a target of this kind. Put this PR in this repo to avoid customization in the downstream repo.
1 parent 601222a commit 781b312

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

libclc/cmake/modules/AddLibclc.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ function(add_libclc_builtin_set)
508508
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBCLC_LIBRARY_OUTPUT_INTDIR}
509509
COMMAND ${libclc-remangler_exe}
510510
-o "${builtins_remangle_path}"
511+
--triple=${ARG_TRIPLE}
511512
--long-width=${long_width}
512513
--char-signedness=${signedness}
513514
--input-ir=${builtins_lib}

libclc/utils/libclc-remangler/LibclcRemangler.cpp

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@
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"
@@ -43,6 +52,7 @@
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

6373
static 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.
6779
static llvm::cl::OptionCategory
@@ -72,6 +84,8 @@ static cl::opt<std::string>
7284
cl::cat(LibCLCRemanglerToolCategory));
7385
static 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"));
7589
static 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

714739
class 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

Comments
 (0)