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);
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;
}
if (Instruction *X = foldFNegIntoConstant(I))
return X;
+ if (Instruction *R = hoistFNegAboveFMulFDiv(I, Builder))
+ return R;
+
Value *X, *Y;
Constant *C;
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);
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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:%.*]]
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]]
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
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
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
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
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