Index: llvm/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LICM.cpp +++ llvm/lib/Transforms/Scalar/LICM.cpp @@ -68,6 +68,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PatternMatch.h" @@ -102,6 +103,8 @@ STATISTIC(NumPromotionCandidates, "Number of promotion candidates"); STATISTIC(NumLoadPromoted, "Number of load-only promotions"); STATISTIC(NumLoadStorePromoted, "Number of load and store promotions"); +STATISTIC(NumMinMaxHoisted, + "Number min/max expressions hoisted out of the loop"); /// Memory promotion is enabled by default. static cl::opt @@ -166,6 +169,11 @@ SinkAndHoistLICMFlags &Flags); static bool pointerInvalidatedByBlock(BasicBlock &BB, MemorySSA &MSSA, MemoryUse &MU); +/// Try to simplify things like (A < INV_1 AND icmp A < INV_2) into (A < +/// min(INV_1, INV_2)), if INV_1 and INV_2 are both loop invariants and their +/// minimun can be computed outside of loop, and X is not a loop-invariant. +static bool hoistMinMax(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo, + MemorySSAUpdater &MSSAU); static Instruction *cloneInstructionInExitBlock( Instruction &I, BasicBlock &ExitBlock, PHINode &PN, const LoopInfo *LI, const LoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU); @@ -983,6 +991,15 @@ } } + // Optimize complex patterns, such as (x < INV1 && x < INV2), turning them + // into (x < min(INV1, INV2)), and hoisting the invariant part of this + // expression out of the loop. + if (hoistMinMax(I, *CurLoop, *SafetyInfo, MSSAU)) { + ++NumMinMaxHoisted; + Changed = true; + continue; + } + // Remember possibly hoistable branches so we can actually hoist them // later if needed. if (BranchInst *BI = dyn_cast(&I)) @@ -2383,6 +2400,70 @@ return false; } +static bool hoistMinMax(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo, + MemorySSAUpdater &MSSAU) { + auto *Preheader = L.getLoopPreheader(); + assert(Preheader && "Loop is not in simplify form?"); + bool Inverse = false; + using namespace PatternMatch; + Value *Cond1, *Cond2; + if (match(&I, m_LogicalOr(m_Value(Cond1), m_Value(Cond2)))) + Inverse = true; + else if (!match(&I, m_LogicalAnd(m_Value(Cond1), m_Value(Cond2)))) + return false; + + auto MatchICmpAgainstInvariant = [&](Value *C, ICmpInst::Predicate &P, + Value *&LHS, Value *&RHS) { + if (!C->hasOneUse()) + return false; + if (!match(C, m_ICmp(P, m_Value(LHS), m_Value(RHS)))) + return false; + if (!ICmpInst::isRelational(P)) + return false; + if (L.isLoopInvariant(LHS) || !L.isLoopInvariant(RHS)) + return false; + // TODO: We can do more efforts to canonicalize this. For example: + // - With both LHS and RHS are known non-negative (negative), turn to + // canonical (unsigned) form; + // - Swap LHS and RHS to match the pattern; + // etc. + if (Inverse) + P = ICmpInst::getInversePredicate(P); + return true; + }; + ICmpInst::Predicate P1, P2; + Value *LHS1, *LHS2, *RHS1, *RHS2; + if (!MatchICmpAgainstInvariant(Cond1, P1, LHS1, RHS1) || + !MatchICmpAgainstInvariant(Cond2, P2, LHS2, RHS2)) + return false; + if (P1 != P2 || LHS1 != LHS2) + return false; + + // Everything is fine, we can do the transform. + bool UseMin = ICmpInst::isLT(P1) || ICmpInst::isLE(P1); + assert( + (UseMin || ICmpInst::isGT(P1) || ICmpInst::isGE(P1)) && + "Relational predicate is either less (or equal) or greater (or equal)!"); + Intrinsic::ID id = ICmpInst::isSigned(P1) + ? (UseMin ? Intrinsic::smin : Intrinsic::smax) + : (UseMin ? Intrinsic::umin : Intrinsic::umax); + IRBuilder<> Builder(Preheader->getTerminator()); + Value *NewRHS = Builder.CreateBinaryIntrinsic( + id, RHS1, RHS2, nullptr, StringRef("invariant.") + + (ICmpInst::isSigned(P1) ? "s" : "u") + + (UseMin ? "min" : "max")); + Builder.SetInsertPoint(&I); + auto P = P1; + if (Inverse) + P = ICmpInst::getInversePredicate(P); + Value *NewCond = Builder.CreateICmp(P, LHS1, NewRHS, I.getName()); + I.replaceAllUsesWith(NewCond); + eraseInstruction(I, SafetyInfo, MSSAU); + eraseInstruction(*cast(Cond1), SafetyInfo, MSSAU); + eraseInstruction(*cast(Cond2), SafetyInfo, MSSAU); + return true; +} + /// Little predicate that returns true if the specified basic block is in /// a subloop of the current one, not the current one itself. /// Index: llvm/test/Transforms/LICM/min_max.ll =================================================================== --- llvm/test/Transforms/LICM/min_max.ll +++ llvm/test/Transforms/LICM/min_max.ll @@ -1,18 +1,17 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S %s -passes='loop-mssa(licm)' -verify-memoryssa | FileCheck %s -; TODO: turn to %iv u umax(inv_1, inv_2) and hoist it out of loop. +; turn to %iv >u umax(inv_1, inv_2) and hoist it out of loop. define i32 @test_ugt(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_ugt( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp ugt i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -156,18 +151,17 @@ ret i32 %iv } -; TODO: turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop. +; turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop. define i32 @test_uge(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_uge( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp uge i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp uge i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -187,18 +181,17 @@ ret i32 %iv } -; TODO: turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop. +; turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop. define i32 @test_sgt(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_sgt( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp sgt i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp sgt i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -218,18 +211,17 @@ ret i32 %iv } -; TODO: turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop. +; turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop. define i32 @test_sge(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_sge( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp sge i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -249,18 +241,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_ult_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_ult_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -280,18 +271,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_ule_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_ule_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -311,18 +301,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_slt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_slt_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp slt i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -342,18 +331,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_sle_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_sle_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp sle i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp sle i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMAX]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -373,18 +361,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_ugt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_ugt_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp ugt i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMIN]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -404,18 +391,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_uge_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_uge_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp uge i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp uge i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMIN]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -435,18 +421,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_sgt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_sgt_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp sgt i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp sgt i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMIN]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]] @@ -466,18 +451,17 @@ ret i32 %iv } -; TODO: Turn OR to AND and handle accordingly. +; Turn OR to AND and handle accordingly. define i32 @test_sge_inv(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_sge_inv( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp sge i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = or i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: [[LOOP_COND1:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMIN]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 -; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: br i1 [[LOOP_COND1]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] ; CHECK-NEXT: ret i32 [[IV_LCSSA]]