diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 7221c987b9821..62853ca0f72b0 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1847,15 +1847,16 @@ Instruction *InstCombinerImpl::visitFPTrunc(FPTruncInst &FPT) { Value *X; Instruction *Op = dyn_cast(FPT.getOperand(0)); if (Op && Op->hasOneUse()) { - // FIXME: The FMF should propagate from the fptrunc, not the source op. IRBuilder<>::FastMathFlagGuard FMFG(Builder); - if (isa(Op)) - Builder.setFastMathFlags(Op->getFastMathFlags()); + FastMathFlags FMF = FPT.getFastMathFlags(); + if (auto *FPMO = dyn_cast(Op)) + FMF &= FPMO->getFastMathFlags(); + Builder.setFastMathFlags(FMF); if (match(Op, m_FNeg(m_Value(X)))) { Value *InnerTrunc = Builder.CreateFPTrunc(X, Ty); - - return UnaryOperator::CreateFNegFMF(InnerTrunc, Op); + Value *Neg = Builder.CreateFNeg(InnerTrunc); + return replaceInstUsesWith(FPT, Neg); } // If we are truncating a select that has an extended operand, we can diff --git a/llvm/test/Transforms/InstCombine/fpcast.ll b/llvm/test/Transforms/InstCombine/fpcast.ll index 029e513ceafbc..d5290b572aefd 100644 --- a/llvm/test/Transforms/InstCombine/fpcast.ll +++ b/llvm/test/Transforms/InstCombine/fpcast.ll @@ -29,6 +29,17 @@ define half @test3(float %a) { ret half %c } +define half @test3_fast(float %a) { +; CHECK-LABEL: @test3_fast( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half +; CHECK-NEXT: [[C:%.*]] = call half @llvm.fabs.f16(half [[TMP1]]) +; CHECK-NEXT: ret half [[C]] +; + %b = call float @llvm.fabs.f32(float %a) + %c = fptrunc fast float %b to half + ret half %c +} + define half @fneg_fptrunc(float %a) { ; CHECK-LABEL: @fneg_fptrunc( ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half @@ -78,6 +89,28 @@ define half @test4-fast(float %a) { ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast float [[A:%.*]] to half ; CHECK-NEXT: [[C:%.*]] = fneg fast half [[TMP1]] ; CHECK-NEXT: ret half [[C]] +; + %b = fsub fast float -0.0, %a + %c = fptrunc fast float %b to half + ret half %c +} + +define half @test4-mixed-fast-1(float %a) { +; CHECK-LABEL: @test4-mixed-fast-1( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half +; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]] +; CHECK-NEXT: ret half [[C]] +; + %b = fsub float -0.0, %a + %c = fptrunc fast float %b to half + ret half %c +} + +define half @test4-mixed-fast-2(float %a) { +; CHECK-LABEL: @test4-mixed-fast-2( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half +; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]] +; CHECK-NEXT: ret half [[C]] ; %b = fsub fast float -0.0, %a %c = fptrunc float %b to half @@ -89,12 +122,67 @@ define half @test4_unary_fneg-fast(float %a) { ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast float [[A:%.*]] to half ; CHECK-NEXT: [[C:%.*]] = fneg fast half [[TMP1]] ; CHECK-NEXT: ret half [[C]] +; + %b = fneg fast float %a + %c = fptrunc fast float %b to half + ret half %c +} + +define half @test4_unary_fneg-mixed-fast-1(float %a) { +; CHECK-LABEL: @test4_unary_fneg-mixed-fast-1( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half +; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]] +; CHECK-NEXT: ret half [[C]] +; + %b = fneg float %a + %c = fptrunc fast float %b to half + ret half %c +} + +define half @test4_unary_fneg-mixed-fast-2(float %a) { +; CHECK-LABEL: @test4_unary_fneg-mixed-fast-2( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half +; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]] +; CHECK-NEXT: ret half [[C]] ; %b = fneg fast float %a %c = fptrunc float %b to half ret half %c } +define <2 x half> @test4_unary_fneg-vec-fast(<2 x float> %a) { +; CHECK-LABEL: @test4_unary_fneg-vec-fast( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast <2 x float> [[A:%.*]] to <2 x half> +; CHECK-NEXT: [[C:%.*]] = fneg fast <2 x half> [[TMP1]] +; CHECK-NEXT: ret <2 x half> [[C]] +; + %b = fneg fast <2 x float> %a + %c = fptrunc fast <2 x float> %b to <2 x half> + ret <2 x half> %c +} + +define <2 x half> @test4_unary_fneg-vec-mixed-fast-1(<2 x float> %a) { +; CHECK-LABEL: @test4_unary_fneg-vec-mixed-fast-1( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x float> [[A:%.*]] to <2 x half> +; CHECK-NEXT: [[C:%.*]] = fneg <2 x half> [[TMP1]] +; CHECK-NEXT: ret <2 x half> [[C]] +; + %b = fneg <2 x float> %a + %c = fptrunc fast <2 x float> %b to <2 x half> + ret <2 x half> %c +} + +define <2 x half> @test4_unary_fneg-vec-mixed-fast-2(<2 x float> %a) { +; CHECK-LABEL: @test4_unary_fneg-vec-mixed-fast-2( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x float> [[A:%.*]] to <2 x half> +; CHECK-NEXT: [[C:%.*]] = fneg <2 x half> [[TMP1]] +; CHECK-NEXT: ret <2 x half> [[C]] +; + %b = fneg fast <2 x float> %a + %c = fptrunc <2 x float> %b to <2 x half> + ret <2 x half> %c +} + define half @test5(float %a, float %b, float %c) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: [[D:%.*]] = fcmp ogt float [[A:%.*]], [[B:%.*]] diff --git a/llvm/test/Transforms/InstCombine/fptrunc.ll b/llvm/test/Transforms/InstCombine/fptrunc.ll index a4296a326c4bc..0b5d8b3cd06e0 100644 --- a/llvm/test/Transforms/InstCombine/fptrunc.ll +++ b/llvm/test/Transforms/InstCombine/fptrunc.ll @@ -61,6 +61,18 @@ define float @fptrunc_select_true_val(float %x, double %y, i1 %cond) { ret float %r } +define float @fptrunc_fast_select_true_val(float %x, double %y, i1 %cond) { +; CHECK-LABEL: @fptrunc_fast_select_true_val( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast double [[Y:%.*]] to float +; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[COND:%.*]], float [[TMP1]], float [[X:%.*]] +; CHECK-NEXT: ret float [[NARROW_SEL]] +; + %e = fpext float %x to double + %sel = select fast i1 %cond, double %y, double %e + %r = fptrunc fast double %sel to float + ret float %r +} + define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) { ; CHECK-LABEL: @fptrunc_select_false_val( ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[Y:%.*]] to <2 x float> @@ -73,6 +85,18 @@ define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2 ret <2 x float> %r } +define <2 x float> @fptrunc_nnan_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) { +; CHECK-LABEL: @fptrunc_nnan_select_false_val( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc nnan <2 x double> [[Y:%.*]] to <2 x float> +; CHECK-NEXT: [[NARROW_SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x float> [[TMP1]] +; CHECK-NEXT: ret <2 x float> [[NARROW_SEL]] +; + %e = fpext <2 x float> %x to <2 x double> + %sel = select nnan <2 x i1> %cond, <2 x double> %e, <2 x double> %y + %r = fptrunc nnan <2 x double> %sel to <2 x float> + ret <2 x float> %r +} + declare void @use(float) define half @fptrunc_select_true_val_extra_use(half %x, float %y, i1 %cond) {