Skip to content

Commit

Permalink
[InstCombine] Make fptrunc combine use intersection of fast math flags (
Browse files Browse the repository at this point in the history
llvm#118808)

These combines involve swapping the fptrunc with its operand, and using
the intersection of fast math flags is the safest option as e.g. if we
have (fptrunc (fneg ninf x)) then (fneg ninf (fptrunc x)) will not be
correct as if x is a not within the range of the destination type the
result of (fptrunc x) will be inf.
  • Loading branch information
john-brawn-arm authored Dec 6, 2024
1 parent 76db473 commit 99dc396
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 5 deletions.
11 changes: 6 additions & 5 deletions llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1847,15 +1847,16 @@ Instruction *InstCombinerImpl::visitFPTrunc(FPTruncInst &FPT) {
Value *X;
Instruction *Op = dyn_cast<Instruction>(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<FPMathOperator>(Op))
Builder.setFastMathFlags(Op->getFastMathFlags());
FastMathFlags FMF = FPT.getFastMathFlags();
if (auto *FPMO = dyn_cast<FPMathOperator>(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
Expand Down
88 changes: 88 additions & 0 deletions llvm/test/Transforms/InstCombine/fpcast.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:%.*]]
Expand Down
24 changes: 24 additions & 0 deletions llvm/test/Transforms/InstCombine/fptrunc.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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) {
Expand Down

0 comments on commit 99dc396

Please sign in to comment.