@@ -1989,7 +1989,114 @@ Instruction *InstCombinerImpl::foldOpIntoPhi(Instruction &I, PHINode *PN,
19891989 return replaceInstUsesWith (I, NewPN);
19901990}
19911991
1992+ Instruction *InstCombinerImpl::foldBinopWithRecurrence (BinaryOperator &BO) {
1993+ if (!BO.isAssociative ())
1994+ return nullptr ;
1995+
1996+ // Find the interleaved binary ops.
1997+ auto Opc = BO.getOpcode ();
1998+ auto *BO0 = dyn_cast<BinaryOperator>(BO.getOperand (0 ));
1999+ auto *BO1 = dyn_cast<BinaryOperator>(BO.getOperand (1 ));
2000+ if (!BO0 || !BO1 || !BO0->hasNUses (2 ) || !BO1->hasNUses (2 ) ||
2001+ BO0->getOpcode () != Opc || BO1->getOpcode () != Opc ||
2002+ !BO0->isAssociative () || !BO1->isAssociative () ||
2003+ BO0->getParent () != BO1->getParent ())
2004+ return nullptr ;
2005+
2006+ assert (BO.isCommutative () && BO0->isCommutative () && BO1->isCommutative () &&
2007+ " Expected commutative instructions!" );
2008+
2009+ // Find the matching phis, forming the recurrences.
2010+ PHINode *PN0, *PN1;
2011+ Value *Start0, *Step0, *Start1, *Step1;
2012+ if (!matchSimpleRecurrence (BO0, PN0, Start0, Step0) || !PN0->hasOneUse () ||
2013+ !matchSimpleRecurrence (BO1, PN1, Start1, Step1) || !PN1->hasOneUse () ||
2014+ PN0->getParent () != PN1->getParent ())
2015+ return nullptr ;
2016+
2017+ assert (PN0->getNumIncomingValues () == 2 && PN1->getNumIncomingValues () == 2 &&
2018+ " Expected PHIs with two incoming values!" );
2019+
2020+ // Convert the start and step values to constants.
2021+ auto *Init0 = dyn_cast<Constant>(Start0);
2022+ auto *Init1 = dyn_cast<Constant>(Start1);
2023+ auto *C0 = dyn_cast<Constant>(Step0);
2024+ auto *C1 = dyn_cast<Constant>(Step1);
2025+ if (!Init0 || !Init1 || !C0 || !C1)
2026+ return nullptr ;
2027+
2028+ // Fold the recurrence constants.
2029+ auto *Init = ConstantFoldBinaryInstruction (Opc, Init0, Init1);
2030+ auto *C = ConstantFoldBinaryInstruction (Opc, C0, C1);
2031+ if (!Init || !C)
2032+ return nullptr ;
2033+
2034+ // Create the reduced PHI.
2035+ auto *NewPN = PHINode::Create (PN0->getType (), PN0->getNumIncomingValues (),
2036+ " reduced.phi" );
2037+
2038+ // Create the new binary op.
2039+ auto *NewBO = BinaryOperator::Create (Opc, NewPN, C);
2040+ if (Opc == Instruction::FAdd || Opc == Instruction::FMul) {
2041+ // Intersect FMF flags for FADD and FMUL.
2042+ FastMathFlags Intersect = BO0->getFastMathFlags () &
2043+ BO1->getFastMathFlags () & BO.getFastMathFlags ();
2044+ NewBO->setFastMathFlags (Intersect);
2045+ } else {
2046+ OverflowTracking Flags;
2047+ Flags.AllKnownNonNegative = false ;
2048+ Flags.AllKnownNonZero = false ;
2049+ Flags.mergeFlags (*BO0);
2050+ Flags.mergeFlags (*BO1);
2051+ Flags.mergeFlags (BO);
2052+ Flags.applyFlags (*NewBO);
2053+ }
2054+ NewBO->takeName (&BO);
2055+
2056+ for (unsigned I = 0 , E = PN0->getNumIncomingValues (); I != E; ++I) {
2057+ auto *V = PN0->getIncomingValue (I);
2058+ auto *BB = PN0->getIncomingBlock (I);
2059+ if (V == Init0) {
2060+ assert (((PN1->getIncomingValue (0 ) == Init1 &&
2061+ PN1->getIncomingBlock (0 ) == BB) ||
2062+ (PN1->getIncomingValue (1 ) == Init1 &&
2063+ PN1->getIncomingBlock (1 ) == BB)) &&
2064+ " Invalid incoming block!" );
2065+ NewPN->addIncoming (Init, BB);
2066+ } else if (V == BO0) {
2067+ assert (((PN1->getIncomingValue (0 ) == BO1 &&
2068+ PN1->getIncomingBlock (0 ) == BB) ||
2069+ (PN1->getIncomingValue (1 ) == BO1 &&
2070+ PN1->getIncomingBlock (1 ) == BB)) &&
2071+ " Invalid incoming block!" );
2072+ NewPN->addIncoming (NewBO, BB);
2073+ } else
2074+ llvm_unreachable (" Unexpected incoming value!" );
2075+ }
2076+
2077+ LLVM_DEBUG (dbgs () << " Combined " << *PN0 << " \n " << *BO0
2078+ << " \n with " << *PN1 << " \n " << *BO1
2079+ << ' \n ' );
2080+
2081+ // Insert the new recurrence and remove the old (dead) ones.
2082+ InsertNewInstWith (NewPN, PN0->getIterator ());
2083+ InsertNewInstWith (NewBO, BO0->getIterator ());
2084+
2085+ eraseInstFromFunction (
2086+ *replaceInstUsesWith (*BO0, PoisonValue::get (BO0->getType ())));
2087+ eraseInstFromFunction (
2088+ *replaceInstUsesWith (*BO1, PoisonValue::get (BO1->getType ())));
2089+ eraseInstFromFunction (*PN0);
2090+ eraseInstFromFunction (*PN1);
2091+
2092+ return replaceInstUsesWith (BO, NewBO);
2093+ }
2094+
19922095Instruction *InstCombinerImpl::foldBinopWithPhiOperands (BinaryOperator &BO) {
2096+ // Attempt to fold binary operators whose operands are simple recurrences.
2097+ if (auto *NewBO = foldBinopWithRecurrence (BO))
2098+ return NewBO;
2099+
19932100 // TODO: This should be similar to the incoming values check in foldOpIntoPhi:
19942101 // we are guarding against replicating the binop in >1 predecessor.
19952102 // This could miss matching a phi with 2 constant incoming values.
0 commit comments