[llvm] [win][arm64ec] Handle empty function names (PR #151609)
Daniel Paoliello via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 1 10:53:10 PDT 2025
https://github.com/dpaoliello updated https://github.com/llvm/llvm-project/pull/151609
>From 59e8cda65f2a6b52815d14bdb28bf836813d6994 Mon Sep 17 00:00:00 2001
From: Daniel Paoliello <danpao at microsoft.com>
Date: Thu, 31 Jul 2025 15:27:29 -0700
Subject: [PATCH] [win][arm64ec] Handle empty function names
---
llvm/lib/IR/Mangler.cpp | 3 +++
.../AArch64/AArch64Arm64ECCallLowering.cpp | 18 +++++++++++++-----
.../test/CodeGen/AArch64/arm64ec-empty-name.ll | 15 +++++++++++++++
3 files changed, 31 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/arm64ec-empty-name.ll
diff --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp
index 010bd15e256dc..ca6a4804087ac 100644
--- a/llvm/lib/IR/Mangler.cpp
+++ b/llvm/lib/IR/Mangler.cpp
@@ -292,6 +292,9 @@ void llvm::emitLinkerFlagsForUsedCOFF(raw_ostream &OS, const GlobalValue *GV,
}
std::optional<std::string> llvm::getArm64ECMangledFunctionName(StringRef Name) {
+ assert(!Name.empty() &&
+ "getArm64ECMangledFunctionName requires non-empty name");
+
if (Name[0] != '?') {
// For non-C++ symbols, prefix the name with "#" unless it's already
// mangled.
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index 509cbb092705d..3748590ec6c4f 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -597,6 +597,14 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
return Thunk;
}
+std::optional<std::string> getArm64ECMangledFunctionName(GlobalValue &GV) {
+ if (!GV.hasName()) {
+ GV.setName("__unnamed");
+ }
+
+ return llvm::getArm64ECMangledFunctionName(GV.getName());
+}
+
// Builds the "guest exit thunk", a helper to call a function which may or may
// not be an exit thunk. (We optimistically assume non-dllimport function
// declarations refer to functions defined in AArch64 code; if the linker
@@ -608,7 +616,7 @@ Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
getThunkType(F->getFunctionType(), F->getAttributes(),
Arm64ECThunkType::GuestExit, NullThunkName, Arm64Ty, X64Ty,
ArgTranslations);
- auto MangledName = getArm64ECMangledFunctionName(F->getName().str());
+ auto MangledName = getArm64ECMangledFunctionName(*F);
assert(MangledName && "Can't guest exit to function that's already native");
std::string ThunkName = *MangledName;
if (ThunkName[0] == '?' && ThunkName.find("@") != std::string::npos) {
@@ -790,7 +798,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
if (!F)
continue;
if (std::optional<std::string> MangledName =
- getArm64ECMangledFunctionName(A.getName().str())) {
+ getArm64ECMangledFunctionName(A)) {
F->addMetadata("arm64ec_unmangled_name",
*MDNode::get(M->getContext(),
MDString::get(M->getContext(), A.getName())));
@@ -807,7 +815,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
cast<GlobalValue>(F.getPersonalityFn()->stripPointerCasts());
if (PersFn->getValueType() && PersFn->getValueType()->isFunctionTy()) {
if (std::optional<std::string> MangledName =
- getArm64ECMangledFunctionName(PersFn->getName().str())) {
+ getArm64ECMangledFunctionName(*PersFn)) {
PersFn->setName(MangledName.value());
}
}
@@ -821,7 +829,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
// Rename hybrid patchable functions and change callers to use a global
// alias instead.
if (std::optional<std::string> MangledName =
- getArm64ECMangledFunctionName(F.getName().str())) {
+ getArm64ECMangledFunctionName(F)) {
std::string OrigName(F.getName());
F.setName(MangledName.value() + HybridPatchableTargetSuffix);
@@ -926,7 +934,7 @@ bool AArch64Arm64ECCallLowering::processFunction(
// FIXME: Handle functions with weak linkage?
if (!F.hasLocalLinkage() || F.hasAddressTaken()) {
if (std::optional<std::string> MangledName =
- getArm64ECMangledFunctionName(F.getName().str())) {
+ getArm64ECMangledFunctionName(F)) {
F.addMetadata("arm64ec_unmangled_name",
*MDNode::get(M->getContext(),
MDString::get(M->getContext(), F.getName())));
diff --git a/llvm/test/CodeGen/AArch64/arm64ec-empty-name.ll b/llvm/test/CodeGen/AArch64/arm64ec-empty-name.ll
new file mode 100644
index 0000000000000..c7c9ee59e1ccc
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/arm64ec-empty-name.ll
@@ -0,0 +1,15 @@
+; RUN: llc -mtriple=arm64ec-pc-windows-msvc %s -o - | FileCheck %s
+
+; Regression test: Arm64EC needs to look at the first character of a function
+; to decide if it will be mangled like a C or C++ function name, which caused
+; it to crash for empty function names.
+define void @""() {
+ ret void
+}
+
+define void @""() {
+ ret void
+}
+
+; CHECK: "#__unnamed":
+; CHECK: "#__unnamed.1":
More information about the llvm-commits
mailing list