[InstCombine] canonicalize fneg before fmul/fdiv

Reverse the canonicalization of fneg relative to fmul/fdiv. That makes it
easier to implement the transforms (and possibly other fneg transforms) in
1 place because we can always start the pattern match from fneg (either the
legacy binop or the new unop).

There's a secondary practical benefit seen in PR21914 and PR42681:
https://bugs.llvm.org/show_bug.cgi?id=21914
https://bugs.llvm.org/show_bug.cgi?id=42681
...hoisting fneg rather than sinking seems to play nicer with LICM in IR
(although this change may expose analysis holes in the other direction).

1. The instcombine test changes show the expected neutral IR diffs from
   reversing the order.

2. The reassociation tests show that we were missing an optimization
   opportunity to fold away fneg-of-fneg. My reading of IEEE-754 says
   that all of these transforms are allowed (regardless of binop/unop
   fneg version) because:

   "For all other operations [besides copy/abs/negate/copysign], this
   standard does not specify the sign bit of a NaN result."
   In all of these transforms, we always have some other binop
   (fadd/fsub/fmul/fdiv), so we are free to flip the sign bit of a
   potential intermediate NaN operand.
   (If that interpretation is wrong, then we must already have a bug in
   the existing transforms?)

3. The clang tests shouldn't exist as-is, but that's effectively a
   revert of rL367149 (the test broke with an extension of the
   pre-existing fneg canonicalization in rL367146).

Differential Revision: https://reviews.llvm.org/D65399

llvm-svn: 367447
This commit is contained in:
Sanjay Patel 2019-07-31 16:53:22 +00:00
parent b9973f87c6
commit 435cdecdf7
8 changed files with 116 additions and 101 deletions

View File

@ -148,10 +148,11 @@ float _Complex div_float_rc(float a, float _Complex b) {
// AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast float [[CC]], [[DD]]
//
// BC = 0
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float [[D]], %a
// AARCH64-FASTMATH: [[BCmAD:%.*]] = fdiv fast float [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: [[DIV:%.*]] = fdiv fast float [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: fsub fast float -0.000000e+00, [[DIV]]
// AARCH64-FASTMATH: [[NEGA:%.*]] = fsub fast float -0.000000e+00, %a
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float [[D]], [[NEGA]]
//
// AARCH64-FASTMATH: fdiv fast float [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: fdiv fast float [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: ret
return a / b;
}
@ -325,10 +326,11 @@ double _Complex div_double_rc(double a, double _Complex b) {
// AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast double [[CC]], [[DD]]
//
// BC = 0
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double [[D]], %a
// AARCH64-FASTMATH: [[BCmAD:%.*]] = fdiv fast double [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: [[DIV:%.*]] = fdiv fast double [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: fsub fast double -0.000000e+00, [[DIV]]
// AARCH64-FASTMATH: [[NEGA:%.*]] = fsub fast double -0.000000e+00, %a
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double [[D]], [[NEGA]]
//
// AARCH64-FASTMATH: fdiv fast double [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: fdiv fast double [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: ret
return a / b;
}
@ -520,10 +522,11 @@ long double _Complex div_long_double_rc(long double a, long double _Complex b) {
// AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast fp128 [[CC]], [[DD]]
//
// BC = 0
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128 [[D]], %a
// AARCH64-FASTMATH: [[BCmAD:%.*]] = fdiv fast fp128 [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: [[DIV:%.*]] = fdiv fast fp128 [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: fsub fast fp128 0xL00000000000000008000000000000000, [[DIV]]
// AARCH64-FASTMATH: [[NEGA:%.*]] = fsub fast fp128 0xL00000000000000008000000000000000, %a
// AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128 [[D]], [[NEGA]]
//
// AARCH64-FASTMATH: fdiv fast fp128 [[AC]], [[CCpDD]]
// AARCH64-FASTMATH: fdiv fast fp128 [[AD]], [[CCpDD]]
// AARCH64-FASTMATH: ret
return a / b;
}

View File

@ -1900,6 +1900,22 @@ static Instruction *foldFNegIntoConstant(Instruction &I) {
return nullptr;
}
static Instruction *hoistFNegAboveFMulFDiv(Instruction &I,
InstCombiner::BuilderTy &Builder) {
Value *FNeg;
if (!match(&I, m_FNeg(m_Value(FNeg))))
return nullptr;
Value *X, *Y;
if (match(FNeg, m_OneUse(m_FMul(m_Value(X), m_Value(Y)))))
return BinaryOperator::CreateFMulFMF(Builder.CreateFNegFMF(X, &I), Y, &I);
if (match(FNeg, m_OneUse(m_FDiv(m_Value(X), m_Value(Y)))))
return BinaryOperator::CreateFDivFMF(Builder.CreateFNegFMF(X, &I), Y, &I);
return nullptr;
}
Instruction *InstCombiner::visitFNeg(UnaryOperator &I) {
Value *Op = I.getOperand(0);
@ -1917,6 +1933,9 @@ Instruction *InstCombiner::visitFNeg(UnaryOperator &I) {
match(Op, m_OneUse(m_FSub(m_Value(X), m_Value(Y)))))
return BinaryOperator::CreateFSubFMF(Y, X, &I);
if (Instruction *R = hoistFNegAboveFMulFDiv(I, Builder))
return R;
return nullptr;
}
@ -1938,6 +1957,9 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) {
if (Instruction *X = foldFNegIntoConstant(I))
return X;
if (Instruction *R = hoistFNegAboveFMulFDiv(I, Builder))
return R;
Value *X, *Y;
Constant *C;

View File

@ -373,16 +373,6 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
if (match(Op0, m_FNeg(m_Value(X))) && match(Op1, m_Constant(C)))
return BinaryOperator::CreateFMulFMF(X, ConstantExpr::getFNeg(C), &I);
// Sink negation: -X * Y --> -(X * Y)
// But don't transform constant expressions because there's an inverse fold.
if (match(Op0, m_OneUse(m_FNeg(m_Value(X)))) && !isa<ConstantExpr>(Op0))
return BinaryOperator::CreateFNegFMF(Builder.CreateFMulFMF(X, Op1, &I), &I);
// Sink negation: Y * -X --> -(X * Y)
// But don't transform constant expressions because there's an inverse fold.
if (match(Op1, m_OneUse(m_FNeg(m_Value(X)))) && !isa<ConstantExpr>(Op1))
return BinaryOperator::CreateFNegFMF(Builder.CreateFMulFMF(X, Op0, &I), &I);
// fabs(X) * fabs(X) -> X * X
if (Op0 == Op1 && match(Op0, m_Intrinsic<Intrinsic::fabs>(m_Value(X))))
return BinaryOperator::CreateFMulFMF(X, X, &I);
@ -1234,16 +1224,6 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
return &I;
}
// Sink negation: -X / Y --> -(X / Y)
// But don't transform constant expressions because there's an inverse fold.
if (match(Op0, m_OneUse(m_FNeg(m_Value(X)))) && !isa<ConstantExpr>(Op0))
return BinaryOperator::CreateFNegFMF(Builder.CreateFDivFMF(X, Op1, &I), &I);
// Sink negation: Y / -X --> -(Y / X)
// But don't transform constant expressions because there's an inverse fold.
if (match(Op1, m_OneUse(m_FNeg(m_Value(X)))) && !isa<ConstantExpr>(Op1))
return BinaryOperator::CreateFNegFMF(Builder.CreateFDivFMF(Op0, X, &I), &I);
// X / (X * Y) --> 1.0 / Y
// Reassociate to (X / X -> 1.0) is legal when NaNs are not allowed.
// We can ignore the possibility that X is infinity because INF/INF is NaN.

View File

@ -160,15 +160,15 @@ define double @fmul_fneg2_commute(double %x, double %py, double %pz) {
ret double %r
}
; Z + (-X / Y) --> Z - (X / Y)
; Z + (-X / Y) - extra use means we can't transform to fsub without an extra instruction
define float @fdiv_fneg1_extra_use(float %x, float %y, float %pz) {
; CHECK-LABEL: @fdiv_fneg1_extra_use(
; CHECK-NEXT: [[Z:%.*]] = frem float 4.200000e+01, [[PZ:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]]
; CHECK-NEXT: call void @use(float [[DIV]])
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = fadd float [[Z]], [[DIV]]
; CHECK-NEXT: ret float [[R]]
;
%z = frem float 42.0, %pz ; thwart complexity-based canonicalization
@ -179,16 +179,16 @@ define float @fdiv_fneg1_extra_use(float %x, float %y, float %pz) {
ret float %r
}
; Z + (Y / -X) --> Z - (Y / X)
; Z + (Y / -X) - extra use means we can't transform to fsub without an extra instruction
define float @fdiv_fneg2_extra_use(float %x, float %py, float %pz) {
; CHECK-LABEL: @fdiv_fneg2_extra_use(
; CHECK-NEXT: [[Y:%.*]] = frem float -4.200000e+01, [[PY:%.*]]
; CHECK-NEXT: [[Z:%.*]] = frem float 4.200000e+01, [[PZ:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[Y]], [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[Y]], [[NEG]]
; CHECK-NEXT: call void @use(float [[DIV]])
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = fadd float [[Z]], [[DIV]]
; CHECK-NEXT: ret float [[R]]
;
%y = frem float -42.0, %py ; thwart complexity-based canonicalization
@ -200,15 +200,15 @@ define float @fdiv_fneg2_extra_use(float %x, float %py, float %pz) {
ret float %r
}
; Z + (-X * Y) --> Z - (X * Y)
; Z + (-X * Y) - extra use means we can't transform to fsub without an extra instruction
define <2 x float> @fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2 x float> %pz) {
; CHECK-LABEL: @fmul_fneg1_extra_use(
; CHECK-NEXT: [[Z:%.*]] = frem <2 x float> <float 4.200000e+01, float -1.000000e+00>, [[PZ:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]]
; CHECK-NEXT: call void @use_vec(<2 x float> [[MUL]])
; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[Z]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[Z]], [[MUL]]
; CHECK-NEXT: ret <2 x float> [[R]]
;
%z = frem <2 x float> <float 42.0, float -1.0>, %pz ; thwart complexity-based canonicalization
@ -219,16 +219,16 @@ define <2 x float> @fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2 x fl
ret <2 x float> %r
}
; Z + (Y * -X) --> Z - (Y * X)
; Z + (Y * -X) - extra use means we can't transform to fsub without an extra instruction
define float @fmul_fneg2_extra_use(float %x, float %py, float %pz) {
; CHECK-LABEL: @fmul_fneg2_extra_use(
; CHECK-NEXT: [[Y:%.*]] = frem float -4.200000e+01, [[PY:%.*]]
; CHECK-NEXT: [[Z:%.*]] = frem float 4.200000e+01, [[PZ:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[Y]], [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[Y]], [[NEG]]
; CHECK-NEXT: call void @use(float [[MUL]])
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z]], [[TMP1]]
; CHECK-NEXT: [[R:%.*]] = fadd float [[Z]], [[MUL]]
; CHECK-NEXT: ret float [[R]]
;
%y = frem float -42.0, %py ; thwart complexity-based canonicalization

View File

@ -501,8 +501,8 @@ define <2 x float> @div_constant_dividend3(<2 x float> %x) {
define double @fdiv_fneg1(double %x, double %y) {
; CHECK-LABEL: @fdiv_fneg1(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub double -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret double [[DIV]]
;
%neg = fsub double -0.0, %x
@ -512,8 +512,8 @@ define double @fdiv_fneg1(double %x, double %y) {
define double @fdiv_unary_fneg1(double %x, double %y) {
; CHECK-LABEL: @fdiv_unary_fneg1(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub double -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fneg double [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret double [[DIV]]
;
%neg = fneg double %x
@ -523,8 +523,8 @@ define double @fdiv_unary_fneg1(double %x, double %y) {
define <2 x float> @fdiv_fneg2(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fdiv_fneg2(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv <2 x float> [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[Y:%.*]], [[NEG]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fsub <2 x float> <float -0.0, float -0.0>, %x
@ -534,8 +534,8 @@ define <2 x float> @fdiv_fneg2(<2 x float> %x, <2 x float> %y) {
define <2 x float> @fdiv_unary_fneg2(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fdiv_unary_fneg2(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv <2 x float> [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[Y:%.*]], [[NEG]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fneg <2 x float> %x

View File

@ -277,11 +277,11 @@ define float @neg_unary_neg_multi_use(float %x, float %y) {
ret float %mul
}
; (-0.0 - X) * Y => -0.0 - (X * Y)
define float @neg_sink(float %x, float %y) {
; CHECK-LABEL: @neg_sink(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; (-0.0 - X) * Y
define float @neg_mul(float %x, float %y) {
; CHECK-LABEL: @neg_mul(
; CHECK-NEXT: [[SUB:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SUB]], [[Y:%.*]]
; CHECK-NEXT: ret float [[MUL]]
;
%sub = fsub float -0.0, %x
@ -289,10 +289,10 @@ define float @neg_sink(float %x, float %y) {
ret float %mul
}
define float @unary_neg_sink(float %x, float %y) {
; CHECK-LABEL: @unary_neg_sink(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
define float @unary_neg_mul(float %x, float %y) {
; CHECK-LABEL: @unary_neg_mul(
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret float [[MUL]]
;
%neg = fneg float %x
@ -300,10 +300,10 @@ define float @unary_neg_sink(float %x, float %y) {
ret float %mul
}
define <2 x float> @neg_sink_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @neg_sink_vec(
; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
define <2 x float> @neg_mul_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @neg_mul_vec(
; CHECK-NEXT: [[SUB:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[SUB]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[MUL]]
;
%sub = fsub <2 x float> <float -0.0, float -0.0>, %x
@ -311,11 +311,10 @@ define <2 x float> @neg_sink_vec(<2 x float> %x, <2 x float> %y) {
ret <2 x float> %mul
}
; FIXME: Should generate a unary FNeg.
define <2 x float> @unary_neg_sink_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @unary_neg_sink_vec(
; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
define <2 x float> @unary_neg_mul_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @unary_neg_mul_vec(
; CHECK-NEXT: [[SUB:%.*]] = fneg <2 x float> [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[SUB]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[MUL]]
;
%sub = fneg <2 x float> %x
@ -323,10 +322,10 @@ define <2 x float> @unary_neg_sink_vec(<2 x float> %x, <2 x float> %y) {
ret <2 x float> %mul
}
define <2 x float> @neg_sink_vec_undef(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @neg_sink_vec_undef(
; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
define <2 x float> @neg_mul_vec_undef(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @neg_mul_vec_undef(
; CHECK-NEXT: [[SUB:%.*]] = fsub <2 x float> <float undef, float -0.000000e+00>, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[SUB]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[MUL]]
;
%sub = fsub <2 x float> <float undef, float -0.0>, %x
@ -334,11 +333,11 @@ define <2 x float> @neg_sink_vec_undef(<2 x float> %x, <2 x float> %y) {
ret <2 x float> %mul
}
; (0.0 - X) * Y => 0.0 - (X * Y)
; (0.0 - X) * Y
define float @neg_sink_nsz(float %x, float %y) {
; CHECK-LABEL: @neg_sink_nsz(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[SUB1:%.*]] = fsub nsz float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SUB1]], [[Y:%.*]]
; CHECK-NEXT: ret float [[MUL]]
;
%sub1 = fsub nsz float 0.0, %x
@ -346,8 +345,6 @@ define float @neg_sink_nsz(float %x, float %y) {
ret float %mul
}
; "(-0.0 - X) * Y => -0.0 - (X * Y)" is disabled if expression "-0.0 - X"
; has multiple uses.
define float @neg_sink_multi_use(float %x, float %y) {
; CHECK-LABEL: @neg_sink_multi_use(
; CHECK-NEXT: [[SUB1:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
@ -361,8 +358,8 @@ define float @neg_sink_multi_use(float %x, float %y) {
ret float %mul2
}
define float @unary_neg_sink_multi_use(float %x, float %y) {
; CHECK-LABEL: @unary_neg_sink_multi_use(
define float @unary_neg_mul_multi_use(float %x, float %y) {
; CHECK-LABEL: @unary_neg_mul_multi_use(
; CHECK-NEXT: [[SUB1:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SUB1]], [[Y:%.*]]
; CHECK-NEXT: [[MUL2:%.*]] = fmul float [[MUL]], [[SUB1]]

View File

@ -454,10 +454,10 @@ define double @fsub_fmul_fneg2(double %x, double %y, double %z) {
define float @fsub_fdiv_fneg1_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]]
; CHECK-NEXT: call void @use(float [[DIV]])
; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
; CHECK-NEXT: ret float [[R]]
;
%neg = fsub float -0.000000e+00, %x
@ -469,10 +469,10 @@ define float @fsub_fdiv_fneg1_extra_use(float %x, float %y, float %z) {
define float @fsub_fdiv_fneg2_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]]
; CHECK-NEXT: call void @use(float [[DIV]])
; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
; CHECK-NEXT: ret float [[R]]
;
%neg = fsub float -0.000000e+00, %x
@ -486,10 +486,10 @@ declare void @use_vec(<2 x float>)
define <2 x float> @fsub_fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
; CHECK-LABEL: @fsub_fmul_fneg1_extra_use(
; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]]
; CHECK-NEXT: call void @use_vec(<2 x float> [[MUL]])
; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[TMP1]], [[Z:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]]
; CHECK-NEXT: ret <2 x float> [[R]]
;
%neg = fsub <2 x float> <float -0.0, float -0.0>, %x
@ -501,10 +501,10 @@ define <2 x float> @fsub_fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2
define float @fsub_fmul_fneg2_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @fsub_fmul_fneg2_extra_use(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]]
; CHECK-NEXT: call void @use(float [[MUL]])
; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]]
; CHECK-NEXT: ret float [[R]]
;
%neg = fsub float -0.000000e+00, %x

View File

@ -614,12 +614,25 @@ define float @test18_reassoc(float %a, float %b, float %z) {
ret float %f
}
; It is not safe to reassociate unary fneg without nnan.
; fneg of fneg is an identity operation, so no FMF are needed to remove those instructions.
define float @test18_unary_fneg_no_FMF(float %a, float %b, float %z) {
; CHECK-LABEL: @test18_unary_fneg_no_FMF(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[Z:%.*]], 4.000000e+01
; CHECK-NEXT: [[F:%.*]] = fmul float [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret float [[F]]
;
%d = fmul float %z, 4.000000e+01
%c = fneg float %d
%e = fmul float %a, %c
%f = fneg float %e
ret float %f
}
define float @test18_reassoc_unary_fneg(float %a, float %b, float %z) {
; CHECK-LABEL: @test18_reassoc_unary_fneg(
; CHECK-NEXT: [[C:%.*]] = fmul reassoc float [[Z:%.*]], -4.000000e+01
; CHECK-NEXT: [[E:%.*]] = fmul reassoc float [[C]], [[A:%.*]]
; CHECK-NEXT: [[F:%.*]] = fneg reassoc float [[E]]
; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[Z:%.*]], 4.000000e+01
; CHECK-NEXT: [[F:%.*]] = fmul reassoc float [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret float [[F]]
;
%d = fmul reassoc float %z, 4.000000e+01