diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ConstraintSystem.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" @@ -262,6 +263,13 @@ void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, unsigned NumOut, SmallVectorImpl &DFSInStack); + /// If \p A is a monotonically increasing induction phi with start value S and + /// \p Pred is ICMP_NE, try to add A < B and A >= S. + void addFactForInductionPhi(CmpInst *CI, CmpInst::Predicate Pred, Value *A, + Value *B, unsigned NumIn, unsigned NumOut, + SmallVectorImpl &DFSInStack, + DominatorTree &DT, LoopInfo &LI); + /// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of /// constraints, using indices from the corresponding constraint system. /// New variables that need to be added to the system are collected in @@ -1119,13 +1127,15 @@ static bool checkAndSecondOpImpliedByFirst( FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl &ReproducerCondStack, - SmallVectorImpl &DFSInStack) { + SmallVectorImpl &DFSInStack, DominatorTree &DT, LoopInfo &LI) { CmpInst::Predicate Pred; Value *A, *B; Instruction *And = CB.getContextInst(); if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B)))) return false; + Info.addFactForInductionPhi(cast(And->getOperand(0)), Pred, A, B, + CB.NumIn, CB.NumOut, DFSInStack, DT, LI); // Optimistically add fact from first condition. unsigned OldSize = DFSInStack.size(); Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); @@ -1150,6 +1160,102 @@ return Changed; } +void ConstraintInfo::addFactForInductionPhi( + CmpInst *CI, CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, + unsigned NumOut, SmallVectorImpl &DFSInStack, DominatorTree &DT, + LoopInfo &LI) { + auto *PN = dyn_cast(A); + // TODO: Extend to support B being the phi node. + if (Pred != CmpInst::ICMP_NE || !PN || PN->getNumIncomingValues() != 2) + return; + + // Check if the edge for which we add the condition is staying in the loop, + // while the other edge leaves the loop. + Loop *L = LI.getLoopFor(PN->getParent()); + if (!L || !CI->hasOneUse()) + return; + Instruction *User = cast(*CI->user_begin()); + // Support conditions implied by first operand of and. + if (match(User, m_OneUse(m_LogicalAnd(m_Value(), m_Value())))) + User = cast(*User->user_begin()); + + if (!isa(User) || User->getParent() != PN->getParent()) + return; + + BasicBlock *InLoopSucc = nullptr; + BasicBlock *LoopExitSucc = nullptr; + // Find the block we add the condition for (using NumIn and NumOut) and the + // other block. + for (BasicBlock *Succ : successors(User->getParent())) { + auto *N = DT.getNode(Succ); + if (NumIn == N->getDFSNumIn() && NumOut == N->getDFSNumOut()) + InLoopSucc = Succ; + else + LoopExitSucc = Succ; + } + if (!InLoopSucc || LI.getLoopFor(InLoopSucc) != L || + LI.getLoopFor(LoopExitSucc) == L) + return; + + // Check if PN is a monotonic pointer induction phi of the form + // %pn = phi [ %start, %entry ], [ %iv.next, %loop ] + // %iv.next = getelementptr inbounds %pn, %step + // with a positive step. + // TODO: generalize to support larger steps, e.g. if the branch controls the + // only exit. + Value *StartValue = nullptr; + GetElementPtrInst *StepInst = nullptr; + for (unsigned I = 0; I != 2; ++I) { + StepInst = dyn_cast(PN->getIncomingValue(I)); + if (StepInst && StepInst->isInBounds() && + StepInst->getPointerOperand() == PN) { + StartValue = PN->getIncomingValue(1 - I); + break; + } + } + if (!StartValue) + return; + + // Make sure the GEP either steps by 1 byte or that the value we compare + // against is a GEP based on the same start value and all offsets are a + // multiple of the step size, to guarantee that the induction will reach the + // value. + const DataLayout &DL = CI->getModule()->getDataLayout(); + unsigned BitWidth = + DL.getIndexTypeSizeInBits(StepInst->getPointerOperand()->getType()); + APInt StepOffset(BitWidth, 0); + if (!StepInst->accumulateConstantOffset(DL, StepOffset) || + StepOffset.isZero() || StepOffset.isNegative()) + return; + + if (!StepOffset.isOne()) { + auto *UpperGEP = dyn_cast(B); + if (!UpperGEP || UpperGEP->getPointerOperand() != StartValue || + !UpperGEP->isInBounds()) + return; + + MapVector UpperVariableOffsets; + APInt UpperConstantOffset(BitWidth, 0); + if (!UpperGEP->collectOffset(DL, BitWidth, UpperVariableOffsets, + UpperConstantOffset)) + return; + // All variable offsets and the constant offset have to be a multiple of the + // step. + if (!UpperConstantOffset.urem(StepOffset).isZero() || + any_of(UpperVariableOffsets, [&StepOffset](const auto &P) { + return !P.second.urem(StepOffset).isZero(); + })) + return; + } + + // We know that PN != B, so if StartValue <= B we know that PN < B and PN >= + // StartValue. + if (!doesHold(CmpInst::ICMP_ULE, StartValue, B)) + return; + addFact(CmpInst::ICMP_ULT, PN, B, NumIn, NumOut, DFSInStack); + addFact(CmpInst::ICMP_UGE, PN, StartValue, NumIn, NumOut, DFSInStack); +} + void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, unsigned NumOut, SmallVectorImpl &DFSInStack) { @@ -1263,7 +1369,7 @@ return Changed; } -static bool eliminateConstraints(Function &F, DominatorTree &DT, +static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, OptimizationRemarkEmitter &ORE) { bool Changed = false; DT.updateDFSNumbers(); @@ -1358,9 +1464,9 @@ ReproducerModule.get(), ReproducerCondStack, S.DT); if (!Simplified && match(CB.getContextInst(), m_LogicalAnd(m_Value(), m_Specific(Inst)))) { - Simplified = - checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(), - ReproducerCondStack, DFSInStack); + Simplified = checkAndSecondOpImpliedByFirst( + CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack, + DT, LI); } Changed |= Simplified; } @@ -1376,6 +1482,9 @@ return; } + if (auto *CI = dyn_cast(CB.Inst)) + Info.addFactForInductionPhi(CI, Pred, A, B, CB.NumIn, + CB.NumOut, DFSInStack, DT, LI); Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) ReproducerCondStack.emplace_back(Pred, A, B); @@ -1440,12 +1549,14 @@ PreservedAnalyses ConstraintEliminationPass::run(Function &F, FunctionAnalysisManager &AM) { auto &DT = AM.getResult(F); + auto &LI = AM.getResult(F); auto &ORE = AM.getResult(F); - if (!eliminateConstraints(F, DT, ORE)) + if (!eliminateConstraints(F, DT, LI, ORE)) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserve(); + PA.preserve(); PA.preserveSet(); return PA; } diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -155,6 +155,7 @@ ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O23SZ-NEXT: Running pass: ConstraintEliminationPass +; CHECK-O23SZ-NEXT: Running analysis: LoopAnalysis ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O2-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O3-NEXT: Running pass: LibCallsShrinkWrapPass @@ -163,7 +164,7 @@ ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running pass: ReassociatePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass -; CHECK-O-NEXT: Running analysis: LoopAnalysis +; CHECK-O1-NEXT: Running analysis: LoopAnalysis ; CHECK-O-NEXT: Running pass: LCSSAPass ; CHECK-O-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll --- a/llvm/test/Other/new-pm-lto-defaults.ll +++ b/llvm/test/Other/new-pm-lto-defaults.ll @@ -81,6 +81,7 @@ ; CHECK-O23SZ-NEXT: Running pass: InstCombinePass ; CHECK-EP-Peephole-NEXT: Running pass: NoOpFunctionPass ; CHECK-O23SZ-NEXT: Running pass: ConstraintEliminationPass +; CHECK-O23SZ-NEXT: Running analysis: LoopAnalysis ; CHECK-O23SZ-NEXT: Running pass: JumpThreadingPass ; CHECK-O23SZ-NEXT: Running analysis: LazyValueAnalysis ; CHECK-O23SZ-NEXT: Running pass: SROAPass on foo @@ -93,7 +94,6 @@ ; CHECK-O23SZ-NEXT: Invalidating analysis: AAManager on foo ; CHECK-O23SZ-NEXT: Running pass: OpenMPOptCGSCCPass on (foo) ; CHECK-O23SZ-NEXT: Running pass: LoopSimplifyPass on foo -; CHECK-O23SZ-NEXT: Running analysis: LoopAnalysis on foo ; CHECK-O23SZ-NEXT: Running pass: LCSSAPass on foo ; CHECK-O23SZ-NEXT: Running analysis: MemorySSAAnalysis on foo ; CHECK-O23SZ-NEXT: Running analysis: AAManager on foo diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -93,6 +93,7 @@ ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O23SZ-NEXT: Running pass: ConstraintEliminationPass +; CHECK-O23SZ-NEXT: Running analysis: LoopAnalysis ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O2-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O3-NEXT: Running pass: LibCallsShrinkWrapPass @@ -100,7 +101,7 @@ ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running pass: ReassociatePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass -; CHECK-O-NEXT: Running analysis: LoopAnalysis +; CHECK-O1-NEXT: Running analysis: LoopAnalysis ; CHECK-O-NEXT: Running pass: LCSSAPass ; CHECK-O-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll --- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll @@ -125,6 +125,7 @@ ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O23SZ-NEXT: Running pass: ConstraintEliminationPass +; CHECK-O23SZ-NEXT: Running analysis: LoopAnalysis ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O2-NEXT: Running pass: LibCallsShrinkWrapPass ; CHECK-O3-NEXT: Running pass: LibCallsShrinkWrapPass @@ -132,7 +133,7 @@ ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running pass: ReassociatePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass -; CHECK-O-NEXT: Running analysis: LoopAnalysis +; CHECK-O1-NEXT: Running analysis: LoopAnalysis ; CHECK-O-NEXT: Running pass: LCSSAPass ; CHECK-O-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy diff --git a/llvm/test/Transforms/ConstraintElimination/analysis-invalidation.ll b/llvm/test/Transforms/ConstraintElimination/analysis-invalidation.ll --- a/llvm/test/Transforms/ConstraintElimination/analysis-invalidation.ll +++ b/llvm/test/Transforms/ConstraintElimination/analysis-invalidation.ll @@ -11,6 +11,7 @@ ; CHECK-NEXT: Running analysis: TargetIRAnalysis on ssub_no_overflow_due_to_or_conds ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on ssub_no_overflow_due_to_or_conds ; CHECK-NEXT: Running pass: ConstraintEliminationPass on ssub_no_overflow_due_to_or_conds +; CHECK-NEXT: Running analysis: LoopAnalysis on ssub_no_overflow_due_to_or_conds ; CHECK-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis on ssub_no_overflow_due_to_or_conds ; CHECK-NEXT: Invalidating analysis: DemandedBitsAnalysis on ssub_no_overflow_due_to_or_conds ; CHECK-NEXT: Running pass: RequireAnalysisPass @@ -22,6 +23,7 @@ ; CHECK-NEXT: Running analysis: TargetIRAnalysis on uge_zext ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on uge_zext ; CHECK-NEXT: Running pass: ConstraintEliminationPass on uge_zext +; CHECK-NEXT: Running analysis: LoopAnalysis on uge_zext ; CHECK-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis on uge_zext ; CHECK-NEXT: Invalidating analysis: DemandedBitsAnalysis on uge_zext ; CHECK-NEXT: Running pass: RequireAnalysisPass diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll --- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll +++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll @@ -282,7 +282,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-constant-upper-offset.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-constant-upper-offset.ll --- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-constant-upper-offset.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-constant-upper-offset.ll @@ -19,7 +19,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -64,7 +64,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -109,7 +109,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -247,7 +247,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -299,7 +299,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -351,7 +351,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-custom-datalayout.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-custom-datalayout.ll --- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-custom-datalayout.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-custom-datalayout.ll @@ -75,7 +75,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -127,7 +127,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -179,7 +179,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -293,7 +293,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -352,7 +352,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -411,7 +411,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll --- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll @@ -27,7 +27,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -144,7 +144,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[END]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-struct-types.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-struct-types.ll --- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-struct-types.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-struct-types.ll @@ -24,7 +24,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -76,7 +76,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -183,7 +183,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -242,7 +242,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -360,7 +360,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -419,7 +419,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -537,7 +537,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -655,7 +655,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -714,7 +714,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -773,7 +773,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -832,7 +832,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -891,7 +891,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -950,7 +950,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -1186,7 +1186,7 @@ ; CHECK: loop.next: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll --- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll +++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll @@ -24,7 +24,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -76,7 +76,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -126,7 +126,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -175,7 +175,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -278,7 +278,7 @@ ; CHECK: for.body: ; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] ; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[END]] -; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[AND:%.*]] = and i1 true, true ; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] ; CHECK: loop.latch: ; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) @@ -1048,3 +1048,109 @@ call void @use.i1(i1 %and) ret void } + +define void @test_monotonic_ptr_iv_dec_1_eq(ptr %start, i16 %len) { +; CHECK-LABEL: @test_monotonic_ptr_iv_dec_1_eq( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]] +; CHECK-NEXT: [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]] +; CHECK: loop.ph: +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ] +; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]] +; CHECK-NEXT: br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] +; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]] +; CHECK: loop.latch: +; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) +; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 -1 +; CHECK-NEXT: br label [[LOOP_HEADER]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %upper = getelementptr inbounds i32, ptr %start, i16 %len + %len.neg = icmp slt i16 %len, 0 + br i1 %len.neg, label %exit, label %loop.ph + +loop.ph: + br label %loop.header + +loop.header: + %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ] + %c = icmp eq ptr %ptr.iv, %upper + br i1 %c, label %exit, label %for.body + +for.body: + %t.1 = icmp uge ptr %ptr.iv, %start + %t.2 = icmp ult ptr %ptr.iv, %upper + %and = and i1 %t.1, %t.2 + br i1 %and, label %loop.latch, label %exit + +loop.latch: + call void @use(ptr %ptr.iv) + %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 -1 + br label %loop.header + +exit: + ret void +} + +define void @test_monotonic_ptr_iv_step_0_cond_controls_single_exit(ptr %start, i16 %len) { +; CHECK-LABEL: @test_monotonic_ptr_iv_step_0_cond_controls_single_exit( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]] +; CHECK-NEXT: [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]] +; CHECK: loop.ph: +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ] +; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]] +; CHECK-NEXT: br i1 [[C_1]], label [[EXIT]], label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]] +; CHECK-NEXT: [[AND:%.*]] = and i1 [[T_1]], [[T_2]] +; CHECK-NEXT: call void @use.i1(i1 [[AND]]) +; CHECK-NEXT: br label [[LOOP_LATCH]] +; CHECK: loop.latch: +; CHECK-NEXT: call void @use(ptr [[PTR_IV]]) +; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 0 +; CHECK-NEXT: br label [[LOOP_HEADER]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %upper = getelementptr inbounds i32, ptr %start, i16 %len + %len.neg = icmp slt i16 %len, 0 + br i1 %len.neg, label %exit, label %loop.ph + +loop.ph: + br label %loop.header + +loop.header: + %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ] + %c.1 = icmp eq ptr %ptr.iv, %upper + br i1 %c.1, label %exit, label %for.body + +for.body: + %t.1 = icmp uge ptr %ptr.iv, %start + %t.2 = icmp ult ptr %ptr.iv, %upper + %and = and i1 %t.1, %t.2 + call void @use.i1(i1 %and) + br label %loop.latch + +loop.latch: + call void @use(ptr %ptr.iv) + %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 0 + br label %loop.header + +exit: + ret void +} diff --git a/llvm/test/Transforms/PhaseOrdering/iterator-with-runtime-check.ll b/llvm/test/Transforms/PhaseOrdering/iterator-with-runtime-check.ll --- a/llvm/test/Transforms/PhaseOrdering/iterator-with-runtime-check.ll +++ b/llvm/test/Transforms/PhaseOrdering/iterator-with-runtime-check.ll @@ -26,8 +26,8 @@ ; CHECK-NEXT: [[ELEMS_COERCE_FCA_1_EXTRACT:%.*]] = extractvalue [2 x i64] [[ELEMS_COERCE]], 1 ; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[ELEMS_COERCE_FCA_1_EXTRACT]] ; CHECK-NEXT: [[CMP_NOT_I_I_I_I:%.*]] = icmp slt i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 0 -; CHECK-NEXT: br i1 [[CMP_NOT_I_I_I_I]], label [[ERROR:%.*]], label [[FOR_COND_PREHEADER:%.*]] -; CHECK: for.cond.preheader: +; CHECK-NEXT: br i1 [[CMP_NOT_I_I_I_I]], label [[ERROR:%.*]], label [[FOR_COND_PREHEADER_SPLIT:%.*]] +; CHECK: for.cond.preheader.split: ; CHECK-NEXT: [[CMP_I_NOT2:%.*]] = icmp eq i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 0 ; CHECK-NEXT: br i1 [[CMP_I_NOT2]], label [[COMMON_RET:%.*]], label [[FOR_BODY:%.*]] ; CHECK: common.ret: @@ -36,10 +36,7 @@ ; CHECK-NEXT: tail call void @error() ; CHECK-NEXT: br label [[COMMON_RET]] ; CHECK: for.body: -; CHECK-NEXT: [[__BEGIN1_SROA_0_03:%.*]] = phi ptr [ [[INCDEC_PTR_I:%.*]], [[FOR_LATCH:%.*]] ], [ [[TMP0]], [[FOR_COND_PREHEADER]] ] -; CHECK-NEXT: [[CMP2_I_I:%.*]] = icmp ult ptr [[__BEGIN1_SROA_0_03]], [[ADD_PTR_I]] -; CHECK-NEXT: br i1 [[CMP2_I_I]], label [[FOR_LATCH]], label [[ERROR]] -; CHECK: for.latch: +; CHECK-NEXT: [[__BEGIN1_SROA_0_03:%.*]] = phi ptr [ [[INCDEC_PTR_I:%.*]], [[FOR_BODY]] ], [ [[TMP0]], [[FOR_COND_PREHEADER_SPLIT]] ] ; CHECK-NEXT: tail call void @use(ptr noundef nonnull align 4 dereferenceable(4) [[__BEGIN1_SROA_0_03]]) ; CHECK-NEXT: [[INCDEC_PTR_I]] = getelementptr inbounds i32, ptr [[__BEGIN1_SROA_0_03]], i64 1 ; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq ptr [[INCDEC_PTR_I]], [[ADD_PTR_I]]