Skip to content

Commit 7b2fb02

Browse files
authored
[SYCL][CUDA][libclc] Clone functions rather than aliasing in remangler (#5921)
The libclc remangler handles function overloads with e.g. `long long` `long` and `int`, ensuring consistency with OpenCL C primitives. Previously, this was achieved by creating a `GlobalAlias` for each of the various overloads. However, the NVPTX target does not work with function aliases. Normally, an optimization pass removes these aliases, but the present approach prevents compiling with DPC++ for CUDA with `-O0`. This PR changes the behaviour of the remangler to emit function clones (a copy of the function with a different name). There is a risk that this bloats the compiled code, but optimization should remove unneeded clones, as it did with unneeded aliases. There is an additional barrier to `-O0` compilation for NVPTX relating to `nvvm_reflect`, addressed here: #5900 **Note:** this PR is best reviewed as separate commits. The first commit makes the (small) functional change. The second commit is simply renaming all 'Alias*' variables to 'Clone*'.
1 parent 5452a5d commit 7b2fb02

File tree

2 files changed

+71
-62
lines changed

2 files changed

+71
-62
lines changed

libclc/utils/libclc-remangler/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
55
Core
66
Demangle
77
Support
8+
TransformUtils
89
)
910

1011
add_clang_tool(libclc-remangler LibclcRemangler.cpp)

libclc/utils/libclc-remangler/LibclcRemangler.cpp

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@
1111
// `unsigned long`, and `char` to appear as if they use `long long`,
1212
// `unsigned long long`, and `signed char`, as is consistent with the primitive
1313
// types defined by OpenCL C. Following a remangling, the original function
14-
// mangling will be made an alias to either the remangled function or a function
15-
// with a suitable function if any exists. In some cases an alias of the
16-
// remangled function is created for functions where multiple parameters have
17-
// been replaced, and the replaced values are aliases.
14+
// mangling will be built as a clone of either the remangled function or a
15+
// function with a suitable function if any exists. In some cases a clone of
16+
// the remangled function is created for functions where multiple parameters
17+
// have been replaced, and the replaced values are aliases.
1818
//
19-
// Original Alias Example:
19+
// Original Clone Example:
2020
// If libclc defined a function `f(long)` the mangled name would be
2121
// `_Z1fl`. The remangler would rename this function to `_Z1fx`
22-
// (`f(long long)`.) If the target uses 64-bit `long`, `_Z1fl` is made
23-
// an alias to the old function now under the name `_Z1fx`, whereas if
24-
// the target uses 32-bit `long`, `_Z1fl` is made an alias to `_Z1fi`
22+
// (`f(long long)`.) If the target uses 64-bit `long`, `_Z1fl` is
23+
// cloned from the old function now under the name `_Z1fx`, whereas if
24+
// the target uses 32-bit `long`, `_Z1fl` is cloned from `_Z1fi`
2525
// (`f(int)`) if such a function exists.
2626
//
27-
// Remangled Alias Example:
27+
// Remangled Clone Example:
2828
// In cases where the remangled name squashes valid versions of a
29-
// function an alias is created. `f(long, char, signed char)` would be
29+
// function a clone is created. `f(long, char, signed char)` would be
3030
// mangled to
3131
// `_Z1flca`. The remangler would rename this function to `_Z1fyaa`
3232
// (`f(long long, signed char, signed char)`). If the target uses a
33-
// signed char then a valid alias `_Z1fyca`,
33+
// signed char then a valid clone `_Z1fyca`,
3434
// (`f(long long, char, signed char)`), is not defined. The remangler
35-
// creates an alias of the renamed function,`_Z1fyaa` , to this
35+
// creates a clone of the renamed function,`_Z1fyaa` , to this
3636
// permutation, `_Z1fyca`.
3737
//
3838
//===----------------------------------------------------------------------===//
@@ -58,6 +58,8 @@
5858
#include "llvm/Support/Signals.h"
5959
#include "llvm/Support/ToolOutputFile.h"
6060
#include "llvm/Support/raw_ostream.h"
61+
#include "llvm/Transforms/Utils/Cloning.h"
62+
#include "llvm/Transforms/Utils/ValueMapper.h"
6163

6264
#include <iostream>
6365
#include <memory>
@@ -153,7 +155,7 @@ class DefaultAllocator {
153155
public:
154156
void reset() { Alloc.reset(); }
155157

156-
template <typename T, typename... Args> T *makeNode(Args &&... args) {
158+
template <typename T, typename... Args> T *makeNode(Args &&...args) {
157159
return new (Alloc.allocate(sizeof(T))) T(std::forward<Args>(args)...);
158160
}
159161

@@ -478,19 +480,19 @@ class Remangler {
478480

479481
class TargetTypeReplacements {
480482
SmallDenseMap<const char *, const char *> ParameterTypeReplacements;
481-
SmallDenseMap<const char *, const char *> AliasTypeReplacements;
482-
SmallDenseMap<const char *, const char *> RemangledAliasTypeReplacements;
483+
SmallDenseMap<const char *, const char *> CloneTypeReplacements;
484+
SmallDenseMap<const char *, const char *> RemangledCloneTypeReplacements;
483485

484486
void CreateRemangledTypeReplacements() {
485487
// RemangleTypes which are not aliases or not the exact same alias type
486488
for (auto &TypeReplacementPair : ParameterTypeReplacements)
487-
if (AliasTypeReplacements.find(TypeReplacementPair.getFirst()) ==
488-
AliasTypeReplacements.end())
489-
RemangledAliasTypeReplacements[TypeReplacementPair.getFirst()] =
489+
if (CloneTypeReplacements.find(TypeReplacementPair.getFirst()) ==
490+
CloneTypeReplacements.end())
491+
RemangledCloneTypeReplacements[TypeReplacementPair.getFirst()] =
490492
TypeReplacementPair.getSecond();
491-
else if (AliasTypeReplacements[TypeReplacementPair.getFirst()] !=
493+
else if (CloneTypeReplacements[TypeReplacementPair.getFirst()] !=
492494
TypeReplacementPair.getSecond())
493-
RemangledAliasTypeReplacements[TypeReplacementPair.getFirst()] =
495+
RemangledCloneTypeReplacements[TypeReplacementPair.getFirst()] =
494496
TypeReplacementPair.getSecond();
495497
}
496498

@@ -503,22 +505,22 @@ class TargetTypeReplacements {
503505
// Replace char with signed char
504506
ParameterTypeReplacements["char"] = "signed char";
505507

506-
// Make replaced long functions aliases to either integer or long long
508+
// Make replaced long functions clones of either integer or long long
507509
// variant
508510
if (LongWidth == SupportedLongWidth::L32) {
509-
AliasTypeReplacements["long"] = "int";
510-
AliasTypeReplacements["unsigned long"] = "unsigned int";
511+
CloneTypeReplacements["long"] = "int";
512+
CloneTypeReplacements["unsigned long"] = "unsigned int";
511513
} else {
512-
AliasTypeReplacements["long"] = "long long";
513-
AliasTypeReplacements["unsigned long"] = "unsigned long long";
514+
CloneTypeReplacements["long"] = "long long";
515+
CloneTypeReplacements["unsigned long"] = "unsigned long long";
514516
}
515517

516-
// Make replaced char functions aliases to either integer or long long
518+
// Make replaced char functions clones of either integer or long long
517519
// variant
518520
if (CharSignedness == Signedness::Signed) {
519-
AliasTypeReplacements["char"] = "signed char";
521+
CloneTypeReplacements["char"] = "signed char";
520522
} else {
521-
AliasTypeReplacements["char"] = "unsigned char";
523+
CloneTypeReplacements["char"] = "unsigned char";
522524
}
523525

524526
CreateRemangledTypeReplacements();
@@ -528,21 +530,21 @@ class TargetTypeReplacements {
528530
return ParameterTypeReplacements;
529531
}
530532

531-
SmallDenseMap<const char *, const char *> getAliasTypeReplacements() {
532-
return AliasTypeReplacements;
533+
SmallDenseMap<const char *, const char *> getCloneTypeReplacements() {
534+
return CloneTypeReplacements;
533535
}
534536

535537
SmallDenseMap<const char *, const char *>
536-
getRemangledAliasTypeReplacements() {
537-
return RemangledAliasTypeReplacements;
538+
getRemangledCloneTypeReplacements() {
539+
return RemangledCloneTypeReplacements;
538540
}
539541
};
540542

541-
bool createAliasFromMap(
543+
bool createCloneFromMap(
542544
Module *M, std::string originalName,
543545
const itanium_demangle::Node *functionTree,
544546
SmallDenseMap<const char *, const char *> TypeReplacements,
545-
bool AliaseeTypeReplacement = false) {
547+
bool CloneeTypeReplacement = false) {
546548
Remangler ATR{functionTree, TypeReplacements};
547549
std::string RemangledName = ATR.remangle();
548550

@@ -553,39 +555,41 @@ bool createAliasFromMap(
553555
if (RemangledName == originalName)
554556
return true;
555557

556-
StringRef AliasName, AliaseeName;
557-
if (AliaseeTypeReplacement) {
558-
AliasName = originalName;
559-
AliaseeName = RemangledName;
558+
StringRef CloneName, CloneeName;
559+
if (CloneeTypeReplacement) {
560+
CloneName = originalName;
561+
CloneeName = RemangledName;
560562
} else {
561-
AliasName = RemangledName;
562-
AliaseeName = originalName;
563+
CloneName = RemangledName;
564+
CloneeName = originalName;
563565
}
564566

565-
Function *Aliasee = M->getFunction(AliaseeName);
566-
if (Aliasee) {
567-
GlobalAlias::create(AliasName, Aliasee);
567+
Function *Clonee = M->getFunction(CloneeName);
568+
if (Clonee) {
569+
ValueToValueMapTy Dummy;
570+
Function *NewF = CloneFunction(Clonee, Dummy);
571+
NewF->setName(std::string(CloneName));
568572
} else if (Verbose) {
569-
std::cout << "Could not create alias " << AliasName.data() << " : missing "
570-
<< AliaseeName.data() << std::endl;
573+
std::cout << "Could not create copy " << CloneName.data() << " : missing "
574+
<< CloneeName.data() << std::endl;
571575
}
572576

573577
return true;
574578
}
575579

576-
bool createAliases(Module *M, std::string originalMangledName,
577-
std::string remangledName,
578-
const itanium_demangle::Node *functionTree,
579-
TargetTypeReplacements replacements) {
580-
// create alias of original function
581-
if (!createAliasFromMap(M, originalMangledName, functionTree,
582-
replacements.getAliasTypeReplacements(),
583-
/* AliaseeTypeReplacement= */ true))
580+
bool createClones(Module *M, std::string originalMangledName,
581+
std::string remangledName,
582+
const itanium_demangle::Node *functionTree,
583+
TargetTypeReplacements replacements) {
584+
// create clone of original function
585+
if (!createCloneFromMap(M, originalMangledName, functionTree,
586+
replacements.getCloneTypeReplacements(),
587+
/* CloneeTypeReplacement= */ true))
584588
return false;
585589

586-
// create alias from remangled function
587-
if (!createAliasFromMap(M, remangledName, functionTree,
588-
replacements.getRemangledAliasTypeReplacements()))
590+
// create clone of remangled function
591+
if (!createCloneFromMap(M, remangledName, functionTree,
592+
replacements.getRemangledCloneTypeReplacements()))
589593
return false;
590594

591595
return true;
@@ -621,10 +625,10 @@ bool remangleFunction(Function &func, Module *M,
621625
}
622626
func.setName(RemangledName);
623627

624-
// Make an alias to a suitable function using the old name if there is a
625-
// type-mapping and the corresponding aliasee function exists.
626-
if (!createAliases(M, MangledName, RemangledName, FunctionTree,
627-
replacements))
628+
// Make a clone of a suitable function using the old name if there is a
629+
// type-mapping and the corresponding clonee function exists.
630+
if (!createClones(M, MangledName, RemangledName, FunctionTree,
631+
replacements))
628632
return false;
629633
}
630634

@@ -661,10 +665,14 @@ int main(int argc, const char **argv) {
661665
return 1;
662666
}
663667

664-
bool Success = true;
668+
std::vector<Function *> FuncList;
665669
for (auto &Func : M->getFunctionList())
666-
Success = remangleFunction(Func, M.get(), Replacements) && Success;
670+
FuncList.push_back(&Func);
667671

672+
bool Success = true;
673+
for (auto Func : FuncList) {
674+
Success = remangleFunction(*Func, M.get(), Replacements) && Success;
675+
}
668676
// Only fail after all to give as much context as possible.
669677
if (!Success) {
670678
errs() << "Failed to remangle all mangled functions in module.\n";

0 commit comments

Comments
 (0)