@@ -113,6 +113,8 @@ STATISTIC(NumFPAssociationsHoisted, "Number of invariant FP expressions "
113
113
STATISTIC (NumIntAssociationsHoisted,
114
114
" Number of invariant int expressions "
115
115
" reassociated and hoisted out of the loop" );
116
+ STATISTIC (NumBOAssociationsHoisted, " Number of invariant BinaryOp expressions "
117
+ " reassociated and hoisted out of the loop" );
116
118
117
119
// / Memory promotion is enabled by default.
118
120
static cl::opt<bool >
@@ -2779,6 +2781,60 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
2779
2781
return true ;
2780
2782
}
2781
2783
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
+
2782
2838
static bool hoistArithmetics (Instruction &I, Loop &L,
2783
2839
ICFLoopSafetyInfo &SafetyInfo,
2784
2840
MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2816,6 +2872,12 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
2816
2872
return true ;
2817
2873
}
2818
2874
2875
+ if (hoistBOAssociation (I, L, SafetyInfo, MSSAU, AC, DT)) {
2876
+ ++NumHoisted;
2877
+ ++NumBOAssociationsHoisted;
2878
+ return true ;
2879
+ }
2880
+
2819
2881
return false ;
2820
2882
}
2821
2883
0 commit comments