Index: llvm/include/llvm/Transforms/Scalar/Reassociate.h =================================================================== --- llvm/include/llvm/Transforms/Scalar/Reassociate.h +++ llvm/include/llvm/Transforms/Scalar/Reassociate.h @@ -122,7 +122,9 @@ void EraseInst(Instruction *I); void RecursivelyEraseDeadInsts(Instruction *I, OrderedSet &Insts); void OptimizeInst(Instruction *I); - Instruction *canonicalizeNegConstExpr(Instruction *I); + Instruction *canonicalizeNegFPConstantsForOp(Instruction *I, Instruction *Op, + Value *OtherOp); + Instruction *canonicalizeNegFPConstants(Instruction *I); void BuildPairMap(ReversePostOrderTraversal &RPOT); }; Index: llvm/lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- llvm/lib/Transforms/Scalar/Reassociate.cpp +++ llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -1938,88 +1938,132 @@ MadeChange = true; } -// Canonicalize expressions of the following form: -// x + (-Constant * y) -> x - (Constant * y) -// x - (-Constant * y) -> x + (Constant * y) -Instruction *ReassociatePass::canonicalizeNegConstExpr(Instruction *I) { - if (!I->hasOneUse() || I->getType()->isVectorTy()) - return nullptr; - - // Must be a fmul or fdiv instruction. - unsigned Opcode = I->getOpcode(); - if (Opcode != Instruction::FMul && Opcode != Instruction::FDiv) - return nullptr; - - auto *C0 = dyn_cast(I->getOperand(0)); - auto *C1 = dyn_cast(I->getOperand(1)); - - // Both operands are constant, let it get constant folded away. - if (C0 && C1) - return nullptr; - - ConstantFP *CF = C0 ? C0 : C1; - - // Must have one constant operand. - if (!CF) - return nullptr; +/// Recursively analyze an expression to build a list of instructions that have +/// negative floating-point constant operands. The caller can then transform +/// the list to create positive constants for better reassociation and CSE. +static void getNegatibleInsts(Value *V, + SmallVectorImpl &Candidates) { + // Handle only one-use instructions. Combining negations does not justify + // replicating instructions. + Instruction *I; + if (!match(V, m_OneUse(m_Instruction(I)))) + return; - // Must be a negative ConstantFP. - if (!CF->isNegative()) - return nullptr; + // Handle expressions of multiplications and divisions. + // TODO: This could look through floating-point casts. + const APFloat *C; + switch (I->getOpcode()) { + case Instruction::FMul: + // Not expecting non-canonical code here. Bail out and wait. + if (match(I->getOperand(0), m_Constant())) + break; - // User must be a binary operator with one or more uses. - Instruction *User = I->user_back(); - if (!isa(User) || User->use_empty()) - return nullptr; + if (match(I->getOperand(1), m_APFloat(C)) && C->isNegative()) { + Candidates.push_back(I); + LLVM_DEBUG(dbgs() << "FMul with negative constant: " << *I << '\n'); + } + getNegatibleInsts(I->getOperand(0), Candidates); + getNegatibleInsts(I->getOperand(1), Candidates); + break; + case Instruction::FDiv: + // Not expecting non-canonical code here. Bail out and wait. + if (match(I->getOperand(0), m_Constant()) && + match(I->getOperand(1), m_Constant())) + break; - unsigned UserOpcode = User->getOpcode(); - if (UserOpcode != Instruction::FAdd && UserOpcode != Instruction::FSub) - return nullptr; + if ((match(I->getOperand(0), m_APFloat(C)) && C->isNegative()) || + (match(I->getOperand(1), m_APFloat(C)) && C->isNegative())) { + Candidates.push_back(I); + LLVM_DEBUG(dbgs() << "FDiv with negative constant: " << *I << '\n'); + } + getNegatibleInsts(I->getOperand(0), Candidates); + getNegatibleInsts(I->getOperand(1), Candidates); + break; + default: + break; + } +} - // Subtraction is not commutative. Explicitly, the following transform is - // not valid: (-Constant * y) - x -> x + (Constant * y) - if (!User->isCommutative() && User->getOperand(1) != I) +/// Given an fadd/fsub with an operand that is a one-use instruction +/// (the fadd/fsub), try to change negative floating-point constants into +/// positive constants to increase potential for reassociation and CSE. +Instruction *ReassociatePass::canonicalizeNegFPConstantsForOp(Instruction *I, + Instruction *Op, + Value *OtherOp) { + assert((I->getOpcode() == Instruction::FAdd || + I->getOpcode() == Instruction::FSub) && "Expected fadd/fsub"); + + // Collect instructions with negative FP constants from the subtree that ends + // in Op. + SmallVector Candidates; + getNegatibleInsts(Op, Candidates); + if (Candidates.empty()) return nullptr; // Don't canonicalize x + (-Constant * y) -> x - (Constant * y), if the // resulting subtract will be broken up later. This can get us into an // infinite loop during reassociation. - if (UserOpcode == Instruction::FAdd && ShouldBreakUpSubtract(User)) + bool IsFSub = I->getOpcode() == Instruction::FSub; + bool NeedsSubtract = !IsFSub && Candidates.size() % 2 == 1; + if (NeedsSubtract && ShouldBreakUpSubtract(I)) return nullptr; - // Change the sign of the constant. - APFloat Val = CF->getValueAPF(); - Val.changeSign(); - I->setOperand(C0 ? 0 : 1, ConstantFP::get(CF->getContext(), Val)); - - // Canonicalize I to RHS to simplify the next bit of logic. E.g., - // ((-Const*y) + x) -> (x + (-Const*y)). - if (User->getOperand(0) == I && User->isCommutative()) - cast(User)->swapOperands(); - - Value *Op0 = User->getOperand(0); - Value *Op1 = User->getOperand(1); - BinaryOperator *NI; - switch (UserOpcode) { - default: - llvm_unreachable("Unexpected Opcode!"); - case Instruction::FAdd: - NI = BinaryOperator::CreateFSub(Op0, Op1); - NI->setFastMathFlags(cast(User)->getFastMathFlags()); - break; - case Instruction::FSub: - NI = BinaryOperator::CreateFAdd(Op0, Op1); - NI->setFastMathFlags(cast(User)->getFastMathFlags()); - break; + for (Instruction *Negatible : Candidates) { + const APFloat *C; + if (match(Negatible->getOperand(0), m_APFloat(C))) { + assert(!match(Negatible->getOperand(1), m_Constant()) && + "Expecting only 1 constant operand"); + assert(C->isNegative() && "Expected negative FP constant"); + Negatible->setOperand(0, ConstantFP::get(Negatible->getType(), abs(*C))); + MadeChange = true; + } + if (match(Negatible->getOperand(1), m_APFloat(C))) { + assert(!match(Negatible->getOperand(0), m_Constant()) && + "Expecting only 1 constant operand"); + assert(C->isNegative() && "Expected negative FP constant"); + Negatible->setOperand(1, ConstantFP::get(Negatible->getType(), abs(*C))); + MadeChange = true; + } } + assert(MadeChange == true && "Negative constant candidate was not changed"); - NI->insertBefore(User); - NI->setName(User->getName()); - User->replaceAllUsesWith(NI); - NI->setDebugLoc(I->getDebugLoc()); + // Negations cancelled out. + if (Candidates.size() % 2 == 0) + return I; + + // Negate the final operand in the expression by flipping the opcode of this + // fadd/fsub. + assert(Candidates.size() % 2 == 1 && "Expected odd number"); + IRBuilder<> Builder(I); + Value *NewInst = IsFSub ? Builder.CreateFAddFMF(OtherOp, Op, I) + : Builder.CreateFSubFMF(OtherOp, Op, I); + I->replaceAllUsesWith(NewInst); RedoInsts.insert(I); - MadeChange = true; - return NI; + return dyn_cast(NewInst); +} + +/// Canonicalize expressions that contain a negative floating-point constant +/// of the following form: +/// OtherOp + (subtree) -> OtherOp {+/-} (canonical subtree) +/// (subtree) + OtherOp -> OtherOp {+/-} (canonical subtree) +/// OtherOp - (subtree) -> OtherOp {+/-} (canonical subtree) +/// +/// The fadd/fsub opcode may be switched to allow folding a negation into the +/// input instruction. +Instruction *ReassociatePass::canonicalizeNegFPConstants(Instruction *I) { + LLVM_DEBUG(dbgs() << "Combine negations for: " << *I << '\n'); + Value *X; + Instruction *Op; + if (match(I, m_FAdd(m_Value(X), m_OneUse(m_Instruction(Op))))) + if (Instruction *R = canonicalizeNegFPConstantsForOp(I, Op, X)) + I = R; + if (match(I, m_FAdd(m_OneUse(m_Instruction(Op)), m_Value(X)))) + if (Instruction *R = canonicalizeNegFPConstantsForOp(I, Op, X)) + I = R; + if (match(I, m_FSub(m_Value(X), m_OneUse(m_Instruction(Op))))) + if (Instruction *R = canonicalizeNegFPConstantsForOp(I, Op, X)) + I = R; + return I; } /// Inspect and optimize the given instruction. Note that erasing @@ -2042,16 +2086,16 @@ I = NI; } - // Canonicalize negative constants out of expressions. - if (Instruction *Res = canonicalizeNegConstExpr(I)) - I = Res; - // Commute binary operators, to canonicalize the order of their operands. // This can potentially expose more CSE opportunities, and makes writing other // transformations simpler. if (I->isCommutative()) canonicalizeOperands(I); + // Canonicalize negative constants out of expressions. + if (Instruction *Res = canonicalizeNegFPConstants(I)) + I = Res; + // Don't optimize floating-point instructions unless they are 'fast'. if (I->getType()->isFPOrFPVectorTy() && !I->isFast()) return; Index: llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll =================================================================== --- llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll +++ llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll @@ -187,10 +187,10 @@ define double @fadd_fmul_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fmul_neg_const1( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[C:%.*]] -; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A:%.*]], [[MUL1]] -; CHECK-NEXT: ret double [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[A:%.*]], [[MUL1]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %b, -3.0 %mul1 = fmul double %mul0, %c @@ -200,11 +200,11 @@ define double @fadd_fmul_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fmul_neg_const2( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[B:%.*]] ; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], 4.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[A]], [[MUL2]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A]], [[MUL2]] +; CHECK-NEXT: ret double [[ADD]] ; %mul0 = fmul double %a, -3.0 %mul1 = fmul double %mul0, %b @@ -215,12 +215,12 @@ define double @fadd_fmul_neg_const3(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fmul_neg_const3( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[B:%.*]] -; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], -4.000000e+00 +; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], 4.000000e+00 ; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[MUL2]], 5.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[C:%.*]], [[MUL3]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[C:%.*]], [[MUL3]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %a, -3.0 %mul1 = fmul double %mul0, %b @@ -232,10 +232,10 @@ define double @fsub_fmul_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_fmul_neg_const1( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[C:%.*]] -; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A:%.*]], [[MUL1]] -; CHECK-NEXT: ret double [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[A:%.*]], [[MUL1]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %b, -3.0 %mul1 = fmul double %mul0, %c @@ -245,11 +245,11 @@ define double @fsub_fmul_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_fmul_neg_const2( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[B:%.*]] ; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], 4.000000e+00 -; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A]], [[MUL2]] -; CHECK-NEXT: ret double [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[A]], [[MUL2]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %a, -3.0 %mul1 = fmul double %mul0, %b @@ -262,10 +262,10 @@ ; CHECK-LABEL: @fsub_fmul_neg_const3( ; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[MUL0]], [[B:%.*]] -; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], -4.000000e+00 +; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[MUL1]], 4.000000e+00 ; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[MUL2]], 5.000000e+00 -; CHECK-NEXT: [[SUB1:%.*]] = fadd double [[C:%.*]], [[MUL3]] -; CHECK-NEXT: ret double [[SUB1]] +; CHECK-NEXT: [[SUB:%.*]] = fsub double [[C:%.*]], [[MUL3]] +; CHECK-NEXT: ret double [[SUB]] ; %mul0 = fmul double %a, 3.0 %mul1 = fmul double %mul0, %b @@ -277,10 +277,10 @@ define double @fadd_fdiv_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fdiv_neg_const1( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[C:%.*]] -; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A:%.*]], [[DIV1]] -; CHECK-NEXT: ret double [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[A:%.*]], [[DIV1]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double %b, -3.0 %div1 = fdiv double %div0, %c @@ -290,11 +290,11 @@ define double @fadd_fdiv_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fdiv_neg_const2( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[B:%.*]] ; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[DIV1]], 7.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[A]], [[DIV2]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A]], [[DIV2]] +; CHECK-NEXT: ret double [[ADD]] ; %div0 = fdiv double -3.0, %a %div1 = fdiv double %div0, %b @@ -305,9 +305,9 @@ define double @fadd_fdiv_neg_const3(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_fdiv_neg_const3( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[B:%.*]] -; CHECK-NEXT: [[DIV2:%.*]] = fdiv double -4.000000e+00, [[DIV1]] +; CHECK-NEXT: [[DIV2:%.*]] = fdiv double 4.000000e+00, [[DIV1]] ; CHECK-NEXT: [[DIV3:%.*]] = fdiv double [[DIV2]], 5.000000e+00 ; CHECK-NEXT: [[ADD:%.*]] = fadd double [[C:%.*]], [[DIV3]] ; CHECK-NEXT: ret double [[ADD]] @@ -322,10 +322,10 @@ define double @fsub_fdiv_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_fdiv_neg_const1( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[C:%.*]] -; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A:%.*]], [[DIV1]] -; CHECK-NEXT: ret double [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[A:%.*]], [[DIV1]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double %b, -3.0 %div1 = fdiv double %div0, %c @@ -335,11 +335,11 @@ define double @fsub_fdiv_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_fdiv_neg_const2( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[B:%.*]] ; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[DIV1]], 7.000000e+00 -; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A]], [[DIV2]] -; CHECK-NEXT: ret double [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[A]], [[DIV2]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double -3.0, %a %div1 = fdiv double %div0, %b @@ -350,12 +350,12 @@ define double @fsub_fdiv_neg_const3(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_fdiv_neg_const3( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[DIV0]], [[B:%.*]] -; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[DIV1]], -7.000000e+00 +; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[DIV1]], 7.000000e+00 ; CHECK-NEXT: [[DIV3:%.*]] = fdiv double 5.000000e+00, [[DIV2]] -; CHECK-NEXT: [[SUB1:%.*]] = fadd double [[C:%.*]], [[DIV3]] -; CHECK-NEXT: ret double [[SUB1]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[C:%.*]], [[DIV3]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double -3.0, %a %div1 = fdiv double %div0, %b @@ -367,10 +367,10 @@ define double @fadd_mix_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_mix_neg_const1( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[MUL0]], [[C:%.*]] -; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A:%.*]], [[DIV1]] -; CHECK-NEXT: ret double [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[A:%.*]], [[DIV1]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %b, -3.0 %div1 = fdiv double %mul0, %c @@ -380,11 +380,11 @@ define double @fadd_mix_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_mix_neg_const2( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[DIV0]], [[B:%.*]] ; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[MUL1]], 5.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[A]], [[DIV2]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[ADD:%.*]] = fadd double [[A]], [[DIV2]] +; CHECK-NEXT: ret double [[ADD]] ; %div0 = fdiv double -3.0, %a %mul1 = fmul double %div0, %b @@ -395,12 +395,12 @@ define double @fadd_mix_neg_const3(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_mix_neg_const3( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[MUL0]], [[B:%.*]] -; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[DIV1]], -4.000000e+00 +; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[DIV1]], 4.000000e+00 ; CHECK-NEXT: [[DIV3:%.*]] = fdiv double [[MUL2]], 5.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[C:%.*]], [[DIV3]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[C:%.*]], [[DIV3]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %a, -3.0 %div1 = fdiv double %mul0, %b @@ -412,10 +412,10 @@ define double @fsub_mix_neg_const1(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_mix_neg_const1( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], -3.000000e+00 +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double [[B:%.*]], 3.000000e+00 ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[DIV0]], [[C:%.*]] -; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A:%.*]], [[MUL1]] -; CHECK-NEXT: ret double [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[A:%.*]], [[MUL1]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double %b, -3.0 %mul1 = fmul double %div0, %c @@ -424,11 +424,11 @@ } define double @fsub_mix_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_mix_neg_const2( -; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 +; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], 3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[MUL0]], [[B:%.*]] ; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[DIV1]], 5.000000e+00 -; CHECK-NEXT: [[SUB1:%.*]] = fadd double [[A]], [[MUL2]] -; CHECK-NEXT: ret double [[SUB1]] +; CHECK-NEXT: [[SUB:%.*]] = fsub double [[A]], [[MUL2]] +; CHECK-NEXT: ret double [[SUB]] ; %mul0 = fmul double -3.0, %a %div1 = fdiv double %mul0, %b @@ -439,12 +439,12 @@ define double @fsub_mix_neg_const3(double %a, double %b, double %c) { ; CHECK-LABEL: @fsub_mix_neg_const3( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[DIV0]], [[B:%.*]] -; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[MUL1]], -7.000000e+00 +; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[MUL1]], 7.000000e+00 ; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[DIV2]], 5.000000e+00 -; CHECK-NEXT: [[SUB1:%.*]] = fadd double [[C:%.*]], [[MUL3]] -; CHECK-NEXT: ret double [[SUB1]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[C:%.*]], [[MUL3]] +; CHECK-NEXT: ret double [[TMP1]] ; %div0 = fdiv double -3.0, %a %mul1 = fmul double %div0, %b @@ -458,10 +458,10 @@ ; CHECK-LABEL: @fadd_both_ops_mix_neg_const1( ; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[B:%.*]], -3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[MUL0]], [[C:%.*]] -; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[A:%.*]], -4.000000e+00 +; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[A:%.*]], 4.000000e+00 ; CHECK-NEXT: [[DIV3:%.*]] = fdiv double [[MUL2]], [[C]] -; CHECK-NEXT: [[ADD:%.*]] = fadd double [[DIV1]], [[DIV3]] -; CHECK-NEXT: ret double [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[DIV1]], [[DIV3]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %b, -3.0 %div1 = fdiv double %mul0, %c @@ -473,14 +473,14 @@ define double @fadd_both_ops_mix_neg_const2(double %a, double %b, double %c) { ; CHECK-LABEL: @fadd_both_ops_mix_neg_const2( -; CHECK-NEXT: [[DIV0:%.*]] = fdiv double -3.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[DIV0:%.*]] = fdiv double 3.000000e+00, [[A:%.*]] ; CHECK-NEXT: [[MUL1:%.*]] = fmul double [[DIV0]], [[B:%.*]] ; CHECK-NEXT: [[DIV2:%.*]] = fdiv double [[MUL1]], 7.000000e+00 -; CHECK-NEXT: [[DIV3:%.*]] = fdiv double -5.000000e+00, [[C:%.*]] +; CHECK-NEXT: [[DIV3:%.*]] = fdiv double 5.000000e+00, [[C:%.*]] ; CHECK-NEXT: [[MUL4:%.*]] = fmul double [[B]], [[DIV3]] -; CHECK-NEXT: [[DIV5:%.*]] = fdiv double [[MUL4]], -6.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[DIV5]], [[DIV2]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[DIV5:%.*]] = fdiv double [[MUL4]], 6.000000e+00 +; CHECK-NEXT: [[ADD:%.*]] = fadd double [[DIV2]], [[DIV5]] +; CHECK-NEXT: ret double [[ADD]] ; %div0 = fdiv double -3.0, %a %mul1 = fmul double %div0, %b @@ -497,13 +497,13 @@ ; CHECK-NEXT: [[MUL0:%.*]] = fmul double [[A:%.*]], -3.000000e+00 ; CHECK-NEXT: [[DIV1:%.*]] = fdiv double [[MUL0]], [[B:%.*]] ; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[DIV1]], -4.000000e+00 -; CHECK-NEXT: [[DIV3:%.*]] = fdiv double [[MUL2]], 5.000000e+00 -; CHECK-NEXT: [[MUL4:%.*]] = fmul double [[C:%.*]], -6.000000e+00 +; CHECK-NEXT: [[DIV3:%.*]] = fdiv double [[MUL2]], -5.000000e+00 +; CHECK-NEXT: [[MUL4:%.*]] = fmul double [[C:%.*]], 6.000000e+00 ; CHECK-NEXT: [[DIV5:%.*]] = fdiv double [[MUL4]], [[B]] -; CHECK-NEXT: [[MUL6:%.*]] = fmul double [[DIV5]], -7.000000e+00 -; CHECK-NEXT: [[MUL7:%.*]] = fdiv double [[MUL6]], -9.000000e+00 -; CHECK-NEXT: [[ADD1:%.*]] = fsub double [[MUL7]], [[DIV3]] -; CHECK-NEXT: ret double [[ADD1]] +; CHECK-NEXT: [[MUL6:%.*]] = fmul double [[DIV5]], 7.000000e+00 +; CHECK-NEXT: [[MUL7:%.*]] = fdiv double [[MUL6]], 9.000000e+00 +; CHECK-NEXT: [[TMP1:%.*]] = fsub double [[DIV3]], [[MUL7]] +; CHECK-NEXT: ret double [[TMP1]] ; %mul0 = fmul double %a, -3.0 %div1 = fdiv double %mul0, %b Index: llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll =================================================================== --- llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll +++ llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll @@ -282,9 +282,10 @@ define <2 x float> @test10(<2 x float> %a, <2 x float> %b, <2 x float> %z) { ; CHECK-LABEL: @test10( ; CHECK-NEXT: [[TMP1:%.*]] = fsub fast <2 x float> zeroinitializer, zeroinitializer -; CHECK-NEXT: [[E:%.*]] = fmul fast <2 x float> [[A:%.*]], -; CHECK-NEXT: [[F:%.*]] = fmul fast <2 x float> [[E]], [[Z:%.*]] -; CHECK-NEXT: ret <2 x float> [[F]] +; CHECK-NEXT: [[C:%.*]] = fmul fast <2 x float> [[A:%.*]], +; CHECK-NEXT: [[E:%.*]] = fmul fast <2 x float> [[C]], [[Z:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = fadd fast <2 x float> [[E]], zeroinitializer +; CHECK-NEXT: ret <2 x float> [[TMP2]] ; %d = fmul fast <2 x float> %z, %c = fsub fast <2 x float> , %d @@ -343,7 +344,7 @@ define <2 x double> @test11(<2 x double> %x, <2 x double> %y) { ; CHECK-LABEL: @test11( -; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast <2 x double> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast <2 x double> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <2 x double> [[FACTOR]], ; CHECK-NEXT: ret <2 x double> [[REASS_MUL]] ; @@ -381,15 +382,13 @@ ret <2 x i64> %shl } -; FIXME: expressions with a negative const should be canonicalized to assist -; further reassociation. -; We would expect (-5*b)+a -> a-(5*b) but only the constant operand is commuted. +; (-5*b)+a -> a-(5*b) define <4 x float> @test13(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: @test13( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast <4 x float> [[B:%.*]], -; CHECK-NEXT: [[ADD:%.*]] = fadd fast <4 x float> [[MUL]], [[A:%.*]] -; CHECK-NEXT: ret <4 x float> [[ADD]] +; CHECK-NEXT: [[MUL:%.*]] = fmul fast <4 x float> [[B:%.*]], +; CHECK-NEXT: [[TMP1:%.*]] = fsub fast <4 x float> [[A:%.*]], [[MUL]] +; CHECK-NEXT: ret <4 x float> [[TMP1]] ; %mul = fmul fast <4 x float> , %b %add = fadd fast <4 x float> %mul, %a Index: llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll =================================================================== --- llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll +++ llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll @@ -1,15 +1,15 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -reassociate -S | FileCheck %s -; Input is A op (B op C) +; B * 5 + A * -5 +; TODO: (B - A) * 5 define half @faddsubAssoc1(half %a, half %b) { ; CHECK-LABEL: @faddsubAssoc1( -; CHECK-NEXT: [[T2_NEG:%.*]] = fmul fast half [[A:%.*]], 0xH4500 +; CHECK-NEXT: [[T2_NEG:%.*]] = fmul fast half [[A:%.*]], 0xHC500 ; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast half [[B:%.*]], 0xH4500 -; CHECK-NEXT: [[T51:%.*]] = fsub fast half [[REASS_MUL]], [[T2_NEG]] ; CHECK-NEXT: [[T5:%.*]] = fadd fast half [[REASS_MUL]], [[T2_NEG]] -; CHECK-NEXT: ret half [[T51]] +; CHECK-NEXT: ret half [[T5]] ; %t1 = fmul fast half %b, 0xH4200 ; 3*b %t2 = fmul fast half %a, 0xH4500 ; 5*a @@ -19,7 +19,7 @@ ret half %t5 ; = 5 * (b - a) } -; Input is (A op B) op C +; B + A * 5 define half @faddsubAssoc2(half %a, half %b) { ; CHECK-LABEL: @faddsubAssoc2(