diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index afbf1b4c55e70..8b65d3eeafa06 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 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: