Skip to content

[SYCL][CUDA][libclc] Clone functions rather than aliasing in remangler #5921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libclc/utils/libclc-remangler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
Core
Demangle
Support
TransformUtils
)

add_clang_tool(libclc-remangler LibclcRemangler.cpp)
Expand Down
132 changes: 70 additions & 62 deletions libclc/utils/libclc-remangler/LibclcRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,28 @@
// `unsigned long`, and `char` to appear as if they use `long long`,
// `unsigned long long`, and `signed char`, as is consistent with the primitive
// types defined by OpenCL C. Following a remangling, the original function
// mangling will be made an alias to either the remangled function or a function
// with a suitable function if any exists. In some cases an alias of the
// remangled function is created for functions where multiple parameters have
// been replaced, and the replaced values are aliases.
// mangling will be built as a clone of either the remangled function or a
// function with a suitable function if any exists. In some cases a clone of
// the remangled function is created for functions where multiple parameters
// have been replaced, and the replaced values are aliases.
//
// Original Alias Example:
// Original Clone Example:
// If libclc defined a function `f(long)` the mangled name would be
// `_Z1fl`. The remangler would rename this function to `_Z1fx`
// (`f(long long)`.) If the target uses 64-bit `long`, `_Z1fl` is made
// an alias to the old function now under the name `_Z1fx`, whereas if
// the target uses 32-bit `long`, `_Z1fl` is made an alias to `_Z1fi`
// (`f(long long)`.) If the target uses 64-bit `long`, `_Z1fl` is
// cloned from the old function now under the name `_Z1fx`, whereas if
// the target uses 32-bit `long`, `_Z1fl` is cloned from `_Z1fi`
// (`f(int)`) if such a function exists.
//
// Remangled Alias Example:
// Remangled Clone Example:
// In cases where the remangled name squashes valid versions of a
// function an alias is created. `f(long, char, signed char)` would be
// function a clone is created. `f(long, char, signed char)` would be
// mangled to
// `_Z1flca`. The remangler would rename this function to `_Z1fyaa`
// (`f(long long, signed char, signed char)`). If the target uses a
// signed char then a valid alias `_Z1fyca`,
// signed char then a valid clone `_Z1fyca`,
// (`f(long long, char, signed char)`), is not defined. The remangler
// creates an alias of the renamed function,`_Z1fyaa` , to this
// creates a clone of the renamed function,`_Z1fyaa` , to this
// permutation, `_Z1fyca`.
//
//===----------------------------------------------------------------------===//
Expand All @@ -58,6 +58,8 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ValueMapper.h"

#include <iostream>
#include <memory>
Expand Down Expand Up @@ -153,7 +155,7 @@ class DefaultAllocator {
public:
void reset() { Alloc.reset(); }

template <typename T, typename... Args> T *makeNode(Args &&... args) {
template <typename T, typename... Args> T *makeNode(Args &&...args) {
return new (Alloc.allocate(sizeof(T))) T(std::forward<Args>(args)...);
}

Expand Down Expand Up @@ -478,19 +480,19 @@ class Remangler {

class TargetTypeReplacements {
SmallDenseMap<const char *, const char *> ParameterTypeReplacements;
SmallDenseMap<const char *, const char *> AliasTypeReplacements;
SmallDenseMap<const char *, const char *> RemangledAliasTypeReplacements;
SmallDenseMap<const char *, const char *> CloneTypeReplacements;
SmallDenseMap<const char *, const char *> RemangledCloneTypeReplacements;

void CreateRemangledTypeReplacements() {
// RemangleTypes which are not aliases or not the exact same alias type
for (auto &TypeReplacementPair : ParameterTypeReplacements)
if (AliasTypeReplacements.find(TypeReplacementPair.getFirst()) ==
AliasTypeReplacements.end())
RemangledAliasTypeReplacements[TypeReplacementPair.getFirst()] =
if (CloneTypeReplacements.find(TypeReplacementPair.getFirst()) ==
CloneTypeReplacements.end())
RemangledCloneTypeReplacements[TypeReplacementPair.getFirst()] =
TypeReplacementPair.getSecond();
else if (AliasTypeReplacements[TypeReplacementPair.getFirst()] !=
else if (CloneTypeReplacements[TypeReplacementPair.getFirst()] !=
TypeReplacementPair.getSecond())
RemangledAliasTypeReplacements[TypeReplacementPair.getFirst()] =
RemangledCloneTypeReplacements[TypeReplacementPair.getFirst()] =
TypeReplacementPair.getSecond();
}

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

// Make replaced long functions aliases to either integer or long long
// Make replaced long functions clones of either integer or long long
// variant
if (LongWidth == SupportedLongWidth::L32) {
AliasTypeReplacements["long"] = "int";
AliasTypeReplacements["unsigned long"] = "unsigned int";
CloneTypeReplacements["long"] = "int";
CloneTypeReplacements["unsigned long"] = "unsigned int";
} else {
AliasTypeReplacements["long"] = "long long";
AliasTypeReplacements["unsigned long"] = "unsigned long long";
CloneTypeReplacements["long"] = "long long";
CloneTypeReplacements["unsigned long"] = "unsigned long long";
}

// Make replaced char functions aliases to either integer or long long
// Make replaced char functions clones of either integer or long long
// variant
if (CharSignedness == Signedness::Signed) {
AliasTypeReplacements["char"] = "signed char";
CloneTypeReplacements["char"] = "signed char";
} else {
AliasTypeReplacements["char"] = "unsigned char";
CloneTypeReplacements["char"] = "unsigned char";
}

CreateRemangledTypeReplacements();
Expand All @@ -528,21 +530,21 @@ class TargetTypeReplacements {
return ParameterTypeReplacements;
}

SmallDenseMap<const char *, const char *> getAliasTypeReplacements() {
return AliasTypeReplacements;
SmallDenseMap<const char *, const char *> getCloneTypeReplacements() {
return CloneTypeReplacements;
}

SmallDenseMap<const char *, const char *>
getRemangledAliasTypeReplacements() {
return RemangledAliasTypeReplacements;
getRemangledCloneTypeReplacements() {
return RemangledCloneTypeReplacements;
}
};

bool createAliasFromMap(
bool createCloneFromMap(
Module *M, std::string originalName,
const itanium_demangle::Node *functionTree,
SmallDenseMap<const char *, const char *> TypeReplacements,
bool AliaseeTypeReplacement = false) {
bool CloneeTypeReplacement = false) {
Remangler ATR{functionTree, TypeReplacements};
std::string RemangledName = ATR.remangle();

Expand All @@ -553,39 +555,41 @@ bool createAliasFromMap(
if (RemangledName == originalName)
return true;

StringRef AliasName, AliaseeName;
if (AliaseeTypeReplacement) {
AliasName = originalName;
AliaseeName = RemangledName;
StringRef CloneName, CloneeName;
if (CloneeTypeReplacement) {
CloneName = originalName;
CloneeName = RemangledName;
} else {
AliasName = RemangledName;
AliaseeName = originalName;
CloneName = RemangledName;
CloneeName = originalName;
}

Function *Aliasee = M->getFunction(AliaseeName);
if (Aliasee) {
GlobalAlias::create(AliasName, Aliasee);
Function *Clonee = M->getFunction(CloneeName);
if (Clonee) {
ValueToValueMapTy Dummy;
Function *NewF = CloneFunction(Clonee, Dummy);
NewF->setName(std::string(CloneName));
} else if (Verbose) {
std::cout << "Could not create alias " << AliasName.data() << " : missing "
<< AliaseeName.data() << std::endl;
std::cout << "Could not create copy " << CloneName.data() << " : missing "
<< CloneeName.data() << std::endl;
}

return true;
}

bool createAliases(Module *M, std::string originalMangledName,
std::string remangledName,
const itanium_demangle::Node *functionTree,
TargetTypeReplacements replacements) {
// create alias of original function
if (!createAliasFromMap(M, originalMangledName, functionTree,
replacements.getAliasTypeReplacements(),
/* AliaseeTypeReplacement= */ true))
bool createClones(Module *M, std::string originalMangledName,
std::string remangledName,
const itanium_demangle::Node *functionTree,
TargetTypeReplacements replacements) {
// create clone of original function
if (!createCloneFromMap(M, originalMangledName, functionTree,
replacements.getCloneTypeReplacements(),
/* CloneeTypeReplacement= */ true))
return false;

// create alias from remangled function
if (!createAliasFromMap(M, remangledName, functionTree,
replacements.getRemangledAliasTypeReplacements()))
// create clone of remangled function
if (!createCloneFromMap(M, remangledName, functionTree,
replacements.getRemangledCloneTypeReplacements()))
return false;

return true;
Expand Down Expand Up @@ -621,10 +625,10 @@ bool remangleFunction(Function &func, Module *M,
}
func.setName(RemangledName);

// Make an alias to a suitable function using the old name if there is a
// type-mapping and the corresponding aliasee function exists.
if (!createAliases(M, MangledName, RemangledName, FunctionTree,
replacements))
// Make a clone of a suitable function using the old name if there is a
// type-mapping and the corresponding clonee function exists.
if (!createClones(M, MangledName, RemangledName, FunctionTree,
replacements))
return false;
}

Expand Down Expand Up @@ -661,10 +665,14 @@ int main(int argc, const char **argv) {
return 1;
}

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

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