[llvm] [ARM] Don't select hard-float fastcc for soft-float subtargets (PR #228394)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 2 04:09:27 PDT 2026
https://github.com/vaibhav-1207 created https://github.com/llvm/llvm-project/pull/228394
Since #221434, ARMBaseTargetMachine::createMachineFunctionInfo reports "calling convention is hard-float, but floating-point registers are unavailable" when useSoftFloat() is set and a function (or a call it makes) has an effective calling convention of ARM_AAPCS_VFP.
getEffectiveCallingConv() still maps fastcc and cxx_fast_tlscc to ARM_AAPCS_VFP whenever the subtarget has FP registers, without checking useSoftFloat(). A +soft-float subtarget that still has FP registers, such as Rust's armv7-unknown-linux-gnueabi target, therefore hits the error as soon as GlobalOpt turns an internal function into fastcc (i.e. at -O1 and above). The diagnostic is a false positive here: with soft-float, FP arguments are softened to integers and passed in core registers anyway.
Only pick ARM_AAPCS_VFP for fastcc/cxx_fast_tlscc when soft-float is not in use. The generated code does not change; the only effect is that the false error goes away.
Fixes #228390
Assisted-by: Jetski (Gemini)
>From 38023734d7fab2a4e01115b74d81b5684f8ba9db Mon Sep 17 00:00:00 2001
From: Vaibhav Shukla <vaibhavshukla at google.com>
Date: Fri, 2 Oct 2026 11:02:59 +0000
Subject: [PATCH] [ARM] Don't select hard-float fastcc for soft-float
subtargets
Since #221434, ARMBaseTargetMachine::createMachineFunctionInfo reports
"calling convention is hard-float, but floating-point registers are
unavailable" when useSoftFloat() is set and a function (or a call it
makes) has an effective calling convention of ARM_AAPCS_VFP.
getEffectiveCallingConv() still maps fastcc and cxx_fast_tlscc to
ARM_AAPCS_VFP whenever the subtarget has FP registers, without checking
useSoftFloat(). A +soft-float subtarget that still has FP registers,
such as Rust's armv7-unknown-linux-gnueabi target, therefore hits the
error as soon as GlobalOpt turns an internal function into fastcc (i.e.
at -O1 and above). The diagnostic is a false positive here: with
soft-float, FP arguments are softened to integers and passed in core
registers anyway.
Only pick ARM_AAPCS_VFP for fastcc/cxx_fast_tlscc when soft-float is not
in use. The generated code does not change; the only effect is that the
false error goes away.
Fixes #228390
Assisted-by: Jetski (Gemini)
---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 2 +-
llvm/test/CodeGen/ARM/eabihf-no-fpregs.ll | 20 +++++
llvm/test/CodeGen/ARM/fastcc-soft-float.ll | 99 ++++++++++++++++++++++
3 files changed, 120 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/ARM/fastcc-soft-float.ll
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 2f4a4b47677c56..185978d0eb9557 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1718,7 +1718,7 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
return CallingConv::Fast;
return CallingConv::ARM_APCS;
} else if (Subtarget->hasFPRegs() && !Subtarget->isThumb1Only() &&
- !isVarArg)
+ !Subtarget->useSoftFloat() && !isVarArg)
return CallingConv::ARM_AAPCS_VFP;
else
return CallingConv::ARM_AAPCS;
diff --git a/llvm/test/CodeGen/ARM/eabihf-no-fpregs.ll b/llvm/test/CodeGen/ARM/eabihf-no-fpregs.ll
index 022a9732173691..89891731ed1cea 100644
--- a/llvm/test/CodeGen/ARM/eabihf-no-fpregs.ll
+++ b/llvm/test/CodeGen/ARM/eabihf-no-fpregs.ll
@@ -2,6 +2,7 @@
; RUN: not llc --mtriple=armv7-none-eabihf --mattr=-fpregs < %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=CHECK,EABIHF --implicit-check-not=error:
; RUN: not llc --mtriple=thumbv6-none-eabihf --mcpu=arm1176jzf-s < %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=CHECK,EABIHF --implicit-check-not=error:
; RUN: not llc --mtriple=armv7-none-eabihf --mattr=+soft-float < %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=CHECK,EABIHF --implicit-check-not=error:
+; RUN: not llc --mtriple=armv7-none-eabi --mattr=+soft-float < %s -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
; EABIHF: error: <unknown>:0:0: in function default_pcs void (): calling convention is hard-float, but floating-point registers are unavailable
define void @default_pcs() {
@@ -21,6 +22,17 @@ define void @variadic(...) {
ret void
}
+; fastcc and cxx_fast_tlscc only use the hard-float calling convention when
+; FP registers are usable, so they are never diagnosed here, including when
+; FP registers exist but +soft-float is used.
+define fastcc void @fast_pcs() {
+ ret void
+}
+
+define cxx_fast_tlscc void @fast_tls_pcs() {
+ ret void
+}
+
; CHECK: error: {{.*}} in function soft_to_hard {{.*}}: 'soft_to_hard' calls 'hard_callee', which expects a hard-float calling convention, but floating-point registers are unavailable
; CHECK: error: {{.*}} 'soft_to_hard' calls 'hard_callee2', which expects a hard-float calling convention, but floating-point registers are unavailable
define arm_aapcscc void @soft_to_hard() {
@@ -35,6 +47,14 @@ define arm_aapcscc void @soft_to_default_hard() {
ret void
}
+define arm_aapcscc void @soft_to_fast() {
+ call fastcc void @fast_callee()
+ call cxx_fast_tlscc void @fast_tls_callee()
+ ret void
+}
+
declare arm_aapcs_vfpcc void @hard_callee()
declare arm_aapcs_vfpcc void @hard_callee2()
declare void @default_callee()
+declare fastcc void @fast_callee()
+declare cxx_fast_tlscc void @fast_tls_callee()
diff --git a/llvm/test/CodeGen/ARM/fastcc-soft-float.ll b/llvm/test/CodeGen/ARM/fastcc-soft-float.ll
new file mode 100644
index 00000000000000..a092c4caefd35e
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/fastcc-soft-float.ll
@@ -0,0 +1,99 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=armv7-unknown-linux-gnueabi < %s | FileCheck %s
+
+; A soft-float subtarget can still have FP registers (e.g. Rust's
+; armv7-unknown-linux-gnueabi target uses "+v7,+thumb2,+soft-float,-neon").
+; fastcc must not be mapped to the hard-float ARM_AAPCS_VFP calling convention
+; in that case: that used to trigger the "calling convention is hard-float, but
+; floating-point registers are unavailable" error. FP arguments are softened
+; and passed in core registers.
+
+define internal fastcc i32 @fast_int(i32 %a, i32 %b) #0 {
+; CHECK-LABEL: fast_int:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: add r0, r0, r1
+; CHECK-NEXT: bx lr
+ %r = add i32 %a, %b
+ ret i32 %r
+}
+
+define internal fastcc float @fast_float(float %a, float %b) #0 {
+; CHECK-LABEL: fast_float:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .save {r11, lr}
+; CHECK-NEXT: push {r11, lr}
+; CHECK-NEXT: bl __aeabi_fadd
+; CHECK-NEXT: pop {r11, pc}
+ %r = fadd float %a, %b
+ ret float %r
+}
+
+define internal fastcc double @fast_double(double %a, double %b) #0 {
+; CHECK-LABEL: fast_double:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .save {r11, lr}
+; CHECK-NEXT: push {r11, lr}
+; CHECK-NEXT: bl __aeabi_dadd
+; CHECK-NEXT: pop {r11, pc}
+ %r = fadd double %a, %b
+ ret double %r
+}
+
+define internal fastcc double @fast_mixed(i32 %i, float %f, double %d) #0 {
+; CHECK-LABEL: fast_mixed:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .save {r4, r5, r6, lr}
+; CHECK-NEXT: push {r4, r5, r6, lr}
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: mov r5, r2
+; CHECK-NEXT: mov r6, r1
+; CHECK-NEXT: bl __aeabi_i2f
+; CHECK-NEXT: mov r1, r6
+; CHECK-NEXT: bl __aeabi_fadd
+; CHECK-NEXT: bl __aeabi_f2d
+; CHECK-NEXT: mov r2, r5
+; CHECK-NEXT: mov r3, r4
+; CHECK-NEXT: bl __aeabi_dmul
+; CHECK-NEXT: pop {r4, r5, r6, pc}
+ %fi = sitofp i32 %i to float
+ %s = fadd float %fi, %f
+ %e = fpext float %s to double
+ %r = fmul double %e, %d
+ ret double %r
+}
+
+define double @caller(i32 %i, float %f, double %d) #0 {
+; CHECK-LABEL: caller:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .save {r4, r5, r6, r7, r11, lr}
+; CHECK-NEXT: push {r4, r5, r6, r7, r11, lr}
+; CHECK-NEXT: mov r6, r1
+; CHECK-NEXT: mov r1, #1
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: mov r5, r2
+; CHECK-NEXT: bl fast_int
+; CHECK-NEXT: mov r7, r0
+; CHECK-NEXT: mov r0, r6
+; CHECK-NEXT: mov r1, #1073741824
+; CHECK-NEXT: bl fast_float
+; CHECK-NEXT: movw r3, #0
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: movt r3, #16392
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: mov r1, r4
+; CHECK-NEXT: mov r2, #0
+; CHECK-NEXT: bl fast_double
+; CHECK-NEXT: mov r2, r0
+; CHECK-NEXT: mov r3, r1
+; CHECK-NEXT: mov r0, r7
+; CHECK-NEXT: mov r1, r6
+; CHECK-NEXT: bl fast_mixed
+; CHECK-NEXT: pop {r4, r5, r6, r7, r11, pc}
+ %a = call fastcc i32 @fast_int(i32 %i, i32 1)
+ %b = call fastcc float @fast_float(float %f, float 2.0)
+ %c = call fastcc double @fast_double(double %d, double 3.0)
+ %m = call fastcc double @fast_mixed(i32 %a, float %b, double %c)
+ ret double %m
+}
+
+attributes #0 = { noinline nounwind "target-features"="+v7,+thumb2,+soft-float,-neon" }
More information about the llvm-commits
mailing list