From 59e8cda65f2a6b52815d14bdb28bf836813d6994 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello 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 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 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 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(F.getPersonalityFn()->stripPointerCasts()); if (PersFn->getValueType() && PersFn->getValueType()->isFunctionTy()) { if (std::optional 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 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 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":