From dc185ee27551c0ed5a66ca999bab6794c39b30f4 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Sun, 12 Aug 2018 15:48:26 +0000 Subject: [PATCH] [InstCombine] fix/enhance fadd/fsub factorization (X * Z) + (Y * Z) --> (X + Y) * Z (X * Z) - (Y * Z) --> (X - Y) * Z (X / Z) + (Y / Z) --> (X + Y) / Z (X / Z) - (Y / Z) --> (X - Y) / Z The existing code that implemented these folds failed to optimize vectors, and it transformed code with multiple uses when it should not have. llvm-svn: 339519 --- .../Transforms/InstCombine/InstCombineAddSub.cpp | 132 +++++++-------------- .../Transforms/InstCombine/fadd-fsub-factor.ll | 130 +++++++++----------- 2 files changed, 98 insertions(+), 164 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index e339134..d204574 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -186,8 +186,6 @@ namespace { Value *simplifyFAdd(AddendVect& V, unsigned InstrQuota); - Value *performFactorization(Instruction *I); - /// Convert given addend to a Value Value *createAddendVal(const FAddend &A, bool& NeedNeg); @@ -427,89 +425,6 @@ unsigned FAddend::drillAddendDownOneStep return BreakNum; } -// Try to perform following optimization on the input instruction I. Return the -// simplified expression if was successful; otherwise, return 0. -// -// Instruction "I" is Simplified into -// ------------------------------------------------------- -// (x * y) +/- (x * z) x * (y +/- z) -// (y / x) +/- (z / x) (y +/- z) / x -Value *FAddCombine::performFactorization(Instruction *I) { - assert((I->getOpcode() == Instruction::FAdd || - I->getOpcode() == Instruction::FSub) && "Expect add/sub"); - - Instruction *I0 = dyn_cast(I->getOperand(0)); - Instruction *I1 = dyn_cast(I->getOperand(1)); - - if (!I0 || !I1 || I0->getOpcode() != I1->getOpcode()) - return nullptr; - - bool isMpy = false; - if (I0->getOpcode() == Instruction::FMul) - isMpy = true; - else if (I0->getOpcode() != Instruction::FDiv) - return nullptr; - - Value *Opnd0_0 = I0->getOperand(0); - Value *Opnd0_1 = I0->getOperand(1); - Value *Opnd1_0 = I1->getOperand(0); - Value *Opnd1_1 = I1->getOperand(1); - - // Input Instr I Factor AddSub0 AddSub1 - // ---------------------------------------------- - // (x*y) +/- (x*z) x y z - // (y/x) +/- (z/x) x y z - Value *Factor = nullptr; - Value *AddSub0 = nullptr, *AddSub1 = nullptr; - - if (isMpy) { - if (Opnd0_0 == Opnd1_0 || Opnd0_0 == Opnd1_1) - Factor = Opnd0_0; - else if (Opnd0_1 == Opnd1_0 || Opnd0_1 == Opnd1_1) - Factor = Opnd0_1; - - if (Factor) { - AddSub0 = (Factor == Opnd0_0) ? Opnd0_1 : Opnd0_0; - AddSub1 = (Factor == Opnd1_0) ? Opnd1_1 : Opnd1_0; - } - } else if (Opnd0_1 == Opnd1_1) { - Factor = Opnd0_1; - AddSub0 = Opnd0_0; - AddSub1 = Opnd1_0; - } - - if (!Factor) - return nullptr; - - FastMathFlags Flags; - Flags.setFast(); - if (I0) Flags &= I->getFastMathFlags(); - if (I1) Flags &= I->getFastMathFlags(); - - // Create expression "NewAddSub = AddSub0 +/- AddsSub1" - Value *NewAddSub = (I->getOpcode() == Instruction::FAdd) ? - createFAdd(AddSub0, AddSub1) : - createFSub(AddSub0, AddSub1); - if (ConstantFP *CFP = dyn_cast(NewAddSub)) { - const APFloat &F = CFP->getValueAPF(); - if (!F.isNormal()) - return nullptr; - } else if (Instruction *II = dyn_cast(NewAddSub)) - II->setFastMathFlags(Flags); - - if (isMpy) { - Value *RI = createFMul(Factor, NewAddSub); - if (Instruction *II = dyn_cast(RI)) - II->setFastMathFlags(Flags); - return RI; - } - - Value *RI = createFDiv(NewAddSub, Factor); - if (Instruction *II = dyn_cast(RI)) - II->setFastMathFlags(Flags); - return RI; -} - Value *FAddCombine::simplify(Instruction *I) { assert(I->hasAllowReassoc() && I->hasNoSignedZeros() && "Expected 'reassoc'+'nsz' instruction"); @@ -594,8 +509,7 @@ Value *FAddCombine::simplify(Instruction *I) { return R; } - // step 6: Try factorization as the last resort, - return performFactorization(I); + return nullptr; } Value *FAddCombine::simplifyFAdd(AddendVect& Addends, unsigned InstrQuota) { @@ -1391,6 +1305,45 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) { return Changed ? &I : nullptr; } +/// Factor a common operand out of fadd/fsub of fmul/fdiv. +static Instruction *factorizeFAddFSub(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + assert((I.getOpcode() == Instruction::FAdd || + I.getOpcode() == Instruction::FSub) && "Expecting fadd/fsub"); + assert(I.hasAllowReassoc() && I.hasNoSignedZeros() && + "FP factorization requires FMF"); + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + Value *X, *Y, *Z; + bool IsFMul; + if ((match(Op0, m_OneUse(m_FMul(m_Value(X), m_Value(Z)))) && + match(Op1, m_OneUse(m_c_FMul(m_Value(Y), m_Specific(Z))))) || + (match(Op0, m_OneUse(m_FMul(m_Value(Z), m_Value(X)))) && + match(Op1, m_OneUse(m_c_FMul(m_Value(Y), m_Specific(Z)))))) + IsFMul = true; + else if (match(Op0, m_OneUse(m_FDiv(m_Value(X), m_Value(Z)))) && + match(Op1, m_OneUse(m_FDiv(m_Value(Y), m_Specific(Z))))) + IsFMul = false; + else + return nullptr; + + // (X * Z) + (Y * Z) --> (X + Y) * Z + // (X * Z) - (Y * Z) --> (X - Y) * Z + // (X / Z) + (Y / Z) --> (X + Y) / Z + // (X / Z) - (Y / Z) --> (X - Y) / Z + bool IsFAdd = I.getOpcode() == Instruction::FAdd; + Value *XY = IsFAdd ? Builder.CreateFAddFMF(X, Y, &I) + : Builder.CreateFSubFMF(X, Y, &I); + + // Bail out if we just created a denormal constant. + // TODO: This is copied from a previous implementation. Is it necessary? + const APFloat *C; + if (match(XY, m_APFloat(C)) && !C->isNormal()) + return nullptr; + + return IsFMul ? BinaryOperator::CreateFMulFMF(XY, Z, &I) + : BinaryOperator::CreateFDivFMF(XY, Z, &I); +} + Instruction *InstCombiner::visitFAdd(BinaryOperator &I) { if (Value *V = SimplifyFAddInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), @@ -1478,6 +1431,8 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) { return replaceInstUsesWith(I, V); if (I.hasAllowReassoc() && I.hasNoSignedZeros()) { + if (Instruction *F = factorizeFAddFSub(I, Builder)) + return F; if (Value *V = FAddCombine(Builder).simplify(&I)) return replaceInstUsesWith(I, V); } @@ -1925,6 +1880,9 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) { return BinaryOperator::CreateFMulFMF(Op0, OneSubC, &I); } + if (Instruction *F = factorizeFAddFSub(I, Builder)) + return F; + // TODO: This performs reassociative folds for FP ops. Some fraction of the // functionality has been subsumed by simple pattern matching here and in // InstSimplify. We should let a dedicated reassociation pass handle more diff --git a/llvm/test/Transforms/InstCombine/fadd-fsub-factor.ll b/llvm/test/Transforms/InstCombine/fadd-fsub-factor.ll index da9afca..09104e5 100644 --- a/llvm/test/Transforms/InstCombine/fadd-fsub-factor.ll +++ b/llvm/test/Transforms/InstCombine/fadd-fsub-factor.ll @@ -16,8 +16,8 @@ define float @fmul_fadd(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fadd( ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %x, %z %t2 = fmul float %y, %z @@ -25,14 +25,12 @@ define float @fmul_fadd(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Verify vector types and commuted operands. define <2 x float> @fmul_fadd_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) { ; CHECK-LABEL: @fmul_fadd_commute1_vec( -; CHECK-NEXT: [[T1:%.*]] = fmul <2 x float> [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fmul <2 x float> [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz <2 x float> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %t1 = fmul <2 x float> %z, %x @@ -41,14 +39,12 @@ define <2 x float> @fmul_fadd_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x ret <2 x float> %r } -; FIXME: ; Verify vector types, commuted operands, FMF propagation. define <2 x float> @fmul_fadd_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) { ; CHECK-LABEL: @fmul_fadd_commute2_vec( -; CHECK-NEXT: [[T1:%.*]] = fmul fast <2 x float> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fmul nnan <2 x float> [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fadd reassoc ninf nsz <2 x float> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %t1 = fmul fast <2 x float> %x, %z @@ -62,8 +58,8 @@ define <2 x float> @fmul_fadd_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x define double @fmul_fadd_commute3(double %x, double %y, double %z) { ; CHECK-LABEL: @fmul_fadd_commute3( ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nnan nsz double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret double [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret double [[R]] ; %t1 = fmul double %z, %x %t2 = fmul fast double %y, %z @@ -88,16 +84,15 @@ define float @fmul_fadd_not_enough_FMF(float %x, float %y, float %z) { declare void @use(float) -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fadd_uses1(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fadd_uses1( ; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[X]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %z, %x %t2 = fmul float %y, %z @@ -106,16 +101,15 @@ define float @fmul_fadd_uses1(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fadd_uses2(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fadd_uses2( -; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]] +; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %z, %x %t2 = fmul float %z, %y @@ -124,18 +118,16 @@ define float @fmul_fadd_uses2(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fadd_uses3(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fadd_uses3( ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]] ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[X]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %x, %z %t2 = fmul float %z, %y @@ -150,8 +142,8 @@ define float @fmul_fadd_uses3(float %x, float %y, float %z) { define half @fmul_fsub(half %x, half %y, half %z) { ; CHECK-LABEL: @fmul_fsub( ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz half [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz half [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret half [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz half [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret half [[R]] ; %t1 = fmul half %x, %z %t2 = fmul half %y, %z @@ -159,14 +151,12 @@ define half @fmul_fsub(half %x, half %y, half %z) { ret half %r } -; FIXME: ; Verify vector types and commuted operands. define <2 x float> @fmul_fsub_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) { ; CHECK-LABEL: @fmul_fsub_commute1_vec( -; CHECK-NEXT: [[T1:%.*]] = fmul <2 x float> [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fmul <2 x float> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz <2 x float> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %t1 = fmul <2 x float> %z, %x @@ -175,14 +165,12 @@ define <2 x float> @fmul_fsub_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x ret <2 x float> %r } -; FIXME: ; Verify vector types, commuted operands, FMF propagation. define <2 x float> @fmul_fsub_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) { ; CHECK-LABEL: @fmul_fsub_commute2_vec( -; CHECK-NEXT: [[T1:%.*]] = fmul fast <2 x float> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fmul nnan <2 x float> [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fsub reassoc ninf nsz <2 x float> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %t1 = fmul fast <2 x float> %x, %z @@ -196,8 +184,8 @@ define <2 x float> @fmul_fsub_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x define double @fmul_fsub_commute3(double %x, double %y, double %z) { ; CHECK-LABEL: @fmul_fsub_commute3( ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nnan nsz double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret double [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret double [[R]] ; %t1 = fmul double %z, %x %t2 = fmul fast double %z, %y @@ -220,16 +208,15 @@ define float @fmul_fsub_not_enough_FMF(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fsub_uses1(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fsub_uses1( ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %x, %z %t2 = fmul float %y, %z @@ -238,16 +225,15 @@ define float @fmul_fsub_uses1(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fsub_uses2(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fsub_uses2( -; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X:%.*]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]] +; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %z, %x %t2 = fmul float %z, %y @@ -256,18 +242,16 @@ define float @fmul_fsub_uses2(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fmul_fsub_uses3(float %x, float %y, float %z) { ; CHECK-LABEL: @fmul_fsub_uses3( ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]] ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fmul float %x, %z %t2 = fmul float %y, %z @@ -282,8 +266,8 @@ define float @fmul_fsub_uses3(float %x, float %y, float %z) { define double @fdiv_fadd(double %x, double %y, double %z) { ; CHECK-LABEL: @fdiv_fadd( ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fdiv reassoc nsz double [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret double [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz double [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret double [[R]] ; %t1 = fdiv double %x, %z %t2 = fdiv double %y, %z @@ -294,8 +278,8 @@ define double @fdiv_fadd(double %x, double %y, double %z) { define float @fdiv_fsub(float %x, float %y, float %z) { ; CHECK-LABEL: @fdiv_fsub( ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fdiv reassoc nsz float [[TMP1]], [[Z:%.*]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz float [[TMP1]], [[Z:%.*]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fdiv fast float %x, %z %t2 = fdiv nnan float %y, %z @@ -303,14 +287,12 @@ define float @fdiv_fsub(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Verify vector types. define <2 x double> @fdiv_fadd_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) { ; CHECK-LABEL: @fdiv_fadd_vec( -; CHECK-NEXT: [[T1:%.*]] = fdiv fast <2 x double> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fdiv <2 x double> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz <2 x double> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz <2 x double> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz <2 x double> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x double> [[R]] ; %t1 = fdiv fast <2 x double> %x, %z @@ -319,14 +301,12 @@ define <2 x double> @fdiv_fadd_vec(<2 x double> %x, <2 x double> %y, <2 x double ret <2 x double> %r } -; FIXME: ; Verify vector types. define <2 x float> @fdiv_fsub_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) { ; CHECK-LABEL: @fdiv_fsub_vec( -; CHECK-NEXT: [[T1:%.*]] = fdiv <2 x float> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[T2:%.*]] = fdiv nnan <2 x float> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz <2 x float> [[T1]], [[T2]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]] ; CHECK-NEXT: ret <2 x float> [[R]] ; %t1 = fdiv <2 x float> %x, %z @@ -395,16 +375,15 @@ define float @fdiv_fsub_not_enough_FMF(float %x, float %y, float %z) { ret float %t3 } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fdiv_fadd_uses1(float %x, float %y, float %z) { ; CHECK-LABEL: @fdiv_fadd_uses1( ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fadd fast float [[X]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = fdiv fast float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fadd fast float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fdiv fast float %x, %z %t2 = fdiv fast float %y, %z @@ -413,16 +392,15 @@ define float @fdiv_fadd_uses1(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fdiv_fsub_uses2(float %x, float %y, float %z) { ; CHECK-LABEL: @fdiv_fsub_uses2( -; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = fsub fast float [[X:%.*]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fdiv fast float [[TMP1]], [[Z]] +; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fdiv fast float %x, %z %t2 = fdiv fast float %y, %z @@ -431,18 +409,16 @@ define float @fdiv_fsub_uses2(float %x, float %y, float %z) { ret float %r } -; FIXME: ; Negative test - extra uses should disable the fold. define float @fdiv_fsub_uses3(float %x, float %y, float %z) { ; CHECK-LABEL: @fdiv_fsub_uses3( ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]] ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[TMP1:%.*]] = fsub fast float [[X]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = fdiv fast float [[TMP1]], [[Z]] +; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]] ; CHECK-NEXT: call void @use(float [[T1]]) ; CHECK-NEXT: call void @use(float [[T2]]) -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fdiv fast float %x, %z %t2 = fdiv fast float %y, %z @@ -456,8 +432,8 @@ define float @fdiv_fsub_uses3(float %x, float %y, float %z) { define float @fdiv_fadd_not_denorm(float %x) { ; CHECK-LABEL: @fdiv_fadd_not_denorm( -; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast float 0x3818000000000000, [[X:%.*]] -; CHECK-NEXT: ret float [[TMP1]] +; CHECK-NEXT: [[R:%.*]] = fdiv fast float 0x3818000000000000, [[X:%.*]] +; CHECK-NEXT: ret float [[R]] ; %t1 = fdiv fast float 0x3810000000000000, %x %t2 = fdiv fast float 0x3800000000000000, %x -- 2.7.4