[llvm] 46b3892 - [ARM]: codegen `llvm.roundeven.v*` (#141786)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 30 11:36:33 PDT 2025
Author: Folkert de Vries
Date: 2025-05-30T19:36:29+01:00
New Revision: 46b389218bf392b87fe9d375e4214a6faf470ec5
URL: https://github.com/llvm/llvm-project/commit/46b389218bf392b87fe9d375e4214a6faf470ec5
DIFF: https://github.com/llvm/llvm-project/commit/46b389218bf392b87fe9d375e4214a6faf470ec5.diff
LOG: [ARM]: codegen `llvm.roundeven.v*` (#141786)
fixes https://github.com/llvm/llvm-project/issues/73588
The aarch64 version of `frintn.ll` notes the intention to auto-upgrade
`frintn` to `roundeven`. I haven't been able to figure out how to make
that happen though (either for arm or aarch64).
The original issue came up in
https://github.com/rust-lang/stdarch/pull/1807
Added:
Modified:
llvm/lib/Target/ARM/ARMISelLowering.cpp
llvm/lib/Target/ARM/ARMInstrVFP.td
llvm/test/CodeGen/ARM/arm32-rounding.ll
llvm/test/CodeGen/ARM/fp16-fullfp16.ll
llvm/test/CodeGen/ARM/fp16-promote.ll
llvm/test/CodeGen/ARM/vrint.ll
llvm/test/CodeGen/Thumb2/bf16-instructions.ll
llvm/test/CodeGen/Thumb2/float-intrinsics-double.ll
llvm/test/CodeGen/Thumb2/float-intrinsics-float.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index b169adc1389d8..360fc21435381 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -905,6 +905,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCEIL, MVT::v2f64, Expand);
setOperationAction(ISD::FTRUNC, MVT::v2f64, Expand);
setOperationAction(ISD::FRINT, MVT::v2f64, Expand);
+ setOperationAction(ISD::FROUNDEVEN, MVT::v2f64, Expand);
setOperationAction(ISD::FNEARBYINT, MVT::v2f64, Expand);
setOperationAction(ISD::FFLOOR, MVT::v2f64, Expand);
setOperationAction(ISD::FMA, MVT::v2f64, Expand);
@@ -927,6 +928,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCEIL, MVT::v4f32, Expand);
setOperationAction(ISD::FTRUNC, MVT::v4f32, Expand);
setOperationAction(ISD::FRINT, MVT::v4f32, Expand);
+ setOperationAction(ISD::FROUNDEVEN, MVT::v4f32, Expand);
setOperationAction(ISD::FNEARBYINT, MVT::v4f32, Expand);
setOperationAction(ISD::FFLOOR, MVT::v4f32, Expand);
@@ -945,6 +947,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCEIL, MVT::v2f32, Expand);
setOperationAction(ISD::FTRUNC, MVT::v2f32, Expand);
setOperationAction(ISD::FRINT, MVT::v2f32, Expand);
+ setOperationAction(ISD::FROUNDEVEN, MVT::v2f32, Expand);
setOperationAction(ISD::FNEARBYINT, MVT::v2f32, Expand);
setOperationAction(ISD::FFLOOR, MVT::v2f32, Expand);
@@ -1087,6 +1090,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCEIL, MVT::f64, Expand);
setOperationAction(ISD::FTRUNC, MVT::f64, Expand);
setOperationAction(ISD::FRINT, MVT::f64, Expand);
+ setOperationAction(ISD::FROUNDEVEN, MVT::f64, Expand);
setOperationAction(ISD::FNEARBYINT, MVT::f64, Expand);
setOperationAction(ISD::FFLOOR, MVT::f64, Expand);
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
@@ -1534,6 +1538,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FTRUNC, MVT::f32, Legal);
setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal);
setOperationAction(ISD::FRINT, MVT::f32, Legal);
+ setOperationAction(ISD::FROUNDEVEN, MVT::f32, Legal);
setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
if (Subtarget->hasNEON()) {
@@ -1550,6 +1555,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FTRUNC, MVT::f64, Legal);
setOperationAction(ISD::FNEARBYINT, MVT::f64, Legal);
setOperationAction(ISD::FRINT, MVT::f64, Legal);
+ setOperationAction(ISD::FROUNDEVEN, MVT::f64, Legal);
setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
}
diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td
index 2ee2cb2fda4a0..1d5c12fabf093 100644
--- a/llvm/lib/Target/ARM/ARMInstrVFP.td
+++ b/llvm/lib/Target/ARM/ARMInstrVFP.td
@@ -1135,8 +1135,13 @@ multiclass vrint_inst_anpm<string opc, bits<2> rm,
Requires<[HasFPARMv8,HasDPVFP]>;
}
+// Match either froundeven or int_arm_neon_vrintn
+def vrintn_or_froundeven : PatFrags<(ops node:$src),
+ [(int_arm_neon_vrintn node:$src),
+ (froundeven node:$src)]>;
+
defm VRINTA : vrint_inst_anpm<"a", 0b00, fround>;
-defm VRINTN : vrint_inst_anpm<"n", 0b01, int_arm_neon_vrintn>;
+defm VRINTN : vrint_inst_anpm<"n", 0b01, vrintn_or_froundeven>;
defm VRINTP : vrint_inst_anpm<"p", 0b10, fceil>;
defm VRINTM : vrint_inst_anpm<"m", 0b11, ffloor>;
diff --git a/llvm/test/CodeGen/ARM/arm32-rounding.ll b/llvm/test/CodeGen/ARM/arm32-rounding.ll
index b0a9f54e42404..cc5b5612f49bb 100644
--- a/llvm/test/CodeGen/ARM/arm32-rounding.ll
+++ b/llvm/test/CodeGen/ARM/arm32-rounding.ll
@@ -104,6 +104,22 @@ entry:
ret double %call
}
+; CHECK-LABEL: test13
+; CHECK: vrintn.f32
+define float @test13(float %a) {
+entry:
+ %round = call float @llvm.roundeven.f32(float %a)
+ ret float %round
+}
+
+; CHECK-LABEL: test14
+; CHECK: vrintn.f64
+define double @test14(double %a) {
+entry:
+ %round = call double @llvm.roundeven.f64(double %a)
+ ret double %round
+}
+
declare float @floorf(float) nounwind readnone
declare double @floor(double) nounwind readnone
declare float @ceilf(float) nounwind readnone
@@ -116,3 +132,5 @@ declare float @nearbyintf(float) nounwind readnone
declare double @nearbyint(double) nounwind readnone
declare float @rintf(float) nounwind readnone
declare double @rint(double) nounwind readnone
+declare float @llvm.roundeven.f32(float)
+declare double @llvm.roundeven.f64(double)
diff --git a/llvm/test/CodeGen/ARM/fp16-fullfp16.ll b/llvm/test/CodeGen/ARM/fp16-fullfp16.ll
index 2656cdbb0347e..200b14bae56ed 100644
--- a/llvm/test/CodeGen/ARM/fp16-fullfp16.ll
+++ b/llvm/test/CodeGen/ARM/fp16-fullfp16.ll
@@ -585,6 +585,18 @@ define void @test_round(ptr %p) {
ret void
}
+define void @test_roundeven(ptr %p) {
+; CHECK-LABEL: test_roundeven:
+; CHECK: vldr.16 s0, [r0]
+; CHECK-NEXT: vrintn.f16 s0, s0
+; CHECK-NEXT: vstr.16 s0, [r0]
+; CHECK-NEXT: bx lr
+ %a = load half, ptr %p, align 2
+ %r = call half @llvm.roundeven.f16(half %a)
+ store half %r, ptr %p
+ ret void
+}
+
define void @test_fmuladd(ptr %p, ptr %q, ptr %r) {
; CHECK-LABEL: test_fmuladd:
; CHECK: vldr.16 s0, [r1]
@@ -623,4 +635,5 @@ declare half @llvm.trunc.f16(half %a)
declare half @llvm.rint.f16(half %a)
declare half @llvm.nearbyint.f16(half %a)
declare half @llvm.round.f16(half %a)
+declare half @llvm.roundeven.f16(half %a)
declare half @llvm.fmuladd.f16(half %a, half %b, half %c)
diff --git a/llvm/test/CodeGen/ARM/fp16-promote.ll b/llvm/test/CodeGen/ARM/fp16-promote.ll
index ae3b8f9920e3b..b4e20c9bf6be9 100644
--- a/llvm/test/CodeGen/ARM/fp16-promote.ll
+++ b/llvm/test/CodeGen/ARM/fp16-promote.ll
@@ -411,6 +411,7 @@ declare half @llvm.trunc.f16(half %a) #0
declare half @llvm.rint.f16(half %a) #0
declare half @llvm.nearbyint.f16(half %a) #0
declare half @llvm.round.f16(half %a) #0
+declare half @llvm.roundeven.f16(half %a) #0
declare half @llvm.fmuladd.f16(half %a, half %b, half %c) #0
; CHECK-ALL-LABEL: test_sqrt:
@@ -811,6 +812,21 @@ define void @test_round(ptr %p) {
ret void
}
+; CHECK-FP16-LABEL: test_roundeven:
+; CHECK-FP16: vcvtb.f32.f16
+; CHECK-FP16: bl roundevenf
+; CHECK-FP16: vcvtb.f16.f32
+; CHECK-LIBCALL-LABEL: test_roundeven:
+; CHECK-LIBCALL: bl __aeabi_h2f
+; CHECK-LIBCALL: bl roundevenf
+; CHECK-LIBCALL: bl __aeabi_f2h
+define void @test_roundeven(ptr %p) {
+ %a = load half, ptr %p, align 2
+ %r = call half @llvm.roundeven.f16(half %a)
+ store half %r, ptr %p
+ ret void
+}
+
; CHECK-FP16-LABEL: test_fmuladd:
; CHECK-FP16: vcvtb.f32.f16
; CHECK-FP16: vcvtb.f32.f16
diff --git a/llvm/test/CodeGen/ARM/vrint.ll b/llvm/test/CodeGen/ARM/vrint.ll
index 908be673295ff..40f806ba55d36 100644
--- a/llvm/test/CodeGen/ARM/vrint.ll
+++ b/llvm/test/CodeGen/ARM/vrint.ll
@@ -1,6 +1,8 @@
; RUN: llc -mtriple=armv8 -mattr=+neon %s -o - | FileCheck %s
declare float @llvm.arm.neon.vrintn.f32(float) nounwind readnone
+declare <2 x float> @llvm.arm.neon.vrintn.v2f32(<2 x float>) nounwind readnone
+declare <4 x float> @llvm.arm.neon.vrintn.v4f32(<4 x float>) nounwind readnone
; CHECK-LABEL: vrintn_f32:
; CHECK: vrintn.f32
@@ -9,3 +11,109 @@ define float @vrintn_f32(ptr %A) nounwind {
%tmp2 = call float @llvm.arm.neon.vrintn.f32(float %tmp1)
ret float %tmp2
}
+
+define <2 x float> @frintn_2s(<2 x float> %A) nounwind {
+; CHECK-LABEL: frintn_2s:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov d16, r0, r1
+; CHECK-NEXT: vrintn.f32 d16, d16
+; CHECK-NEXT: vmov r0, r1, d16
+; CHECK-NEXT: bx lr
+ %tmp3 = call <2 x float> @llvm.arm.neon.vrintn.v2f32(<2 x float> %A)
+ ret <2 x float> %tmp3
+}
+
+define <4 x float> @frintn_4s(<4 x float> %A) nounwind {
+; CHECK-LABEL: frintn_4s:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov d17, r2, r3
+; CHECK-NEXT: vmov d16, r0, r1
+; CHECK-NEXT: vrintn.f32 q8, q8
+; CHECK-NEXT: vmov r0, r1, d16
+; CHECK-NEXT: vmov r2, r3, d17
+; CHECK-NEXT: bx lr
+ %tmp3 = call <4 x float> @llvm.arm.neon.vrintn.v4f32(<4 x float> %A)
+ ret <4 x float> %tmp3
+}
+
+define <4 x half> @roundeven_4h(<4 x half> %A) nounwind {
+; CHECK-LABEL: roundeven_4h:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov s0, r3
+; CHECK-NEXT: vcvtb.f32.f16 s0, s0
+; CHECK-NEXT: vmov s2, r2
+; CHECK-NEXT: vrintn.f32 s0, s0
+; CHECK-NEXT: vcvtb.f32.f16 s2, s2
+; CHECK-NEXT: vrintn.f32 s2, s2
+; CHECK-NEXT: vcvtb.f16.f32 s0, s0
+; CHECK-NEXT: vcvtb.f16.f32 s2, s2
+; CHECK-NEXT: vmov r2, s0
+; CHECK-NEXT: vmov s0, r1
+; CHECK-NEXT: vmov r3, s2
+; CHECK-NEXT: vcvtb.f32.f16 s0, s0
+; CHECK-NEXT: vmov s2, r0
+; CHECK-NEXT: vrintn.f32 s0, s0
+; CHECK-NEXT: vcvtb.f32.f16 s2, s2
+; CHECK-NEXT: vcvtb.f16.f32 s0, s0
+; CHECK-NEXT: vrintn.f32 s2, s2
+; CHECK-NEXT: vmov r0, s0
+; CHECK-NEXT: vcvtb.f16.f32 s2, s2
+; CHECK-NEXT: vmov r1, s2
+; CHECK-NEXT: pkhbt r2, r3, r2, lsl #16
+; CHECK-NEXT: pkhbt r0, r1, r0, lsl #16
+; CHECK-NEXT: vmov d16, r0, r2
+; CHECK-NEXT: vmov.u16 r0, d16[0]
+; CHECK-NEXT: vmov.u16 r1, d16[1]
+; CHECK-NEXT: vmov.u16 r2, d16[2]
+; CHECK-NEXT: vmov.u16 r3, d16[3]
+; CHECK-NEXT: bx lr
+ %tmp3 = call <4 x half> @llvm.roundeven.v4f16(<4 x half> %A)
+ ret <4 x half> %tmp3
+}
+
+define <2 x float> @roundeven_2s(<2 x float> %A) nounwind {
+; CHECK-LABEL: roundeven_2s:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov d0, r0, r1
+; CHECK-NEXT: vrintn.f32 s3, s1
+; CHECK-NEXT: vrintn.f32 s2, s0
+; CHECK-NEXT: vmov r0, r1, d1
+; CHECK-NEXT: bx lr
+ %tmp3 = call <2 x float> @llvm.roundeven.v2f32(<2 x float> %A)
+ ret <2 x float> %tmp3
+}
+
+define <4 x float> @roundeven_4s(<4 x float> %A) nounwind {
+; CHECK-LABEL: roundeven_4s:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov d1, r2, r3
+; CHECK-NEXT: vmov d0, r0, r1
+; CHECK-NEXT: vrintn.f32 s7, s3
+; CHECK-NEXT: vrintn.f32 s6, s2
+; CHECK-NEXT: vrintn.f32 s5, s1
+; CHECK-NEXT: vrintn.f32 s4, s0
+; CHECK-NEXT: vmov r2, r3, d3
+; CHECK-NEXT: vmov r0, r1, d2
+; CHECK-NEXT: bx lr
+ %tmp3 = call <4 x float> @llvm.roundeven.v4f32(<4 x float> %A)
+ ret <4 x float> %tmp3
+}
+
+define <2 x double> @roundeven_2d(<2 x double> %A) nounwind {
+; CHECK-LABEL: roundeven_2d:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vmov d16, r2, r3
+; CHECK-NEXT: vmov d17, r0, r1
+; CHECK-NEXT: vrintn.f64 d16, d16
+; CHECK-NEXT: vrintn.f64 d17, d17
+; CHECK-NEXT: vmov r2, r3, d16
+; CHECK-NEXT: vmov r0, r1, d17
+; CHECK-NEXT: bx lr
+ %tmp3 = call <2 x double> @llvm.roundeven.v2f64(<2 x double> %A)
+ ret <2 x double> %tmp3
+}
+
+declare <4 x half> @llvm.roundeven.v4f16(<4 x half>) nounwind readnone
+declare <2 x float> @llvm.roundeven.v2f32(<2 x float>) nounwind readnone
+declare <4 x float> @llvm.roundeven.v4f32(<4 x float>) nounwind readnone
+declare <2 x double> @llvm.roundeven.v2f64(<2 x double>) nounwind readnone
diff --git a/llvm/test/CodeGen/Thumb2/bf16-instructions.ll b/llvm/test/CodeGen/Thumb2/bf16-instructions.ll
index c93ddca949234..313d237d54b35 100644
--- a/llvm/test/CodeGen/Thumb2/bf16-instructions.ll
+++ b/llvm/test/CodeGen/Thumb2/bf16-instructions.ll
@@ -2373,7 +2373,7 @@ define bfloat @test_roundeven(bfloat %a) {
; CHECK-FP-NEXT: vmov r0, s0
; CHECK-FP-NEXT: lsls r0, r0, #16
; CHECK-FP-NEXT: vmov s0, r0
-; CHECK-FP-NEXT: bl roundevenf
+; CHECK-FP-NEXT: vrintn.f32 s0, s0
; CHECK-FP-NEXT: bl __truncsfbf2
; CHECK-FP-NEXT: vmov.f16 r0, s0
; CHECK-FP-NEXT: vmov s0, r0
diff --git a/llvm/test/CodeGen/Thumb2/float-intrinsics-double.ll b/llvm/test/CodeGen/Thumb2/float-intrinsics-double.ll
index 7f5da36886939..1d954324f1c48 100644
--- a/llvm/test/CodeGen/Thumb2/float-intrinsics-double.ll
+++ b/llvm/test/CodeGen/Thumb2/float-intrinsics-double.ll
@@ -204,6 +204,16 @@ define double @round_d(double %a) {
ret double %1
}
+declare double @llvm.roundeven.f64(double %Val)
+define double @roundeven_d(double %a) {
+; CHECK-LABEL: roundeven_d:
+; SOFT: {{(bl|b)}} roundeven
+; VFP4: b roundeven
+; FP-ARMv8: vrintn.f64
+ %1 = call double @llvm.roundeven.f64(double %a)
+ ret double %1
+}
+
declare double @llvm.fmuladd.f64(double %a, double %b, double %c)
define double @fmuladd_d(double %a, double %b, double %c) {
; CHECK-LABEL: fmuladd_d:
diff --git a/llvm/test/CodeGen/Thumb2/float-intrinsics-float.ll b/llvm/test/CodeGen/Thumb2/float-intrinsics-float.ll
index 94ba9b218a072..864983c4e7701 100644
--- a/llvm/test/CodeGen/Thumb2/float-intrinsics-float.ll
+++ b/llvm/test/CodeGen/Thumb2/float-intrinsics-float.ll
@@ -210,6 +210,16 @@ define float @round_f(float %a) {
ret float %1
}
+declare float @llvm.roundeven.f32(float %Val)
+define float @roundeven_f(float %a) {
+; CHECK-LABEL: roundeven_f:
+; SOFT: bl roundevenf
+; VFP4: b roundevenf
+; FP-ARMv8: vrintn.f32
+ %1 = call float @llvm.roundeven.f32(float %a)
+ ret float %1
+}
+
declare float @llvm.fmuladd.f32(float %a, float %b, float %c)
define float @fmuladd_f(float %a, float %b, float %c) {
; CHECK-LABEL: fmuladd_f:
More information about the llvm-commits
mailing list