forked from OSchip/llvm-project
diff --git a/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
index f72a808..9fa49fd 100644 --- a/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp +++ b/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp @@ -450,20 +450,10 @@ struct LoopStructure { // equivalent to: // // intN_ty inc = IndVarIncreasing ? 1 : -1; - // pred_ty predicate = IndVarIncreasing - // ? IsSignedPredicate ? ICMP_SLT : ICMP_ULT - // : IsSignedPredicate ? ICMP_SGT : ICMP_UGT; + // pred_ty predicate = IndVarIncreasing ? ICMP_SLT : ICMP_SGT; // - // - // for (intN_ty iv = IndVarStart; predicate(IndVarBase, LoopExitAt); - // iv = IndVarNext) + // for (intN_ty iv = IndVarStart; predicate(iv, LoopExitAt); iv = IndVarBase) // ... body ... - // - // Here IndVarBase is either current or next value of the induction variable. - // in the former case, IsIndVarNext = false and IndVarBase points to the - // Phi node of the induction variable. Otherwise, IsIndVarNext = true and - // IndVarBase points to IV increment instruction. - // Value *IndVarBase; Value *IndVarStart; @@ -471,13 +461,12 @@ struct LoopStructure { Value *LoopExitAt; bool IndVarIncreasing; bool IsSignedPredicate; - bool IsIndVarNext; LoopStructure() : Tag(""), Header(nullptr), Latch(nullptr), LatchBr(nullptr), LatchExit(nullptr), LatchBrExitIdx(-1), IndVarBase(nullptr), IndVarStart(nullptr), IndVarStep(nullptr), LoopExitAt(nullptr), - IndVarIncreasing(false), IsSignedPredicate(true), IsIndVarNext(false) {} + IndVarIncreasing(false), IsSignedPredicate(true) {} template <typename M> LoopStructure map(M Map) const { LoopStructure Result; @@ -493,7 +482,6 @@ struct LoopStructure { Result.LoopExitAt = Map(LoopExitAt); Result.IndVarIncreasing = IndVarIncreasing; Result.IsSignedPredicate = IsSignedPredicate; - Result.IsIndVarNext = IsIndVarNext; return Result; } @@ -841,42 +829,21 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE, return false; }; - // `ICI` can either be a comparison against IV or a comparison of IV.next. - // Depending on the interpretation, we calculate the start value differently. + // `ICI` is interpreted as taking the backedge if the *next* value of the + // induction variable satisfies some constraint. - // Pair {IndVarBase; IsIndVarNext} semantically designates whether the latch - // comparisons happens against the IV before or after its value is - // incremented. Two valid combinations for them are: - // - // 1) { phi [ iv.start, preheader ], [ iv.next, latch ]; false }, - // 2) { iv.next; true }. - // - // The latch comparison happens against IndVarBase which can be either current - // or next value of the induction variable. const SCEVAddRecExpr *IndVarBase = cast<SCEVAddRecExpr>(LeftSCEV); bool IsIncreasing = false; bool IsSignedPredicate = true; - bool IsIndVarNext = false; ConstantInt *StepCI; if (!IsInductionVar(IndVarBase, IsIncreasing, StepCI)) { FailureReason = "LHS in icmp not induction variable"; return None; } - const SCEV *IndVarStart = nullptr; - // TODO: Currently we only handle comparison against IV, but we can extend - // this analysis to be able to deal with comparison against sext(iv) and such. - if (isa<PHINode>(LeftValue) && - cast<PHINode>(LeftValue)->getParent() == Header) - // The comparison is made against current IV value. - IndVarStart = IndVarBase->getStart(); - else { - // Assume that the comparison is made against next IV value. - const SCEV *StartNext = IndVarBase->getStart(); - const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE)); - IndVarStart = SE.getAddExpr(StartNext, Addend); - IsIndVarNext = true; - } + const SCEV *StartNext = IndVarBase->getStart(); + const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE)); + const SCEV *IndVarStart = SE.getAddExpr(StartNext, Addend); const SCEV *Step = SE.getSCEV(StepCI); ConstantInt *One = ConstantInt::get(IndVarTy, 1); @@ -1060,7 +1027,6 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE, Result.IndVarIncreasing = IsIncreasing; Result.LoopExitAt = RightValue; Result.IsSignedPredicate = IsSignedPredicate; - Result.IsIndVarNext = IsIndVarNext; FailureReason = nullptr; @@ -1350,9 +1316,8 @@ LoopConstrainer::RewrittenRangeInfo LoopConstrainer::changeIterationSpaceEnd( BranchToContinuation); NewPHI->addIncoming(PN->getIncomingValueForBlock(Preheader), Preheader); - auto *FixupValue = - LS.IsIndVarNext ? PN->getIncomingValueForBlock(LS.Latch) : PN; - NewPHI->addIncoming(FixupValue, RRI.ExitSelector); + NewPHI->addIncoming(PN->getIncomingValueForBlock(LS.Latch), + RRI.ExitSelector); RRI.PHIValuesAtPseudoExit.push_back(NewPHI); } @@ -1735,10 +1700,7 @@ bool InductiveRangeCheckElimination::runOnLoop(Loop *L, LPPassManager &LPM) { } LoopStructure LS = MaybeLoopStructure.getValue(); const SCEVAddRecExpr *IndVar = - cast<SCEVAddRecExpr>(SE.getSCEV(LS.IndVarBase)); - if (LS.IsIndVarNext) - IndVar = cast<SCEVAddRecExpr>(SE.getMinusSCEV(IndVar, - SE.getSCEV(LS.IndVarStep))); + cast<SCEVAddRecExpr>(SE.getMinusSCEV(SE.getSCEV(LS.IndVarBase), SE.getSCEV(LS.IndVarStep))); Optional<InductiveRangeCheck::Range> SafeIterRange; Instruction *ExprInsertPt = Preheader->getTerminator(); diff --git a/test/Transforms/IRCE/latch-comparison-against-current-value.ll b/test/Transforms/IRCE/latch-comparison-against-current-value.ll deleted file mode 100644 index afea0e6..0000000 --- a/test/Transforms/IRCE/latch-comparison-against-current-value.ll +++ /dev/null @@ -1,182 +0,0 @@ -; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s - -; Check that IRCE is able to deal with loops where the latch comparison is -; done against current value of the IV, not the IV.next. - -; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK-NOT: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK-NOT: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> - -; SLT condition for increasing loop from 0 to 100. -define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { - -; CHECK: test_01 -; CHECK: entry: -; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0 -; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at -; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit -; CHECK: loop: -; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] -; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1 -; CHECK-NEXT: %abc = icmp slt i32 %idx, %exit.mainloop.at -; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 -; CHECK: in.bounds: -; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx -; CHECK-NEXT: store i32 0, i32* %addr -; CHECK-NEXT: %next = icmp slt i32 %idx, 100 -; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp slt i32 %idx, %exit.mainloop.at -; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector -; CHECK: main.exit.selector: -; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ] -; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp slt i32 %idx.lcssa, 100 -; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit -; CHECK-NOT: loop.preloop: -; CHECK: loop.postloop: -; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] -; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 -; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %exit.mainloop.at -; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit - -entry: - %len = load i32, i32* %a_len_ptr, !range !0 - br label %loop - -loop: - %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] - %idx.next = add nsw nuw i32 %idx, 1 - %abc = icmp slt i32 %idx, %len - br i1 %abc, label %in.bounds, label %out.of.bounds - -in.bounds: - %addr = getelementptr i32, i32* %arr, i32 %idx - store i32 0, i32* %addr - %next = icmp slt i32 %idx, 100 - br i1 %next, label %loop, label %exit - -out.of.bounds: - ret void - -exit: - ret void -} - -; ULT condition for increasing loop from 0 to 100. -define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { - -; CHECK: test_02 -; CHECK: entry: -; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0 -; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at -; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit -; CHECK: loop: -; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] -; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1 -; CHECK-NEXT: %abc = icmp ult i32 %idx, %exit.mainloop.at -; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 -; CHECK: in.bounds: -; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx -; CHECK-NEXT: store i32 0, i32* %addr -; CHECK-NEXT: %next = icmp ult i32 %idx, 100 -; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp ult i32 %idx, %exit.mainloop.at -; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector -; CHECK: main.exit.selector: -; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ] -; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp ult i32 %idx.lcssa, 100 -; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit -; CHECK-NOT: loop.preloop: -; CHECK: loop.postloop: -; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] -; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 -; CHECK-NEXT: %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at -; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit - -entry: - %len = load i32, i32* %a_len_ptr, !range !0 - br label %loop - -loop: - %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] - %idx.next = add nsw nuw i32 %idx, 1 - %abc = icmp ult i32 %idx, %len - br i1 %abc, label %in.bounds, label %out.of.bounds - -in.bounds: - %addr = getelementptr i32, i32* %arr, i32 %idx - store i32 0, i32* %addr - %next = icmp ult i32 %idx, 100 - br i1 %next, label %loop, label %exit - -out.of.bounds: - ret void - -exit: - ret void -} - -; Same as test_01, but comparison happens against IV extended to a wider type. -; This test ensures that IRCE rejects it and does not falsely assume that it was -; a comparison against iv.next. -; TODO: We can actually extend the recognition to cover this case. -define void @test_03(i32* %arr, i64* %a_len_ptr) #0 { - -; CHECK: test_03 - -entry: - %len = load i64, i64* %a_len_ptr, !range !1 - br label %loop - -loop: - %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] - %idx.next = add nsw nuw i32 %idx, 1 - %idx.ext = sext i32 %idx to i64 - %abc = icmp slt i64 %idx.ext, %len - br i1 %abc, label %in.bounds, label %out.of.bounds - -in.bounds: - %addr = getelementptr i32, i32* %arr, i32 %idx - store i32 0, i32* %addr - %next = icmp slt i32 %idx, 100 - br i1 %next, label %loop, label %exit - -out.of.bounds: - ret void - -exit: - ret void -} - -; Same as test_02, but comparison happens against IV extended to a wider type. -; This test ensures that IRCE rejects it and does not falsely assume that it was -; a comparison against iv.next. -; TODO: We can actually extend the recognition to cover this case. -define void @test_04(i32* %arr, i64* %a_len_ptr) #0 { - -; CHECK: test_04 - -entry: - %len = load i64, i64* %a_len_ptr, !range !1 - br label %loop - -loop: - %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] - %idx.next = add nsw nuw i32 %idx, 1 - %idx.ext = sext i32 %idx to i64 - %abc = icmp ult i64 %idx.ext, %len - br i1 %abc, label %in.bounds, label %out.of.bounds - -in.bounds: - %addr = getelementptr i32, i32* %arr, i32 %idx - store i32 0, i32* %addr - %next = icmp ult i32 %idx, 100 - br i1 %next, label %loop, label %exit - -out.of.bounds: - ret void - -exit: - ret void -} - -!0 = !{i32 0, i32 50} -!1 = !{i64 0, i64 50} llvm-svn: 312775
This commit is contained in:
parent
086b6682dd
commit
57db44838d
|
@ -450,20 +450,10 @@ struct LoopStructure {
|
|||
// equivalent to:
|
||||
//
|
||||
// intN_ty inc = IndVarIncreasing ? 1 : -1;
|
||||
// pred_ty predicate = IndVarIncreasing
|
||||
// ? IsSignedPredicate ? ICMP_SLT : ICMP_ULT
|
||||
// : IsSignedPredicate ? ICMP_SGT : ICMP_UGT;
|
||||
// pred_ty predicate = IndVarIncreasing ? ICMP_SLT : ICMP_SGT;
|
||||
//
|
||||
//
|
||||
// for (intN_ty iv = IndVarStart; predicate(IndVarBase, LoopExitAt);
|
||||
// iv = IndVarNext)
|
||||
// for (intN_ty iv = IndVarStart; predicate(iv, LoopExitAt); iv = IndVarBase)
|
||||
// ... body ...
|
||||
//
|
||||
// Here IndVarBase is either current or next value of the induction variable.
|
||||
// in the former case, IsIndVarNext = false and IndVarBase points to the
|
||||
// Phi node of the induction variable. Otherwise, IsIndVarNext = true and
|
||||
// IndVarBase points to IV increment instruction.
|
||||
//
|
||||
|
||||
Value *IndVarBase;
|
||||
Value *IndVarStart;
|
||||
|
@ -471,13 +461,12 @@ struct LoopStructure {
|
|||
Value *LoopExitAt;
|
||||
bool IndVarIncreasing;
|
||||
bool IsSignedPredicate;
|
||||
bool IsIndVarNext;
|
||||
|
||||
LoopStructure()
|
||||
: Tag(""), Header(nullptr), Latch(nullptr), LatchBr(nullptr),
|
||||
LatchExit(nullptr), LatchBrExitIdx(-1), IndVarBase(nullptr),
|
||||
IndVarStart(nullptr), IndVarStep(nullptr), LoopExitAt(nullptr),
|
||||
IndVarIncreasing(false), IsSignedPredicate(true), IsIndVarNext(false) {}
|
||||
IndVarIncreasing(false), IsSignedPredicate(true) {}
|
||||
|
||||
template <typename M> LoopStructure map(M Map) const {
|
||||
LoopStructure Result;
|
||||
|
@ -493,7 +482,6 @@ struct LoopStructure {
|
|||
Result.LoopExitAt = Map(LoopExitAt);
|
||||
Result.IndVarIncreasing = IndVarIncreasing;
|
||||
Result.IsSignedPredicate = IsSignedPredicate;
|
||||
Result.IsIndVarNext = IsIndVarNext;
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -841,42 +829,21 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE,
|
|||
return false;
|
||||
};
|
||||
|
||||
// `ICI` can either be a comparison against IV or a comparison of IV.next.
|
||||
// Depending on the interpretation, we calculate the start value differently.
|
||||
// `ICI` is interpreted as taking the backedge if the *next* value of the
|
||||
// induction variable satisfies some constraint.
|
||||
|
||||
// Pair {IndVarBase; IsIndVarNext} semantically designates whether the latch
|
||||
// comparisons happens against the IV before or after its value is
|
||||
// incremented. Two valid combinations for them are:
|
||||
//
|
||||
// 1) { phi [ iv.start, preheader ], [ iv.next, latch ]; false },
|
||||
// 2) { iv.next; true }.
|
||||
//
|
||||
// The latch comparison happens against IndVarBase which can be either current
|
||||
// or next value of the induction variable.
|
||||
const SCEVAddRecExpr *IndVarBase = cast<SCEVAddRecExpr>(LeftSCEV);
|
||||
bool IsIncreasing = false;
|
||||
bool IsSignedPredicate = true;
|
||||
bool IsIndVarNext = false;
|
||||
ConstantInt *StepCI;
|
||||
if (!IsInductionVar(IndVarBase, IsIncreasing, StepCI)) {
|
||||
FailureReason = "LHS in icmp not induction variable";
|
||||
return None;
|
||||
}
|
||||
|
||||
const SCEV *IndVarStart = nullptr;
|
||||
// TODO: Currently we only handle comparison against IV, but we can extend
|
||||
// this analysis to be able to deal with comparison against sext(iv) and such.
|
||||
if (isa<PHINode>(LeftValue) &&
|
||||
cast<PHINode>(LeftValue)->getParent() == Header)
|
||||
// The comparison is made against current IV value.
|
||||
IndVarStart = IndVarBase->getStart();
|
||||
else {
|
||||
// Assume that the comparison is made against next IV value.
|
||||
const SCEV *StartNext = IndVarBase->getStart();
|
||||
const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE));
|
||||
IndVarStart = SE.getAddExpr(StartNext, Addend);
|
||||
IsIndVarNext = true;
|
||||
}
|
||||
const SCEV *StartNext = IndVarBase->getStart();
|
||||
const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE));
|
||||
const SCEV *IndVarStart = SE.getAddExpr(StartNext, Addend);
|
||||
const SCEV *Step = SE.getSCEV(StepCI);
|
||||
|
||||
ConstantInt *One = ConstantInt::get(IndVarTy, 1);
|
||||
|
@ -1060,7 +1027,6 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE,
|
|||
Result.IndVarIncreasing = IsIncreasing;
|
||||
Result.LoopExitAt = RightValue;
|
||||
Result.IsSignedPredicate = IsSignedPredicate;
|
||||
Result.IsIndVarNext = IsIndVarNext;
|
||||
|
||||
FailureReason = nullptr;
|
||||
|
||||
|
@ -1350,9 +1316,8 @@ LoopConstrainer::RewrittenRangeInfo LoopConstrainer::changeIterationSpaceEnd(
|
|||
BranchToContinuation);
|
||||
|
||||
NewPHI->addIncoming(PN->getIncomingValueForBlock(Preheader), Preheader);
|
||||
auto *FixupValue =
|
||||
LS.IsIndVarNext ? PN->getIncomingValueForBlock(LS.Latch) : PN;
|
||||
NewPHI->addIncoming(FixupValue, RRI.ExitSelector);
|
||||
NewPHI->addIncoming(PN->getIncomingValueForBlock(LS.Latch),
|
||||
RRI.ExitSelector);
|
||||
RRI.PHIValuesAtPseudoExit.push_back(NewPHI);
|
||||
}
|
||||
|
||||
|
@ -1735,10 +1700,7 @@ bool InductiveRangeCheckElimination::runOnLoop(Loop *L, LPPassManager &LPM) {
|
|||
}
|
||||
LoopStructure LS = MaybeLoopStructure.getValue();
|
||||
const SCEVAddRecExpr *IndVar =
|
||||
cast<SCEVAddRecExpr>(SE.getSCEV(LS.IndVarBase));
|
||||
if (LS.IsIndVarNext)
|
||||
IndVar = cast<SCEVAddRecExpr>(SE.getMinusSCEV(IndVar,
|
||||
SE.getSCEV(LS.IndVarStep)));
|
||||
cast<SCEVAddRecExpr>(SE.getMinusSCEV(SE.getSCEV(LS.IndVarBase), SE.getSCEV(LS.IndVarStep)));
|
||||
|
||||
Optional<InductiveRangeCheck::Range> SafeIterRange;
|
||||
Instruction *ExprInsertPt = Preheader->getTerminator();
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
|
||||
|
||||
; Check that IRCE is able to deal with loops where the latch comparison is
|
||||
; done against current value of the IV, not the IV.next.
|
||||
|
||||
; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
|
||||
; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
|
||||
; CHECK-NOT: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
|
||||
; CHECK-NOT: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
|
||||
|
||||
; SLT condition for increasing loop from 0 to 100.
|
||||
define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
|
||||
|
||||
; CHECK: test_01
|
||||
; CHECK: entry:
|
||||
; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
|
||||
; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
|
||||
; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1
|
||||
; CHECK-NEXT: %abc = icmp slt i32 %idx, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
|
||||
; CHECK: in.bounds:
|
||||
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
; CHECK-NEXT: store i32 0, i32* %addr
|
||||
; CHECK-NEXT: %next = icmp slt i32 %idx, 100
|
||||
; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp slt i32 %idx, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector
|
||||
; CHECK: main.exit.selector:
|
||||
; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ]
|
||||
; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp slt i32 %idx.lcssa, 100
|
||||
; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit
|
||||
; CHECK-NOT: loop.preloop:
|
||||
; CHECK: loop.postloop:
|
||||
; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
|
||||
; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
|
||||
; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
|
||||
|
||||
entry:
|
||||
%len = load i32, i32* %a_len_ptr, !range !0
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
|
||||
%idx.next = add nsw nuw i32 %idx, 1
|
||||
%abc = icmp slt i32 %idx, %len
|
||||
br i1 %abc, label %in.bounds, label %out.of.bounds
|
||||
|
||||
in.bounds:
|
||||
%addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
store i32 0, i32* %addr
|
||||
%next = icmp slt i32 %idx, 100
|
||||
br i1 %next, label %loop, label %exit
|
||||
|
||||
out.of.bounds:
|
||||
ret void
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; ULT condition for increasing loop from 0 to 100.
|
||||
define void @test_02(i32* %arr, i32* %a_len_ptr) #0 {
|
||||
|
||||
; CHECK: test_02
|
||||
; CHECK: entry:
|
||||
; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
|
||||
; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
|
||||
; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1
|
||||
; CHECK-NEXT: %abc = icmp ult i32 %idx, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
|
||||
; CHECK: in.bounds:
|
||||
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
; CHECK-NEXT: store i32 0, i32* %addr
|
||||
; CHECK-NEXT: %next = icmp ult i32 %idx, 100
|
||||
; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp ult i32 %idx, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector
|
||||
; CHECK: main.exit.selector:
|
||||
; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ]
|
||||
; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp ult i32 %idx.lcssa, 100
|
||||
; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit
|
||||
; CHECK-NOT: loop.preloop:
|
||||
; CHECK: loop.postloop:
|
||||
; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
|
||||
; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
|
||||
; CHECK-NEXT: %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at
|
||||
; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
|
||||
|
||||
entry:
|
||||
%len = load i32, i32* %a_len_ptr, !range !0
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
|
||||
%idx.next = add nsw nuw i32 %idx, 1
|
||||
%abc = icmp ult i32 %idx, %len
|
||||
br i1 %abc, label %in.bounds, label %out.of.bounds
|
||||
|
||||
in.bounds:
|
||||
%addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
store i32 0, i32* %addr
|
||||
%next = icmp ult i32 %idx, 100
|
||||
br i1 %next, label %loop, label %exit
|
||||
|
||||
out.of.bounds:
|
||||
ret void
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same as test_01, but comparison happens against IV extended to a wider type.
|
||||
; This test ensures that IRCE rejects it and does not falsely assume that it was
|
||||
; a comparison against iv.next.
|
||||
; TODO: We can actually extend the recognition to cover this case.
|
||||
define void @test_03(i32* %arr, i64* %a_len_ptr) #0 {
|
||||
|
||||
; CHECK: test_03
|
||||
|
||||
entry:
|
||||
%len = load i64, i64* %a_len_ptr, !range !1
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
|
||||
%idx.next = add nsw nuw i32 %idx, 1
|
||||
%idx.ext = sext i32 %idx to i64
|
||||
%abc = icmp slt i64 %idx.ext, %len
|
||||
br i1 %abc, label %in.bounds, label %out.of.bounds
|
||||
|
||||
in.bounds:
|
||||
%addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
store i32 0, i32* %addr
|
||||
%next = icmp slt i32 %idx, 100
|
||||
br i1 %next, label %loop, label %exit
|
||||
|
||||
out.of.bounds:
|
||||
ret void
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same as test_02, but comparison happens against IV extended to a wider type.
|
||||
; This test ensures that IRCE rejects it and does not falsely assume that it was
|
||||
; a comparison against iv.next.
|
||||
; TODO: We can actually extend the recognition to cover this case.
|
||||
define void @test_04(i32* %arr, i64* %a_len_ptr) #0 {
|
||||
|
||||
; CHECK: test_04
|
||||
|
||||
entry:
|
||||
%len = load i64, i64* %a_len_ptr, !range !1
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
|
||||
%idx.next = add nsw nuw i32 %idx, 1
|
||||
%idx.ext = sext i32 %idx to i64
|
||||
%abc = icmp ult i64 %idx.ext, %len
|
||||
br i1 %abc, label %in.bounds, label %out.of.bounds
|
||||
|
||||
in.bounds:
|
||||
%addr = getelementptr i32, i32* %arr, i32 %idx
|
||||
store i32 0, i32* %addr
|
||||
%next = icmp ult i32 %idx, 100
|
||||
br i1 %next, label %loop, label %exit
|
||||
|
||||
out.of.bounds:
|
||||
ret void
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
!0 = !{i32 0, i32 50}
|
||||
!1 = !{i64 0, i64 50}
|
Loading…
Reference in New Issue