[llvm] [ARM64EC] Add support for function aliases on ARM64EC (PR #132295)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 31 02:23:33 PDT 2025


https://github.com/cjacek updated https://github.com/llvm/llvm-project/pull/132295

>From d149055bf9f7d37500639b00527db091a7715b6a Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Tue, 10 Sep 2024 19:58:19 +0200
Subject: [PATCH] [ARM64EC] Add support for function aliases on ARM64EC

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.
---
 .../AArch64/AArch64Arm64ECCallLowering.cpp    | 37 ++++++++++++----
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 26 ++++++------
 llvm/test/CodeGen/AArch64/arm64ec-alias.ll    | 42 +++++++++++++++++++
 llvm/test/CodeGen/AArch64/dllexport.ll        | 16 +++----
 4 files changed, 92 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/arm64ec-alias.ll

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 d29a72a4f6884..db0652bc5949c 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"
@@ -1387,22 +1388,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"



More information about the llvm-commits mailing list