@@ -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,60 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
27792781 return true ;
27802782}
27812783
2784+ // / Reassociate general 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+ BinaryOperator *BO = dyn_cast<BinaryOperator>(&I);
2800+ if (!BO || !BO->isAssociative ())
2801+ return false ;
2802+
2803+ Instruction::BinaryOps Opcode = BO->getOpcode ();
2804+ BinaryOperator *Op0 = dyn_cast<BinaryOperator>(BO->getOperand (0 ));
2805+
2806+ // Transform: "(LV op C1) op C2" ==> "LV op (C1 op C2)"
2807+ if (Op0 && Op0->getOpcode () == Opcode) {
2808+ Value *LV = Op0->getOperand (0 );
2809+ Value *C1 = Op0->getOperand (1 );
2810+ Value *C2 = BO->getOperand (1 );
2811+
2812+ if (L.isLoopInvariant (LV) || !L.isLoopInvariant (C1) ||
2813+ !L.isLoopInvariant (C2))
2814+ return false ;
2815+
2816+ auto *Preheader = L.getLoopPreheader ();
2817+ assert (Preheader && " Loop is not in simplify form?" );
2818+ IRBuilder<> Builder (Preheader->getTerminator ());
2819+ Value *Inv = Builder.CreateBinOp (Opcode, C1, C2, " invariant.op" );
2820+
2821+ auto *NewBO =
2822+ BinaryOperator::Create (Opcode, LV, Inv, BO->getName () + " .reass" , BO);
2823+ NewBO->copyIRFlags (BO);
2824+ BO->replaceAllUsesWith (NewBO);
2825+ eraseInstruction (*BO, SafetyInfo, MSSAU);
2826+
2827+ // Note: (LV op C1) might not be erased if it has more uses than the one we
2828+ // just replaced.
2829+ if (Op0->use_empty ())
2830+ eraseInstruction (*Op0, SafetyInfo, MSSAU);
2831+
2832+ return true ;
2833+ }
2834+
2835+ return false ;
2836+ }
2837+
27822838static bool hoistArithmetics (Instruction &I, Loop &L,
27832839 ICFLoopSafetyInfo &SafetyInfo,
27842840 MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2816,6 +2872,12 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
28162872 return true ;
28172873 }
28182874
2875+ if (hoistBOAssociation (I, L, SafetyInfo, MSSAU, AC, DT)) {
2876+ ++NumHoisted;
2877+ ++NumBOAssociationsHoisted;
2878+ return true ;
2879+ }
2880+
28192881 return false ;
28202882}
28212883
0 commit comments