[llvm] [ARM64EC] Add support for function aliases on ARM64EC (PR #132295)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 20 15:17:39 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Jacek Caban (cjacek)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/132295.diff
4 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp (+29-8)
- (modified) llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp (+13-13)
- (added) llvm/test/CodeGen/AArch64/arm64ec-alias.ll (+42)
- (modified) llvm/test/CodeGen/AArch64/dllexport.ll (+8-8)
``````````diff
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
+}
+
+ at func_alias = alias void (), ptr @func
+ at func_alias2 = alias void (), ptr @func_alias
+ at 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"
``````````
</details>
https://github.com/llvm/llvm-project/pull/132295
More information about the llvm-commits
mailing list