[llvm] [Windows] Allow legalizing LDEXP_F128 and FREXP_F128 with libcalls (PR #148326)

Trevor Gross via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 12 14:35:16 PDT 2025


https://github.com/tgross35 updated https://github.com/llvm/llvm-project/pull/148326

>From fd1fb1b259831245b33d75b1d51a840be47a2afe Mon Sep 17 00:00:00 2001
From: Trevor Gross <tmgross at umich.edu>
Date: Fri, 11 Jul 2025 21:47:34 -0400
Subject: [PATCH 1/2] [Windows] Allow legalizing LDEXP_F128 and FREXP_F128 with
 libcalls

Attempting to use `llvm.ldexp.f128` or `llvm.frexp.f128` on Windows
platforms results in a legalization failure. The needed functions
`ldexpf128` and `frexpf128` aren't available on Windows, but it should
be a failure to link that can be solved by adding a `f128` library is
preferable to crashing.

Note that due to [44744] this lowering actually incorrectly produces
`ldexpl` and `frexpl` symbols, which aren't correct for `_Float128` on
Windows. This will be fixed separately.

This patch also adds `{frexp,ldexp}.f128` tests on a couple
architectures that were missing them, unrelated to the Windows-only
change here.

[44744]: https://github.com/llvm/llvm-project/issues/44744

Fixes: https://github.com/llvm/llvm-project/issues/144006
---
 llvm/lib/IR/RuntimeLibcalls.cpp         |   2 -
 llvm/test/CodeGen/AArch64/ldexp.ll      |  13 +++
 llvm/test/CodeGen/AArch64/llvm.frexp.ll |  67 ++++++++++++
 llvm/test/CodeGen/ARM/ldexp.ll          |   8 ++
 llvm/test/CodeGen/ARM/llvm.frexp.ll     |  53 ++++++++++
 llvm/test/CodeGen/Mips/ldexp.ll         |  14 +++
 llvm/test/CodeGen/X86/ldexp.ll          |  57 ++++++++++
 llvm/test/CodeGen/X86/llvm.frexp.ll     | 133 ++++++++++++++++++++++++
 8 files changed, 345 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 64c9415c54d4d..2dbd6b2ef78ea 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -206,12 +206,10 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
   if (TT.isOSWindows() && !TT.isOSCygMing()) {
     setLibcallImpl(RTLIB::LDEXP_F32, RTLIB::Unsupported);
     setLibcallImpl(RTLIB::LDEXP_F80, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::LDEXP_F128, RTLIB::Unsupported);
     setLibcallImpl(RTLIB::LDEXP_PPCF128, RTLIB::Unsupported);
 
     setLibcallImpl(RTLIB::FREXP_F32, RTLIB::Unsupported);
     setLibcallImpl(RTLIB::FREXP_F80, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::FREXP_F128, RTLIB::Unsupported);
     setLibcallImpl(RTLIB::FREXP_PPCF128, RTLIB::Unsupported);
   }
 
diff --git a/llvm/test/CodeGen/AArch64/ldexp.ll b/llvm/test/CodeGen/AArch64/ldexp.ll
index 6019fa1490e3d..75822f512ffdb 100644
--- a/llvm/test/CodeGen/AArch64/ldexp.ll
+++ b/llvm/test/CodeGen/AArch64/ldexp.ll
@@ -147,4 +147,17 @@ entry:
   ret half %0
 }
 
+define fp128 @testExpf128(fp128 %val, i32 %a) {
+; SVE-LABEL: testExpf128:
+; SVE:       // %bb.0: // %entry
+; SVE-NEXT:    b ldexpl
+;
+; WINDOWS-LABEL: testExpf128:
+; WINDOWS:       // %bb.0: // %entry
+; WINDOWS-NEXT:    b ldexpl
+entry:
+  %ldexp = call fp128 @llvm.ldexp.f128.i32(fp128 %val, i32 %a)
+  ret fp128 %ldexp
+}
+
 declare half @llvm.ldexp.f16.i32(half, i32) memory(none)
diff --git a/llvm/test/CodeGen/AArch64/llvm.frexp.ll b/llvm/test/CodeGen/AArch64/llvm.frexp.ll
index 2213aa1429dbd..dca895cfcb976 100644
--- a/llvm/test/CodeGen/AArch64/llvm.frexp.ll
+++ b/llvm/test/CodeGen/AArch64/llvm.frexp.ll
@@ -1131,6 +1131,73 @@ define <2 x i32> @test_frexp_v2f64_v2i32_only_use_exp(<2 x double> %a) nounwind
   ret <2 x i32> %result.1
 }
 
+
+define { fp128, i32 } @test_frexp_f128_i32(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    add x0, sp, #12
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    ldr w0, [sp, #12]
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; WINDOWS-LABEL: test_frexp_f128_i32:
+; WINDOWS:       // %bb.0:
+; WINDOWS-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; WINDOWS-NEXT:    add x0, sp, #12
+; WINDOWS-NEXT:    bl frexpl
+; WINDOWS-NEXT:    ldr w0, [sp, #12]
+; WINDOWS-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; WINDOWS-NEXT:    ret
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  ret { fp128, i32 } %result
+}
+
+define fp128 @test_frexp_f128_i32_only_use_fract(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32_only_use_fract:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    add x0, sp, #12
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; WINDOWS-LABEL: test_frexp_f128_i32_only_use_fract:
+; WINDOWS:       // %bb.0:
+; WINDOWS-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; WINDOWS-NEXT:    add x0, sp, #12
+; WINDOWS-NEXT:    bl frexpl
+; WINDOWS-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; WINDOWS-NEXT:    ret
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 0
+  ret fp128 %result.0
+}
+
+define i32 @test_frexp_f128_i32_only_use_exp(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32_only_use_exp:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    add x0, sp, #12
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    ldr w0, [sp, #12]
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; WINDOWS-LABEL: test_frexp_f128_i32_only_use_exp:
+; WINDOWS:       // %bb.0:
+; WINDOWS-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; WINDOWS-NEXT:    add x0, sp, #12
+; WINDOWS-NEXT:    bl frexpl
+; WINDOWS-NEXT:    ldr w0, [sp, #12]
+; WINDOWS-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; WINDOWS-NEXT:    ret
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 1
+  ret i32 %result.0
+}
+
 declare { float, i32 } @llvm.frexp.f32.i32(float) #0
 declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>) #0
 declare { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float>) #0
diff --git a/llvm/test/CodeGen/ARM/ldexp.ll b/llvm/test/CodeGen/ARM/ldexp.ll
index cdf91eb902e05..1c2c35eaf4f37 100644
--- a/llvm/test/CodeGen/ARM/ldexp.ll
+++ b/llvm/test/CodeGen/ARM/ldexp.ll
@@ -55,4 +55,12 @@ entry:
   ret half %0
 }
 
+define fp128 @testExpf128(fp128 %val, i32 %a) {
+; LINUX: bl ldexpl
+; WINDOWS: bl ldexpl
+entry:
+  %0 = tail call fp128 @llvm.ldexp.f128.i32(fp128 %val, i32 %a)
+  ret fp128 %0
+}
+
 declare half @llvm.ldexp.f16.i32(half, i32) memory(none)
diff --git a/llvm/test/CodeGen/ARM/llvm.frexp.ll b/llvm/test/CodeGen/ARM/llvm.frexp.ll
index 43edb17fe1081..376426d701b3e 100644
--- a/llvm/test/CodeGen/ARM/llvm.frexp.ll
+++ b/llvm/test/CodeGen/ARM/llvm.frexp.ll
@@ -544,6 +544,59 @@ define <2 x i32> @test_frexp_v2f64_v2i32_only_use_exp(<2 x double> %a) {
   ret <2 x i32> %result.1
 }
 
+define { fp128, i32 } @test_frexp_f128_i32(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    push {r4, lr}
+; CHECK-NEXT:    sub sp, #8
+; CHECK-NEXT:    mov r12, r3
+; CHECK-NEXT:    ldr r3, [sp, #16]
+; CHECK-NEXT:    mov r4, r0
+; CHECK-NEXT:    add r0, sp, #4
+; CHECK-NEXT:    str r0, [sp]
+; CHECK-NEXT:    mov r0, r1
+; CHECK-NEXT:    mov r1, r2
+; CHECK-NEXT:    mov r2, r12
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    ldr.w r12, [sp, #4]
+; CHECK-NEXT:    stm.w r4, {r0, r1, r2, r3, r12}
+; CHECK-NEXT:    add sp, #8
+; CHECK-NEXT:    pop {r4, pc}
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  ret { fp128, i32 } %result
+}
+
+define fp128 @test_frexp_f128_i32_only_use_fract(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32_only_use_fract:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    push {r7, lr}
+; CHECK-NEXT:    sub sp, #8
+; CHECK-NEXT:    add.w r12, sp, #4
+; CHECK-NEXT:    str.w r12, [sp]
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    add sp, #8
+; CHECK-NEXT:    pop {r7, pc}
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 0
+  ret fp128 %result.0
+}
+
+define i32 @test_frexp_f128_i32_only_use_exp(fp128 %a) nounwind {
+; CHECK-LABEL: test_frexp_f128_i32_only_use_exp:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    push {r7, lr}
+; CHECK-NEXT:    sub sp, #8
+; CHECK-NEXT:    add.w r12, sp, #4
+; CHECK-NEXT:    str.w r12, [sp]
+; CHECK-NEXT:    bl frexpl
+; CHECK-NEXT:    ldr r0, [sp, #4]
+; CHECK-NEXT:    add sp, #8
+; CHECK-NEXT:    pop {r7, pc}
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 1
+  ret i32 %result.0
+}
+
 declare { float, i32 } @llvm.frexp.f32.i32(float) #0
 declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>) #0
 declare { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float>) #0
diff --git a/llvm/test/CodeGen/Mips/ldexp.ll b/llvm/test/CodeGen/Mips/ldexp.ll
index d321cdb828e43..ca509057ead80 100644
--- a/llvm/test/CodeGen/Mips/ldexp.ll
+++ b/llvm/test/CodeGen/Mips/ldexp.ll
@@ -141,6 +141,20 @@ define x86_fp80 @ldexp_f80(x86_fp80 %arg0, i32 %arg1) nounwind {
   ret x86_fp80 %ldexp
 }
 
+define fp128 @ldexp_f128(fp128 %arg0, i32 %arg1) nounwind {
+; SOFT-LABEL: ldexp_f128:
+; SOFT:       # %bb.0:
+; SOFT-NEXT:    addiu $sp, $sp, -32
+; SOFT-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; SOFT-NEXT:    lw $1, 48($sp)
+; SOFT-NEXT:    jal ldexpl
+; SOFT-NEXT:    sw $1, 16($sp)
+; SOFT-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; SOFT-NEXT:    jr $ra
+; SOFT-NEXT:    addiu $sp, $sp, 32
+  %ldexp = call fp128 @llvm.ldexp.f128.i32(fp128 %arg0, i32 %arg1)
+  ret fp128 %ldexp
+}
 
 declare double @llvm.ldexp.f64.i32(double, i32) #0
 declare float @llvm.ldexp.f32.i32(float, i32) #0
diff --git a/llvm/test/CodeGen/X86/ldexp.ll b/llvm/test/CodeGen/X86/ldexp.ll
index 59ec7bfcaa910..c2126250deeca 100644
--- a/llvm/test/CodeGen/X86/ldexp.ll
+++ b/llvm/test/CodeGen/X86/ldexp.ll
@@ -557,6 +557,63 @@ define half @ldexp_f16(half %arg0, i32 %arg1) nounwind {
   ret half %ldexp
 }
 
+define fp128 @ldexp_f128(fp128 %arg0, i32 %arg1) nounwind {
+; X64-LABEL: ldexp_f128:
+; X64:       # %bb.0:
+; X64-NEXT:    jmp ldexpl at PLT # TAILCALL
+;
+; WIN64-LABEL: ldexp_f128:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $56, %rsp
+; WIN64-NEXT:    .seh_stackalloc 56
+; WIN64-NEXT:    .seh_endprologue
+; WIN64-NEXT:    movaps (%rcx), %xmm0
+; WIN64-NEXT:    movaps %xmm0, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    callq ldexpl
+; WIN64-NEXT:    nop
+; WIN64-NEXT:    .seh_startepilogue
+; WIN64-NEXT:    addq $56, %rsp
+; WIN64-NEXT:    .seh_endepilogue
+; WIN64-NEXT:    retq
+; WIN64-NEXT:    .seh_endproc
+;
+; WIN32-LABEL: ldexp_f128:
+; WIN32:       # %bb.0:
+; WIN32-NEXT:    pushl %ebp
+; WIN32-NEXT:    movl %esp, %ebp
+; WIN32-NEXT:    pushl %edi
+; WIN32-NEXT:    pushl %esi
+; WIN32-NEXT:    andl $-16, %esp
+; WIN32-NEXT:    subl $16, %esp
+; WIN32-NEXT:    movl 8(%ebp), %esi
+; WIN32-NEXT:    movl %esp, %eax
+; WIN32-NEXT:    pushl 28(%ebp)
+; WIN32-NEXT:    pushl 24(%ebp)
+; WIN32-NEXT:    pushl 20(%ebp)
+; WIN32-NEXT:    pushl 16(%ebp)
+; WIN32-NEXT:    pushl 12(%ebp)
+; WIN32-NEXT:    pushl %eax
+; WIN32-NEXT:    calll _ldexpl
+; WIN32-NEXT:    addl $24, %esp
+; WIN32-NEXT:    movl (%esp), %eax
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edi
+; WIN32-NEXT:    movl %edi, 12(%esi)
+; WIN32-NEXT:    movl %edx, 8(%esi)
+; WIN32-NEXT:    movl %ecx, 4(%esi)
+; WIN32-NEXT:    movl %eax, (%esi)
+; WIN32-NEXT:    movl %esi, %eax
+; WIN32-NEXT:    leal -8(%ebp), %esp
+; WIN32-NEXT:    popl %esi
+; WIN32-NEXT:    popl %edi
+; WIN32-NEXT:    popl %ebp
+; WIN32-NEXT:    retl
+  %ldexp = call fp128 @llvm.ldexp.f128.i32(fp128 %arg0, i32 %arg1)
+  ret fp128 %ldexp
+}
+
 declare double @llvm.ldexp.f64.i32(double, i32) #0
 declare float @llvm.ldexp.f32.i32(float, i32) #0
 declare <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float>, <2 x i32>) #0
diff --git a/llvm/test/CodeGen/X86/llvm.frexp.ll b/llvm/test/CodeGen/X86/llvm.frexp.ll
index 83840dd85c533..8e94038df4bee 100644
--- a/llvm/test/CodeGen/X86/llvm.frexp.ll
+++ b/llvm/test/CodeGen/X86/llvm.frexp.ll
@@ -600,6 +600,139 @@ define i32 @test_frexp_f64_i32_only_use_exp(double %a) nounwind {
 ;   ret <2 x i32> %result.1
 ; }
 
+define { fp128, i32 } @test_frexp_f128_i32(fp128 %a) nounwind {
+; X64-LABEL: test_frexp_f128_i32:
+; X64:       # %bb.0:
+; X64-NEXT:    pushq %rax
+; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
+; X64-NEXT:    callq frexpl at PLT
+; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
+; X64-NEXT:    popq %rcx
+; X64-NEXT:    retq
+;
+; WIN32-LABEL: test_frexp_f128_i32:
+; WIN32:       # %bb.0:
+; WIN32-NEXT:    pushl %ebp
+; WIN32-NEXT:    movl %esp, %ebp
+; WIN32-NEXT:    pushl %ebx
+; WIN32-NEXT:    pushl %edi
+; WIN32-NEXT:    pushl %esi
+; WIN32-NEXT:    andl $-16, %esp
+; WIN32-NEXT:    subl $48, %esp
+; WIN32-NEXT:    movl 8(%ebp), %esi
+; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
+; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %ecx
+; WIN32-NEXT:    pushl %eax
+; WIN32-NEXT:    pushl 24(%ebp)
+; WIN32-NEXT:    pushl 20(%ebp)
+; WIN32-NEXT:    pushl 16(%ebp)
+; WIN32-NEXT:    pushl 12(%ebp)
+; WIN32-NEXT:    pushl %ecx
+; WIN32-NEXT:    calll _frexpl
+; WIN32-NEXT:    addl $24, %esp
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edi
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ebx
+; WIN32-NEXT:    movl %ebx, 12(%esi)
+; WIN32-NEXT:    movl %edi, 8(%esi)
+; WIN32-NEXT:    movl %edx, 4(%esi)
+; WIN32-NEXT:    movl %ecx, (%esi)
+; WIN32-NEXT:    movl %eax, 16(%esi)
+; WIN32-NEXT:    movl %esi, %eax
+; WIN32-NEXT:    leal -12(%ebp), %esp
+; WIN32-NEXT:    popl %esi
+; WIN32-NEXT:    popl %edi
+; WIN32-NEXT:    popl %ebx
+; WIN32-NEXT:    popl %ebp
+; WIN32-NEXT:    retl
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  ret { fp128, i32 } %result
+}
+
+define fp128 @test_frexp_f128_i32_only_use_fract(fp128 %a) nounwind {
+; X64-LABEL: test_frexp_f128_i32_only_use_fract:
+; X64:       # %bb.0:
+; X64-NEXT:    pushq %rax
+; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
+; X64-NEXT:    callq frexpl at PLT
+; X64-NEXT:    popq %rax
+; X64-NEXT:    retq
+;
+; WIN32-LABEL: test_frexp_f128_i32_only_use_fract:
+; WIN32:       # %bb.0:
+; WIN32-NEXT:    pushl %ebp
+; WIN32-NEXT:    movl %esp, %ebp
+; WIN32-NEXT:    pushl %edi
+; WIN32-NEXT:    pushl %esi
+; WIN32-NEXT:    andl $-16, %esp
+; WIN32-NEXT:    subl $32, %esp
+; WIN32-NEXT:    movl 8(%ebp), %esi
+; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
+; WIN32-NEXT:    movl %esp, %ecx
+; WIN32-NEXT:    pushl %eax
+; WIN32-NEXT:    pushl 24(%ebp)
+; WIN32-NEXT:    pushl 20(%ebp)
+; WIN32-NEXT:    pushl 16(%ebp)
+; WIN32-NEXT:    pushl 12(%ebp)
+; WIN32-NEXT:    pushl %ecx
+; WIN32-NEXT:    calll _frexpl
+; WIN32-NEXT:    addl $24, %esp
+; WIN32-NEXT:    movl (%esp), %eax
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edi
+; WIN32-NEXT:    movl %edi, 12(%esi)
+; WIN32-NEXT:    movl %edx, 8(%esi)
+; WIN32-NEXT:    movl %ecx, 4(%esi)
+; WIN32-NEXT:    movl %eax, (%esi)
+; WIN32-NEXT:    movl %esi, %eax
+; WIN32-NEXT:    leal -8(%ebp), %esp
+; WIN32-NEXT:    popl %esi
+; WIN32-NEXT:    popl %edi
+; WIN32-NEXT:    popl %ebp
+; WIN32-NEXT:    retl
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 0
+  ret fp128 %result.0
+}
+
+define i32 @test_frexp_f128_i32_only_use_exp(fp128 %a) nounwind {
+; X64-LABEL: test_frexp_f128_i32_only_use_exp:
+; X64:       # %bb.0:
+; X64-NEXT:    pushq %rax
+; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
+; X64-NEXT:    callq frexpl at PLT
+; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
+; X64-NEXT:    popq %rcx
+; X64-NEXT:    retq
+;
+; WIN32-LABEL: test_frexp_f128_i32_only_use_exp:
+; WIN32:       # %bb.0:
+; WIN32-NEXT:    pushl %ebp
+; WIN32-NEXT:    movl %esp, %ebp
+; WIN32-NEXT:    andl $-16, %esp
+; WIN32-NEXT:    subl $48, %esp
+; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
+; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %ecx
+; WIN32-NEXT:    pushl %eax
+; WIN32-NEXT:    pushl 20(%ebp)
+; WIN32-NEXT:    pushl 16(%ebp)
+; WIN32-NEXT:    pushl 12(%ebp)
+; WIN32-NEXT:    pushl 8(%ebp)
+; WIN32-NEXT:    pushl %ecx
+; WIN32-NEXT:    calll _frexpl
+; WIN32-NEXT:    addl $24, %esp
+; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; WIN32-NEXT:    movl %ebp, %esp
+; WIN32-NEXT:    popl %ebp
+; WIN32-NEXT:    retl
+  %result = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %a)
+  %result.0 = extractvalue { fp128, i32 } %result, 1
+  ret i32 %result.0
+}
+
 declare { float, i32 } @llvm.frexp.f32.i32(float) #0
 declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>) #0
 declare { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float>) #0

>From 81961ef78f016f18a1c447a13d70da5acdb3dbe8 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tmgross at umich.edu>
Date: Sat, 12 Jul 2025 21:34:58 +0000
Subject: [PATCH 2/2] Update test without cfi

---
 llvm/test/CodeGen/X86/ldexp.ll | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/llvm/test/CodeGen/X86/ldexp.ll b/llvm/test/CodeGen/X86/ldexp.ll
index c2126250deeca..01dd80961ed64 100644
--- a/llvm/test/CodeGen/X86/ldexp.ll
+++ b/llvm/test/CodeGen/X86/ldexp.ll
@@ -565,18 +565,12 @@ define fp128 @ldexp_f128(fp128 %arg0, i32 %arg1) nounwind {
 ; WIN64-LABEL: ldexp_f128:
 ; WIN64:       # %bb.0:
 ; WIN64-NEXT:    subq $56, %rsp
-; WIN64-NEXT:    .seh_stackalloc 56
-; WIN64-NEXT:    .seh_endprologue
 ; WIN64-NEXT:    movaps (%rcx), %xmm0
 ; WIN64-NEXT:    movaps %xmm0, {{[0-9]+}}(%rsp)
 ; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
 ; WIN64-NEXT:    callq ldexpl
-; WIN64-NEXT:    nop
-; WIN64-NEXT:    .seh_startepilogue
 ; WIN64-NEXT:    addq $56, %rsp
-; WIN64-NEXT:    .seh_endepilogue
 ; WIN64-NEXT:    retq
-; WIN64-NEXT:    .seh_endproc
 ;
 ; WIN32-LABEL: ldexp_f128:
 ; WIN32:       # %bb.0:



More information about the llvm-commits mailing list