[llvm] Workaround MSVC Linker Issue when Cross-Compiling for ARM64EC (PR #143659)

Jiachen Yuan via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 10 23:25:52 PDT 2025


https://github.com/JiachenYuan created https://github.com/llvm/llvm-project/pull/143659

This MR presents a temporary workaround for the issue described at https://github.com/llvm/llvm-project/issues/143575. While an [upstream MSVC bug](https://developercommunity.visualstudio.com/t/MSVC-Linker-Issue-When-Cross-Compiling-L/10920141) is reported, it makes sense to apply a workaround in LLVM code to quickly unblock anyone affected.

>From 7b87c4c9313db84642820a9b435a1739ba667159 Mon Sep 17 00:00:00 2001
From: Jiachen Yuan <jiacheny at nvidia.com>
Date: Tue, 10 Jun 2025 22:58:45 -0700
Subject: [PATCH] Workaround MSVC Linker Issue for ARM64EC

---
 llvm/include/llvm/IR/Mangler.h                        | 11 ++++++++++-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp            |  7 ++++---
 .../lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp |  6 ++++--
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/IR/Mangler.h b/llvm/include/llvm/IR/Mangler.h
index e3dfe1eac6189..508d85631edf9 100644
--- a/llvm/include/llvm/IR/Mangler.h
+++ b/llvm/include/llvm/IR/Mangler.h
@@ -26,7 +26,16 @@ class Triple;
 class Twine;
 class raw_ostream;
 
-constexpr std::string_view HybridPatchableTargetSuffix = "$hp_target";
+// TODO: There is a linker failure that is only hit when compiling llvm for
+// arm64ec on windows. While it is not clear what the root cause is, removing
+// the dollar sign from the following variable and re-concatenating the string
+// at its uses is a **temporary** workaround to help eliminate the linker
+// failure. The description and context of the issue is at
+// https://github.com/llvm/llvm-project/issues/143575#issuecomment-2960369418.
+// The upstream MSVC bug is filed at
+// https://developercommunity.visualstudio.com/t/MSVC-Linker-Issue-When-Cross-
+// Compiling-L/10920141.
+constexpr std::string_view HybridPatchableTargetSuffix = "hp_target";
 
 class Mangler {
   /// We need to give global values the same name every time they are mangled.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index e13e92378d4aa..a449b1cd7521f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -4729,6 +4729,8 @@ AsmPrinter::getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
                          codeview::JumpTableEntrySize::Int32);
 }
 
+static const std::string HPSuffix = ("$" + HybridPatchableTargetSuffix).str();
+
 void AsmPrinter::emitCOFFReplaceableFunctionData(Module &M) {
   const Triple &TT = TM.getTargetTriple();
   assert(TT.isOSBinFormatCOFF());
@@ -4749,9 +4751,8 @@ void AsmPrinter::emitCOFFReplaceableFunctionData(Module &M) {
 
       // For hybrid-patchable targets, strip the prefix so that we can mark
       // the real function as replaceable.
-      if (IsTargetArm64EC && Name.ends_with(HybridPatchableTargetSuffix)) {
-        Name = Name.drop_back(HybridPatchableTargetSuffix.size());
-      }
+      if (IsTargetArm64EC && Name.ends_with(HPSuffix))
+        Name = Name.drop_back(HPSuffix.size());
 
       MCSymbol *FuncOverrideSymbol =
           MMI->getContext().getOrCreateSymbol(Name + "_$fo$");
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index 509cbb092705d..af1c4528990b7 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -760,6 +760,8 @@ void AArch64Arm64ECCallLowering::lowerCall(CallBase *CB) {
   CB->setCalledOperand(GuardCheck);
 }
 
+static const std::string HPSuffix = ("$" + HybridPatchableTargetSuffix).str();
+
 bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
   if (!GenerateThunks)
     return false;
@@ -815,7 +817,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
 
     if (!F.hasFnAttribute(Attribute::HybridPatchable) || F.isDeclaration() ||
         F.hasLocalLinkage() ||
-        F.getName().ends_with(HybridPatchableTargetSuffix))
+        F.getName().ends_with(HPSuffix))
       continue;
 
     // Rename hybrid patchable functions and change callers to use a global
@@ -823,7 +825,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
     if (std::optional<std::string> MangledName =
             getArm64ECMangledFunctionName(F.getName().str())) {
       std::string OrigName(F.getName());
-      F.setName(MangledName.value() + HybridPatchableTargetSuffix);
+      F.setName(MangledName.value() + HPSuffix);
 
       // The unmangled symbol is a weak alias to an undefined symbol with the
       // "EXP+" prefix. This undefined symbol is resolved by the linker by



More information about the llvm-commits mailing list