@@ -113,6 +113,8 @@ STATISTIC(NumFPAssociationsHoisted, "Number of invariant FP expressions "
113113STATISTIC (NumIntAssociationsHoisted,
114114 " Number of invariant int expressions "
115115 " reassociated and hoisted out of the loop" );
116+ STATISTIC (NumBOAssociationsHoisted, " Number of invariant BinaryOp expressions "
117+ " reassociated and hoisted out of the loop" );
116118
117119// / Memory promotion is enabled by default.
118120static cl::opt<bool >
@@ -2779,6 +2781,68 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
27792781 return true ;
27802782}
27812783
2784+ // / Reassociate associative binary expressions of the form
2785+ // /
2786+ // / 1. "(LV op C1) op C2" ==> "LV op (C1 op C2)"
2787+ // /
2788+ // / where op is an associative binary op, LV is a loop variant, and C1 and C2
2789+ // / are loop invariants that we want to hoist.
2790+ // /
2791+ // / TODO: This can be extended to more cases such as
2792+ // / 2. "C1 op (C2 op LV)" ==> "(C1 op C2) op LV"
2793+ // / 3. "(C1 op LV) op C2" ==> "LV op (C1 op C2)" if op is commutative
2794+ // / 4. "C1 op (LV op C2)" ==> "(C1 op C2) op LV" if op is commutative
2795+ static bool hoistBOAssociation (Instruction &I, Loop &L,
2796+ ICFLoopSafetyInfo &SafetyInfo,
2797+ MemorySSAUpdater &MSSAU, AssumptionCache *AC,
2798+ DominatorTree *DT) {
2799+ auto *BO = dyn_cast<BinaryOperator>(&I);
2800+ if (!BO || !BO->isAssociative ())
2801+ return false ;
2802+
2803+ // Only fold ADDs for now.
2804+ Instruction::BinaryOps Opcode = BO->getOpcode ();
2805+ if (Opcode != Instruction::Add)
2806+ return false ;
2807+
2808+ auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand (0 ));
2809+ if (!BO0 || BO0->getOpcode () != Opcode || !BO0->isAssociative ())
2810+ return false ;
2811+
2812+ // Transform: "(LV op C1) op C2" ==> "LV op (C1 op C2)"
2813+ Value *LV = BO0->getOperand (0 );
2814+ Value *C1 = BO0->getOperand (1 );
2815+ Value *C2 = BO->getOperand (1 );
2816+
2817+ if (L.isLoopInvariant (LV) || !L.isLoopInvariant (C1) || !L.isLoopInvariant (C2))
2818+ return false ;
2819+
2820+ auto *Preheader = L.getLoopPreheader ();
2821+ assert (Preheader && " Loop is not in simplify form?" );
2822+
2823+ auto *Inv = BinaryOperator::Create (Opcode, C1, C2, " invariant.op" ,
2824+ Preheader->getTerminator ());
2825+ auto *NewBO =
2826+ BinaryOperator::Create (Opcode, LV, Inv, BO->getName () + " .reass" , BO);
2827+
2828+ // Copy NUW for ADDs if both instructions have it.
2829+ if (Opcode == Instruction::Add && BO->hasNoUnsignedWrap () &&
2830+ BO0->hasNoUnsignedWrap ()) {
2831+ Inv->setHasNoUnsignedWrap (true );
2832+ NewBO->setHasNoUnsignedWrap (true );
2833+ }
2834+
2835+ BO->replaceAllUsesWith (NewBO);
2836+ eraseInstruction (*BO, SafetyInfo, MSSAU);
2837+
2838+ // (LV op C1) might not be erased if it has more uses than the one we just
2839+ // replaced.
2840+ if (BO0->use_empty ())
2841+ eraseInstruction (*BO0, SafetyInfo, MSSAU);
2842+
2843+ return true ;
2844+ }
2845+
27822846static bool hoistArithmetics (Instruction &I, Loop &L,
27832847 ICFLoopSafetyInfo &SafetyInfo,
27842848 MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2816,6 +2880,12 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
28162880 return true ;
28172881 }
28182882
2883+ if (hoistBOAssociation (I, L, SafetyInfo, MSSAU, AC, DT)) {
2884+ ++NumHoisted;
2885+ ++NumBOAssociationsHoisted;
2886+ return true ;
2887+ }
2888+
28192889 return false ;
28202890}
28212891
0 commit comments