-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[ARM64EC] Add support for function aliases on ARM64EC #132295
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
Conversation
@llvm/pr-subscribers-backend-aarch64 Author: Jacek Caban (cjacek) ChangesRequired for mingw-w64, which uses the alias attribute in its CRT. Follows ARM64EC mangling rules by mangling the alias symbol and emitting an unmangled anti-dependency alias. Since metadata is not allowed on GlobalAlias objects, extend arm64ec_unmangled_name to support multiple unmangled names and attach the alias anti-dependency name to the target function's metadata. Full diff: https://github.com/llvm/llvm-project/pull/132295.diff 4 Files Affected:
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index 066d62b3d4b4b..9553a44fb317e 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -627,10 +627,10 @@ Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
Function::Create(Arm64Ty, GlobalValue::WeakODRLinkage, 0, ThunkName, M);
GuestExit->setComdat(M->getOrInsertComdat(ThunkName));
GuestExit->setSection(".wowthk$aa");
- GuestExit->setMetadata(
+ GuestExit->addMetadata(
"arm64ec_unmangled_name",
- MDNode::get(M->getContext(),
- MDString::get(M->getContext(), F->getName())));
+ *MDNode::get(M->getContext(),
+ MDString::get(M->getContext(), F->getName())));
GuestExit->setMetadata(
"arm64ec_ecmangled_name",
MDNode::get(M->getContext(),
@@ -803,6 +803,23 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
DispatchFnGlobal =
M->getOrInsertGlobal("__os_arm64x_dispatch_call", DispatchFnPtrType);
+ // Mangle names of function aliases and add the alias name to
+ // arm64ec_unmangled_name metadata to ensure a weak anti-dependency symbol is
+ // emitted for the alias as well. Do this early, before handling
+ // hybrid_patchable functions, to avoid mangling their aliases.
+ for (GlobalAlias &A : Mod.aliases()) {
+ auto F = dyn_cast_or_null<Function>(A.getAliaseeObject());
+ if (!F)
+ continue;
+ if (std::optional<std::string> MangledName =
+ getArm64ECMangledFunctionName(A.getName().str())) {
+ F->addMetadata("arm64ec_unmangled_name",
+ *MDNode::get(M->getContext(),
+ MDString::get(M->getContext(), A.getName())));
+ A.setName(MangledName.value());
+ }
+ }
+
DenseMap<GlobalAlias *, GlobalAlias *> FnsMap;
SetVector<GlobalAlias *> PatchableFns;
@@ -837,20 +854,24 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
// emitGlobalAlias to emit the right alias.
auto *A =
GlobalAlias::create(GlobalValue::LinkOnceODRLinkage, OrigName, &F);
+ auto *AM = GlobalAlias::create(GlobalValue::LinkOnceODRLinkage,
+ MangledName.value(), &F);
+ F.replaceUsesWithIf(AM,
+ [](Use &U) { return isa<GlobalAlias>(U.getUser()); });
F.replaceAllUsesWith(A);
F.setMetadata("arm64ec_exp_name",
MDNode::get(M->getContext(),
MDString::get(M->getContext(),
"EXP+" + MangledName.value())));
A->setAliasee(&F);
+ AM->setAliasee(&F);
if (F.hasDLLExportStorageClass()) {
A->setDLLStorageClass(GlobalValue::DLLExportStorageClass);
F.setDLLStorageClass(GlobalValue::DefaultStorageClass);
}
- FnsMap[A] = GlobalAlias::create(GlobalValue::LinkOnceODRLinkage,
- MangledName.value(), &F);
+ FnsMap[A] = AM;
PatchableFns.insert(A);
}
}
@@ -928,9 +949,9 @@ bool AArch64Arm64ECCallLowering::processFunction(
if (!F.hasLocalLinkage() || F.hasAddressTaken()) {
if (std::optional<std::string> MangledName =
getArm64ECMangledFunctionName(F.getName().str())) {
- F.setMetadata("arm64ec_unmangled_name",
- MDNode::get(M->getContext(),
- MDString::get(M->getContext(), F.getName())));
+ F.addMetadata("arm64ec_unmangled_name",
+ *MDNode::get(M->getContext(),
+ MDString::get(M->getContext(), F.getName())));
if (F.hasComdat() && F.getComdat()->getName() == F.getName()) {
Comdat *MangledComdat = M->getOrInsertComdat(MangledName.value());
SmallVector<GlobalObject *> ComdatUsers =
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 47c0a1fab08f7..5e9bc4f48b0af 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -45,6 +45,7 @@
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -1381,22 +1382,21 @@ void AArch64AsmPrinter::emitFunctionEntryLabel() {
return Sym;
};
- if (MCSymbol *UnmangledSym =
- getSymbolFromMetadata("arm64ec_unmangled_name")) {
- MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name");
-
- if (ECMangledSym) {
- // An external function, emit the alias from the unmangled symbol to
- // mangled symbol name and the alias from the mangled symbol to guest
- // exit thunk.
+ SmallVector<MDNode *> UnmangledNames;
+ MF->getFunction().getMetadata("arm64ec_unmangled_name", UnmangledNames);
+ for (MDNode *Node : UnmangledNames) {
+ StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
+ MCSymbol *UnmangledSym = MMI->getContext().getOrCreateSymbol(NameStr);
+ if (std::optional<std::string> MangledName =
+ getArm64ECMangledFunctionName(UnmangledSym->getName())) {
+ MCSymbol *ECMangledSym =
+ MMI->getContext().getOrCreateSymbol(*MangledName);
emitFunctionAlias(UnmangledSym, ECMangledSym);
- emitFunctionAlias(ECMangledSym, CurrentFnSym);
- } else {
- // A function implementation, emit the alias from the unmangled symbol
- // to mangled symbol name.
- emitFunctionAlias(UnmangledSym, CurrentFnSym);
}
}
+ if (MCSymbol *ECMangledSym =
+ getSymbolFromMetadata("arm64ec_ecmangled_name"))
+ emitFunctionAlias(ECMangledSym, CurrentFnSym);
}
}
diff --git a/llvm/test/CodeGen/AArch64/arm64ec-alias.ll b/llvm/test/CodeGen/AArch64/arm64ec-alias.ll
new file mode 100644
index 0000000000000..03cc873136940
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/arm64ec-alias.ll
@@ -0,0 +1,42 @@
+; RUN: llc -mtriple arm64ec-windows-msvc -filetype asm -o - %s | FileCheck %s
+
+define void @func() {
+ ret void
+}
+
+define dso_local void @patchable_func() hybrid_patchable {
+ ret void
+}
+
+@func_alias = alias void (), ptr @func
+@func_alias2 = alias void (), ptr @func_alias
+@patchable_alias = alias void (), ptr @patchable_func
+
+; CHECK: .weak_anti_dep func_alias
+; CHECK-NEXT: .set func_alias, "#func_alias"
+; CHECK-NEXT: .weak_anti_dep func_alias2
+; CHECK-NEXT: .set func_alias2, "#func_alias2"
+; CHECK-NEXT: .weak_anti_dep func
+; CHECK-NEXT: .set func, "#func"
+; CHECK: .weak_anti_dep patchable_alias
+; CHECK-NEXT: .set patchable_alias, "#patchable_alias"
+
+; CHECK: .globl "#func_alias"
+; CHECK-NEXT: .def "#func_alias";
+; CHECK-NEXT: .scl 2;
+; CHECK-NEXT: .type 32;
+; CHECK-NEXT: .endef
+; CHECK-NEXT: .set "#func_alias", "#func"
+; CHECK-NEXT: .globl "#func_alias2"
+; CHECK-NEXT: .def "#func_alias2";
+; CHECK-NEXT: .scl 2;
+; CHECK-NEXT: .type 32;
+; CHECK-NEXT: .endef
+; CHECK-NEXT: .set "#func_alias2", "#func_alias"
+
+; CHECK: .globl "#patchable_alias"
+; CHECK-NEXT: .def "#patchable_alias";
+; CHECK-NEXT: .scl 2;
+; CHECK-NEXT: .type 32;
+; CHECK-NEXT: .endef
+; CHECK-NEXT: .set "#patchable_alias", "#patchable_func"
diff --git a/llvm/test/CodeGen/AArch64/dllexport.ll b/llvm/test/CodeGen/AArch64/dllexport.ll
index 580fb5fd9e79e..e15fc0a928b66 100644
--- a/llvm/test/CodeGen/AArch64/dllexport.ll
+++ b/llvm/test/CodeGen/AArch64/dllexport.ll
@@ -88,10 +88,10 @@ define weak_odr dllexport void @l() {
; CHECK-GNU-EC: .ascii " -export:o,data"
; CHECK-GNU-EC: .ascii " -export:p,data"
; CHECK-GNU-EC: .ascii " -export:q,data"
-; CHECK-GNU-EC: .ascii " -export:r"
-; CHECK-GNU-EC: .ascii " -export:s"
-; CHECK-GNU-EC: .ascii " -export:t"
-; CHECK-GNU-EC: .ascii " -export:u"
+; CHECK-GNU-EC: .ascii " -export:#r,EXPORTAS,r"
+; CHECK-GNU-EC: .ascii " -export:#s,EXPORTAS,s"
+; CHECK-GNU-EC: .ascii " -export:#t,EXPORTAS,t"
+; CHECK-GNU-EC: .ascii " -export:#u,EXPORTAS,u"
; CHECK-MSVC-EC-NOT: /EXPORT:f
; CHECK-MSVC-EC-NOT: /EXPORT:#f,EXPORTAS,f
; CHECK-MSVC-EC: .ascii " /EXPORT:#g,EXPORTAS,g"
@@ -106,7 +106,7 @@ define weak_odr dllexport void @l() {
; CHECK-MSVC-EC: .ascii " /EXPORT:o,DATA"
; CHECK-MSVC-EC: .ascii " /EXPORT:p,DATA"
; CHECK-MSVC-EC: .ascii " /EXPORT:q,DATA"
-; CHECK-MSVC-EC: .ascii " /EXPORT:r"
-; CHECK-MSVC-EC: .ascii " /EXPORT:s"
-; CHECK-MSVC-EC: .ascii " /EXPORT:t"
-; CHECK-MSVC-EC: .ascii " /EXPORT:u"
+; CHECK-MSVC-EC: .ascii " /EXPORT:#r,EXPORTAS,r"
+; CHECK-MSVC-EC: .ascii " /EXPORT:#s,EXPORTAS,s"
+; CHECK-MSVC-EC: .ascii " /EXPORT:#t,EXPORTAS,t"
+; CHECK-MSVC-EC: .ascii " /EXPORT:#u,EXPORTAS,u"
|
; CHECK-MSVC-EC: .ascii " /EXPORT:s" | ||
; CHECK-MSVC-EC: .ascii " /EXPORT:t" | ||
; CHECK-MSVC-EC: .ascii " /EXPORT:u" | ||
; CHECK-MSVC-EC: .ascii " /EXPORT:#r,EXPORTAS,r" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work with the MSVC linker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it works, I rechecked to be sure. Thanks!
Required for mingw-w64, which uses the alias attribute in its CRT. Follows ARM64EC mangling rules by mangling the alias symbol and emitting an unmangled anti-dependency alias. Since metadata is not allowed on GlobalAlias objects, extend arm64ec_unmangled_name to support multiple unmangled names and attach the alias anti-dependency name to the target function's metadata.
Required for mingw-w64, which uses the alias attribute in its CRT. Follows ARM64EC mangling rules by mangling the alias symbol and emitting an unmangled anti-dependency alias. Since metadata is not allowed on GlobalAlias objects, extend arm64ec_unmangled_name to support multiple unmangled names and attach the alias anti-dependency name to the target function's metadata.
Required for mingw-w64, which uses the alias attribute in its CRT.
Follows ARM64EC mangling rules by mangling the alias symbol and emitting an unmangled anti-dependency alias. Since metadata is not allowed on GlobalAlias objects, extend arm64ec_unmangled_name to support multiple unmangled names and attach the alias anti-dependency name to the target function's metadata.