Skip to content

[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

Merged
merged 1 commit into from
Mar 31, 2025
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
37 changes: 29 additions & 8 deletions llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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 =
Expand Down
26 changes: 13 additions & 13 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
}

Expand Down
42 changes: 42 additions & 0 deletions llvm/test/CodeGen/AArch64/arm64ec-alias.ll
Original file line number Diff line number Diff line change
@@ -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"
16 changes: 8 additions & 8 deletions llvm/test/CodeGen/AArch64/dllexport.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Copy link
Contributor

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?

Copy link
Contributor Author

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!

; CHECK-MSVC-EC: .ascii " /EXPORT:#s,EXPORTAS,s"
; CHECK-MSVC-EC: .ascii " /EXPORT:#t,EXPORTAS,t"
; CHECK-MSVC-EC: .ascii " /EXPORT:#u,EXPORTAS,u"
Loading