diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 891370e2c76..9363a5e63e9 100644 --- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1964,6 +1964,21 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) { if (match(Op1, m_OneUse(m_FPExt(m_FNeg(m_Value(Y)))))) return BinaryOperator::CreateFAddFMF(Op0, Builder.CreateFPExt(Y, Ty), &I); + // Similar to above, but look through fmul/fdiv of the negated value: + // Op0 - (-X * Y) --> Op0 + (X * Y) + // Op0 - (Y * -X) --> Op0 + (X * Y) + if (match(Op1, m_OneUse(m_c_FMul(m_FNeg(m_Value(X)), m_Value(Y))))) { + Value *FMul = Builder.CreateFMulFMF(X, Y, &I); + return BinaryOperator::CreateFAddFMF(Op0, FMul, &I); + } + // Op0 - (-X / Y) --> Op0 + (X / Y) + // Op0 - (X / -Y) --> Op0 + (X / Y) + if (match(Op1, m_OneUse(m_FDiv(m_FNeg(m_Value(X)), m_Value(Y)))) || + match(Op1, m_OneUse(m_FDiv(m_Value(X), m_FNeg(m_Value(Y)))))) { + Value *FDiv = Builder.CreateFDivFMF(X, Y, &I); + return BinaryOperator::CreateFAddFMF(Op0, FDiv, &I); + } + // Handle special cases for FSub with selects feeding the operation if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1)) return replaceInstUsesWith(I, V); diff --git a/test/Transforms/InstCombine/fsub.ll b/test/Transforms/InstCombine/fsub.ll index 57148cf5642..a08a2944d62 100644 --- a/test/Transforms/InstCombine/fsub.ll +++ b/test/Transforms/InstCombine/fsub.ll @@ -518,8 +518,8 @@ define float @fsub_fdiv_fneg1_extra_use2(float %x, float %y, float %z) { ; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use2( ; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]] ; CHECK-NEXT: call void @use(float [[NEG]]) -; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] +; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret float [[R]] ; %neg = fsub float -0.000000e+00, %x @@ -533,8 +533,8 @@ define float @fsub_fdiv_fneg2_extra_use2(float %x, float %y, float %z) { ; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use2( ; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]] ; CHECK-NEXT: call void @use(float [[NEG]]) -; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]] -; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] +; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[Y:%.*]], [[X]] +; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret float [[R]] ; %neg = fsub float -0.000000e+00, %x @@ -548,8 +548,8 @@ define <2 x float> @fsub_fmul_fneg1_extra_use2(<2 x float> %x, <2 x float> %y, < ; CHECK-LABEL: @fsub_fmul_fneg1_extra_use2( ; CHECK-NEXT: [[NEG:%.*]] = fsub <2 x float> , [[X:%.*]] ; CHECK-NEXT: call void @use_vec(<2 x float> [[NEG]]) -; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %neg = fsub <2 x float> , %x @@ -563,8 +563,8 @@ define float @fsub_fmul_fneg2_extra_use2(float %x, float %y, float %z) { ; CHECK-LABEL: @fsub_fmul_fneg2_extra_use2( ; CHECK-NEXT: [[NEG:%.*]] = fsub float -0.000000e+00, [[X:%.*]] ; CHECK-NEXT: call void @use(float [[NEG]]) -; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret float [[R]] ; %neg = fsub float -0.000000e+00, %x