[llvm] [AArch64] Fix extern_weak function calls on Windows (PR #219202)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 05:44:24 PDT 2026


https://github.com/trcrsired created https://github.com/llvm/llvm-project/pull/219202

On aarch64-windows-gnu/msvc, calls to extern_weak functions were incorrectly going through a GOT/COFFSTUB load (adrp/ldr/blr) instead of using a direct BL instruction. This happened because classifyGlobalFunctionReference delegated to ClassifyGlobalReference for Windows, which returned MO_GOT | MO_COFFSTUB for extern_weak symbols.

The fix adds an early return of MO_NO_FLAG for extern_weak function references on Windows, allowing a direct call. The linker handles extern_weak by resolving to either the real symbol or null, so a direct BL is correct (matching ELF behavior).

issue: #218899

>From 587f4d6540fe810b68f9fa41a6a6570e93fb6f9b Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Thu, 27 Aug 2026 20:18:41 +0800
Subject: [PATCH] [AArch64] Fix extern_weak function calls on Windows

On aarch64-windows-gnu/msvc, calls to extern_weak functions were
incorrectly going through a GOT/COFFSTUB load (adrp/ldr/blr) instead
of using a direct BL instruction. This happened because
classifyGlobalFunctionReference delegated to ClassifyGlobalReference
for Windows, which returned MO_GOT | MO_COFFSTUB for extern_weak
symbols.

The fix adds an early return of MO_NO_FLAG for extern_weak function
references on Windows, allowing a direct call. The linker handles
extern_weak by resolving to either the real symbol or null, so a
direct BL is correct (matching ELF behavior).
---
 llvm/lib/Target/AArch64/AArch64Subtarget.cpp  |  6 +++++
 .../CodeGen/AArch64/windows-extern-weak.ll    | 27 ++++++++++++++++---
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 4fef12ab37ad8..19486ebc36cae 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -503,6 +503,12 @@ unsigned AArch64Subtarget::classifyGlobalFunctionReference(
       }
     }
 
+    // extern_weak function references on Windows should not go through
+    // GOT/COFFSTUB. The linker resolves extern_weak to either the real
+    // symbol or null, so a direct call is correct.
+    if (GV->hasExternalWeakLinkage())
+      return AArch64II::MO_NO_FLAG;
+
     // Use ClassifyGlobalReference for setting MO_DLLIMPORT/MO_COFFSTUB.
     return ClassifyGlobalReference(GV, TM);
   }
diff --git a/llvm/test/CodeGen/AArch64/windows-extern-weak.ll b/llvm/test/CodeGen/AArch64/windows-extern-weak.ll
index ecdb802222935..edc5874c4ff39 100644
--- a/llvm/test/CodeGen/AArch64/windows-extern-weak.ll
+++ b/llvm/test/CodeGen/AArch64/windows-extern-weak.ll
@@ -11,7 +11,7 @@ define void @func() nounwind {
 ; CHECK-NEXT:    ldr x8, [x8, :lo12:.refptr.weakfunc]
 ; CHECK-NEXT:    cbz x8, .LBB0_2
 ; CHECK-NEXT:  // %bb.1:
-; CHECK-NEXT:    blr x8
+; CHECK-NEXT:    bl weakfunc
 ; CHECK-NEXT:  .LBB0_2:
 ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
 ; CHECK-NEXT:    ret
@@ -23,9 +23,7 @@ define void @func() nounwind {
 ; FISEL-NEXT:    ldr x8, [x8, :lo12:.refptr.weakfunc]
 ; FISEL-NEXT:    cbz x8, .LBB0_2
 ; FISEL-NEXT:  // %bb.1:
-; FISEL-NEXT:    adrp x8, .refptr.weakfunc
-; FISEL-NEXT:    ldr x8, [x8, :lo12:.refptr.weakfunc]
-; FISEL-NEXT:    blr x8
+; FISEL-NEXT:    bl weakfunc
 ; FISEL-NEXT:  .LBB0_2:
 ; FISEL-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
 ; FISEL-NEXT:    ret
@@ -41,3 +39,24 @@ define void @func() nounwind {
 }
 
 declare extern_weak void @weakfunc()
+
+define ptr @use() {
+; CHECK-LABEL: use:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK:    bl foo
+; CHECK:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK:    ret
+;
+; FISEL-LABEL: use:
+; FISEL:       // %bb.0: // %entry
+; FISEL-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; FISEL:    bl foo
+; FISEL:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; FISEL:    ret
+entry:
+  %r = call ptr @foo()
+  ret ptr %r
+}
+
+declare extern_weak dso_local ptr @foo()



More information about the llvm-commits mailing list