@@ -106,6 +106,8 @@ STATISTIC(NumMinMaxHoisted,
106106 " Number of min/max expressions hoisted out of the loop" );
107107STATISTIC (NumGEPsHoisted,
108108 " Number of geps reassociated and hoisted out of the loop" );
109+ STATISTIC (NumAddSubHoisted, " Number of add/subtract expressions reassociated "
110+ " and hoisted out of the loop" );
109111
110112// / Memory promotion is enabled by default.
111113static cl::opt<bool >
@@ -2525,10 +2527,89 @@ static bool hoistGEP(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo,
25252527 return true ;
25262528}
25272529
2530+ // / Try to turn things like "LV + C1 < C2" into "LV < C2 - C1". Here
2531+ // / C1 and C2 are loop invariants and LV is a loop-variant.
2532+ static bool hoistAdd (ICmpInst::Predicate Pred, Value *VariantLHS,
2533+ Value *InvariantRHS, ICmpInst &ICmp, Loop &L,
2534+ ICFLoopSafetyInfo &SafetyInfo, MemorySSAUpdater &MSSAU,
2535+ AssumptionCache *AC, DominatorTree *DT) {
2536+ assert (ICmpInst::isSigned (Pred) && " Not supported yet!" );
2537+ assert (!L.isLoopInvariant (VariantLHS) && " Precondition." );
2538+ assert (L.isLoopInvariant (InvariantRHS) && " Precondition." );
2539+
2540+ // Try to represent VariantLHS as sum of invariant and variant operands.
2541+ using namespace PatternMatch ;
2542+ Value *VariantOp, *InvariantOp;
2543+ if (!match (VariantLHS, m_NSWAdd (m_Value (VariantOp), m_Value (InvariantOp))))
2544+ return false ;
2545+
2546+ // LHS itself is a loop-variant, try to represent it in the form:
2547+ // "VariantOp + InvariantOp". If it is possible, then we can reassociate.
2548+ if (L.isLoopInvariant (VariantOp))
2549+ std::swap (VariantOp, InvariantOp);
2550+ if (L.isLoopInvariant (VariantOp) || !L.isLoopInvariant (InvariantOp))
2551+ return false ;
2552+
2553+ // In order to turn "LV + C1 < C2" into "LV < C2 - C1", we need to be able to
2554+ // freely move values from left side of inequality to right side (just as in
2555+ // normal linear arithmetics). Overflows make things much more complicated, so
2556+ // we want to avoid this.
2557+ auto &DL = L.getHeader ()->getModule ()->getDataLayout ();
2558+ bool ProvedNoOverflowAfterReassociate =
2559+ computeOverflowForSignedSub (InvariantRHS, InvariantOp, DL, AC, &ICmp,
2560+ DT) == llvm::OverflowResult::NeverOverflows;
2561+ if (!ProvedNoOverflowAfterReassociate)
2562+ return false ;
2563+ auto *Preheader = L.getLoopPreheader ();
2564+ assert (Preheader && " Loop is not in simplify form?" );
2565+ IRBuilder<> Builder (Preheader->getTerminator ());
2566+ Value *NewCmpOp = Builder.CreateSub (InvariantRHS, InvariantOp, " invariant.op" ,
2567+ /* HasNUW*/ false , /* HasNSW*/ true );
2568+ ICmp.setPredicate (Pred);
2569+ ICmp.setOperand (0 , VariantOp);
2570+ ICmp.setOperand (1 , NewCmpOp);
2571+ eraseInstruction (cast<Instruction>(*VariantLHS), SafetyInfo, MSSAU);
2572+ return true ;
2573+ }
2574+
2575+ // / Reassociate and hoist add/sub expressions.
2576+ static bool hoistAddSub (Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo,
2577+ MemorySSAUpdater &MSSAU, AssumptionCache *AC,
2578+ DominatorTree *DT) {
2579+ using namespace PatternMatch ;
2580+ ICmpInst::Predicate Pred;
2581+ Value *LHS, *RHS;
2582+ if (!match (&I, m_ICmp (Pred, m_Value (LHS), m_Value (RHS))))
2583+ return false ;
2584+
2585+ // TODO: Support unsigned predicates?
2586+ if (!ICmpInst::isSigned (Pred))
2587+ return false ;
2588+
2589+ // Put variant operand to LHS position.
2590+ if (L.isLoopInvariant (LHS)) {
2591+ std::swap (LHS, RHS);
2592+ Pred = ICmpInst::getSwappedPredicate (Pred);
2593+ }
2594+ // We want to delete the initial operation after reassociation, so only do it
2595+ // if it has no other uses.
2596+ if (L.isLoopInvariant (LHS) || !L.isLoopInvariant (RHS) || !LHS->hasOneUse ())
2597+ return false ;
2598+
2599+ // TODO: We could go with smarter context, taking common dominator of all I's
2600+ // users instead of I itself.
2601+ if (hoistAdd (Pred, LHS, RHS, cast<ICmpInst>(I), L, SafetyInfo, MSSAU, AC, DT))
2602+ return true ;
2603+
2604+ // TODO: Support Sub.
2605+
2606+ return false ;
2607+ }
2608+
25282609static bool hoistArithmetics (Instruction &I, Loop &L,
25292610 ICFLoopSafetyInfo &SafetyInfo,
2530- MemorySSAUpdater &MSSAU,
2531- AssumptionCache *AC, DominatorTree *DT) {
2611+ MemorySSAUpdater &MSSAU, AssumptionCache *AC,
2612+ DominatorTree *DT) {
25322613 // Optimize complex patterns, such as (x < INV1 && x < INV2), turning them
25332614 // into (x < min(INV1, INV2)), and hoisting the invariant part of this
25342615 // expression out of the loop.
@@ -2545,6 +2626,13 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
25452626 return true ;
25462627 }
25472628
2629+ // Try to hoist add/sub's by reassociation.
2630+ if (hoistAddSub (I, L, SafetyInfo, MSSAU, AC, DT)) {
2631+ ++NumHoisted;
2632+ ++NumAddSubHoisted;
2633+ return true ;
2634+ }
2635+
25482636 return false ;
25492637}
25502638
0 commit comments