@@ -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,68 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
2779
2781
return true ;
2780
2782
}
2781
2783
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
+
2782
2846
static bool hoistArithmetics (Instruction &I, Loop &L,
2783
2847
ICFLoopSafetyInfo &SafetyInfo,
2784
2848
MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2816,6 +2880,12 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
2816
2880
return true ;
2817
2881
}
2818
2882
2883
+ if (hoistBOAssociation (I, L, SafetyInfo, MSSAU, AC, DT)) {
2884
+ ++NumHoisted;
2885
+ ++NumBOAssociationsHoisted;
2886
+ return true ;
2887
+ }
2888
+
2819
2889
return false ;
2820
2890
}
2821
2891
0 commit comments