[llvm] [X86] Fix crash when calling through __ptr32 function pointer (PR #209078)

Muhammed Shiyas N via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 6 01:27:05 PDT 2026


https://github.com/Shiyas-N updated https://github.com/llvm/llvm-project/pull/209078

>From 7119e668420c1d2258b454d695d79f44391cb564 Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Sun, 12 Jul 2026 15:13:48 +0000
Subject: [PATCH 1/2] [X86] Fix crash when calling through __ptr32 function
 pointer

Extend the i32 callee to i64 in LowerCall for addrspace 270/271 pointers.
Sign-extend for __sptr, zero-extend for __uptr.
---
 llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 11 ++++
 llvm/test/CodeGen/X86/ptr32-call.ll         | 62 +++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/ptr32-call.ll

diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 819e0a023c1c5..d81c12685560b 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2589,6 +2589,17 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
              Callee.getValueType() == MVT::i32) {
     // Zero-extend the 32-bit Callee address into a 64-bit according to x32 ABI
     Callee = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Callee);
+  } else if (Is64Bit && Callee.getValueType() == MVT::i32) {
+    // On 64-bit targets, extend 32-bit MS __ptr32 callees before the call.
+    // Use sign-extension for __sptr (or when CallBase is null)
+    // and zero-extension for __uptr
+    ISD::NodeType ExtOpc = ISD::SIGN_EXTEND;
+    if (CB) {
+      unsigned AS = CB->getCalledOperand()->getType()->getPointerAddressSpace();
+      if (AS == X86AS::PTR32_UPTR)
+        ExtOpc = ISD::ZERO_EXTEND;
+    }
+    Callee = DAG.getNode(ExtOpc, dl, MVT::i64, Callee);
   } else if (Is64Bit && CB && isCFGuardCall(CB)) {
     // We'll use a specific psuedo instruction for tail calls to control flow
     // guard functions to guarantee the instruction used for the call. To do
diff --git a/llvm/test/CodeGen/X86/ptr32-call.ll b/llvm/test/CodeGen/X86/ptr32-call.ll
new file mode 100644
index 0000000000000..a88d7b8b466a9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/ptr32-call.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+; Tail call through addrspace(270) (__ptr32 __sptr) function pointer.
+; The callee should be sign-extended from i32 to i64.
+define i32 @tailcall_sptr(ptr addrspace(270) %fptr, i32 %arg) {
+; CHECK-LABEL: tailcall_sptr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movslq %edi, %rax
+; CHECK-NEXT:    movl %esi, %edi
+; CHECK-NEXT:    jmpq *%rax # TAILCALL
+entry:
+  %call = tail call addrspace(270) i32 %fptr(i32 %arg)
+  ret i32 %call
+}
+
+; Tail call through addrspace(271) (__ptr32 __uptr) function pointer.
+; The callee should be zero-extended from i32 to i64.
+define i32 @tailcall_uptr(ptr addrspace(271) %fptr, i32 %arg) {
+; CHECK-LABEL: tailcall_uptr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    movl %esi, %edi
+; CHECK-NEXT:    jmpq *%rax # TAILCALL
+entry:
+  %call = tail call addrspace(271) i32 %fptr(i32 %arg)
+  ret i32 %call
+}
+
+; Non-tail call through addrspace(270) (__ptr32 __sptr) function pointer.
+define i32 @call_sptr(ptr addrspace(270) %fptr, i32 %arg) {
+; CHECK-LABEL: call_sptr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    movslq %edi, %rax
+; CHECK-NEXT:    movl %esi, %edi
+; CHECK-NEXT:    callq *%rax
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+entry:
+  %call = call addrspace(270) i32 %fptr(i32 %arg)
+  ret i32 %call
+}
+
+; Non-tail call through addrspace(271) (__ptr32 __uptr) function pointer.
+define i32 @call_uptr(ptr addrspace(271) %fptr, i32 %arg) {
+; CHECK-LABEL: call_uptr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    movl %esi, %edi
+; CHECK-NEXT:    callq *%rax
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+entry:
+  %call = call addrspace(271) i32 %fptr(i32 %arg)
+  ret i32 %call
+}

>From 88db9517a80bbfb33fe37acbd403860804265618 Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Thu, 6 Aug 2026 08:25:38 +0000
Subject: [PATCH 2/2] Address review comments

---
 llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 23 +++++++++++----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index d81c12685560b..83a1cf8b447c3 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2589,17 +2589,6 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
              Callee.getValueType() == MVT::i32) {
     // Zero-extend the 32-bit Callee address into a 64-bit according to x32 ABI
     Callee = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Callee);
-  } else if (Is64Bit && Callee.getValueType() == MVT::i32) {
-    // On 64-bit targets, extend 32-bit MS __ptr32 callees before the call.
-    // Use sign-extension for __sptr (or when CallBase is null)
-    // and zero-extension for __uptr
-    ISD::NodeType ExtOpc = ISD::SIGN_EXTEND;
-    if (CB) {
-      unsigned AS = CB->getCalledOperand()->getType()->getPointerAddressSpace();
-      if (AS == X86AS::PTR32_UPTR)
-        ExtOpc = ISD::ZERO_EXTEND;
-    }
-    Callee = DAG.getNode(ExtOpc, dl, MVT::i64, Callee);
   } else if (Is64Bit && CB && isCFGuardCall(CB)) {
     // We'll use a specific psuedo instruction for tail calls to control flow
     // guard functions to guarantee the instruction used for the call. To do
@@ -2617,6 +2606,18 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
         GA->getGlobal(), dl, GA->getValueType(0), 0, X86II::MO_NO_FLAG);
   }
 
+  if (Is64Bit && !Subtarget.isTarget64BitILP32() &&
+      Callee.getValueType() == MVT::i32) {
+    // On 64-bit targets, extend 32-bit MS __ptr32 callees before the call.
+    // Use sign-extension for __sptr and zero-extension for __uptr.
+    assert(CB && "CallBase expected for 32-bit callee");
+    ISD::NodeType ExtOpc = ISD::SIGN_EXTEND;
+    unsigned AS = CB->getCalledOperand()->getType()->getPointerAddressSpace();
+    if (AS == X86AS::PTR32_UPTR)
+      ExtOpc = ISD::ZERO_EXTEND;
+    Callee = DAG.getNode(ExtOpc, dl, MVT::i64, Callee);
+  }
+
   SmallVector<SDValue, 8> Ops;
 
   if (!IsSibcall && isTailCall && !IsMustTail) {



More information about the llvm-commits mailing list