Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -856,6 +856,18 @@ } } + // ARMv8 implements a lot of rounding-like FP operations. + if (Subtarget->hasV8Ops()) { + static MVT RoundingTypes[] = {MVT::f32, MVT::f64}; + for (const auto Ty : RoundingTypes) { + setOperationAction(ISD::FFLOOR, Ty, Legal); + setOperationAction(ISD::FCEIL, Ty, Legal); + setOperationAction(ISD::FROUND, Ty, Legal); + setOperationAction(ISD::FTRUNC, Ty, Legal); + setOperationAction(ISD::FNEARBYINT, Ty, Legal); + setOperationAction(ISD::FRINT, Ty, Legal); + } + } // We have target-specific dag combine patterns for the following nodes: // ARMISD::VMOVRRD - No need to call setTargetDAGCombine setTargetDAGCombine(ISD::ADD); Index: lib/Target/ARM/ARMInstrVFP.td =================================================================== --- lib/Target/ARM/ARMInstrVFP.td +++ lib/Target/ARM/ARMInstrVFP.td @@ -691,18 +691,20 @@ let D = VFPNeonA8Domain; } -multiclass vrint_inst_zrx { +multiclass vrint_inst_zrx { def S : ASuI<0b11101, 0b11, 0b0110, 0b11, 0, (outs SPR:$Sd), (ins SPR:$Sm), NoItinerary, !strconcat("vrint", opc), ".f32\t$Sd, $Sm", - []>, Requires<[HasFPARMv8]> { + [(set (f32 SPR:$Sd), (node (f32 SPR:$Sm)))]>, + Requires<[HasFPARMv8]> { let Inst{7} = op2; let Inst{16} = op; } def D : ADuI<0b11101, 0b11, 0b0110, 0b11, 0, (outs DPR:$Dd), (ins DPR:$Dm), NoItinerary, !strconcat("vrint", opc), ".f64\t$Dd, $Dm", - []>, Requires<[HasFPARMv8, HasDPVFP]> { + [(set (f64 DPR:$Dd), (node (f64 DPR:$Dm)))]>, + Requires<[HasFPARMv8, HasDPVFP]> { let Inst{7} = op2; let Inst{16} = op; } @@ -715,22 +717,25 @@ Requires<[HasFPARMv8,HasDPVFP]>; } -defm VRINTZ : vrint_inst_zrx<"z", 0, 1>; -defm VRINTR : vrint_inst_zrx<"r", 0, 0>; -defm VRINTX : vrint_inst_zrx<"x", 1, 0>; +defm VRINTZ : vrint_inst_zrx<"z", 0, 1, ftrunc>; +defm VRINTR : vrint_inst_zrx<"r", 0, 0, fnearbyint>; +defm VRINTX : vrint_inst_zrx<"x", 1, 0, frint>; -multiclass vrint_inst_anpm rm> { +multiclass vrint_inst_anpm rm, + SDPatternOperator node = null_frag> { let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in { def S : ASuInp<0b11101, 0b11, 0b1000, 0b01, 0, (outs SPR:$Sd), (ins SPR:$Sm), NoItinerary, !strconcat("vrint", opc, ".f32\t$Sd, $Sm"), - []>, Requires<[HasFPARMv8]> { + [(set (f32 SPR:$Sd), (node (f32 SPR:$Sm)))]>, + Requires<[HasFPARMv8]> { let Inst{17-16} = rm; } def D : ADuInp<0b11101, 0b11, 0b1000, 0b01, 0, (outs DPR:$Dd), (ins DPR:$Dm), NoItinerary, !strconcat("vrint", opc, ".f64\t$Dd, $Dm"), - []>, Requires<[HasFPARMv8, HasDPVFP]> { + [(set (f64 DPR:$Dd), (node (f64 DPR:$Dm)))]>, + Requires<[HasFPARMv8, HasDPVFP]> { let Inst{17-16} = rm; } } @@ -743,10 +748,10 @@ Requires<[HasFPARMv8,HasDPVFP]>; } -defm VRINTA : vrint_inst_anpm<"a", 0b00>; +defm VRINTA : vrint_inst_anpm<"a", 0b00, frnd>; defm VRINTN : vrint_inst_anpm<"n", 0b01>; -defm VRINTP : vrint_inst_anpm<"p", 0b10>; -defm VRINTM : vrint_inst_anpm<"m", 0b11>; +defm VRINTP : vrint_inst_anpm<"p", 0b10, fceil>; +defm VRINTM : vrint_inst_anpm<"m", 0b11, ffloor>; def VSQRTD : ADuI<0b11101, 0b11, 0b0001, 0b11, 0, (outs DPR:$Dd), (ins DPR:$Dm), Index: test/CodeGen/ARM/arm32-rounding.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/arm32-rounding.ll @@ -0,0 +1,110 @@ +; RUN: llc < %s -mtriple=armv8-linux-gnueabihf -mattr=+fp-armv8 | FileCheck %s + +; CHECK-LABEL: test1 +; CHECK: vrintm.f32 +define float @test1(float %a) { +entry: + %call = call float @floorf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test2 +; CHECK: vrintm.f64 +define double @test2(double %a) { +entry: + %call = call double @floor(double %a) nounwind readnone + ret double %call +} + +; CHECK-LABEL: test3 +; CHECK: vrintp.f32 +define float @test3(float %a) { +entry: + %call = call float @ceilf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test4 +; CHECK: vrintp.f64 +define double @test4(double %a) { +entry: + %call = call double @ceil(double %a) nounwind readnone + ret double %call +} + +; CHECK-LABEL: test5 +; CHECK: vrinta.f32 +define float @test5(float %a) { +entry: + %call = call float @roundf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test6 +; CHECK: vrinta.f64 +define double @test6(double %a) { +entry: + %call = call double @round(double %a) nounwind readnone + ret double %call +} + +; CHECK-LABEL: test7 +; CHECK: vrintz.f32 +define float @test7(float %a) { +entry: + %call = call float @truncf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test8 +; CHECK: vrintz.f64 +define double @test8(double %a) { +entry: + %call = call double @trunc(double %a) nounwind readnone + ret double %call +} + +; CHECK-LABEL: test9 +; CHECK: vrintr.f32 +define float @test9(float %a) { +entry: + %call = call float @nearbyintf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test10 +; CHECK: vrintr.f64 +define double @test10(double %a) { +entry: + %call = call double @nearbyint(double %a) nounwind readnone + ret double %call +} + +; CHECK-LABEL: test11 +; CHECK: vrintx.f32 +define float @test11(float %a) { +entry: + %call = call float @rintf(float %a) nounwind readnone + ret float %call +} + +; CHECK-LABEL: test12 +; CHECK: vrintx.f64 +define double @test12(double %a) { +entry: + %call = call double @rint(double %a) nounwind readnone + ret double %call +} + +declare float @floorf(float) nounwind readnone +declare double @floor(double) nounwind readnone +declare float @ceilf(float) nounwind readnone +declare double @ceil(double) nounwind readnone +declare float @roundf(float) nounwind readnone +declare double @round(double) nounwind readnone +declare float @truncf(float) nounwind readnone +declare double @trunc(double) nounwind readnone +declare float @nearbyintf(float) nounwind readnone +declare double @nearbyint(double) nounwind readnone +declare float @rintf(float) nounwind readnone +declare double @rint(double) nounwind readnone