[SCEV] Use context to strengthen flags of BinOps
Sometimes SCEV cannot infer nuw/nsw from something as simple as ``` len in [0, MAX_INT] ... iv = phi(0, iv.next) guard(iv <s len) guard(iv <u len) iv.next = iv + 1 ``` just because flag strenthening only relies on definition and does not use local facts. This patch adds support for the simplest case: inference of flags of `add(x, constant)` if we can contextually prove that `x <= max_int - constant`. In case if it has negative CT impact, we can add an option to switch it off. I woudln't expect that though. Differential Revision: https://reviews.llvm.org/D129643 Reviewed By: apilipenko
This commit is contained in:
parent
817dd5e3fd
commit
34ae308c73
|
@ -529,9 +529,11 @@ public:
|
|||
bool containsAddRecurrence(const SCEV *S);
|
||||
|
||||
/// Is operation \p BinOp between \p LHS and \p RHS provably does not have
|
||||
/// a signed/unsigned overflow (\p Signed)?
|
||||
/// a signed/unsigned overflow (\p Signed)? If \p CtxI is specified, the
|
||||
/// no-overflow fact should be true in the context of this instruction.
|
||||
bool willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const Instruction *CtxI = nullptr);
|
||||
|
||||
/// Parse NSW/NUW flags from add/sub/mul IR binary operation \p Op into
|
||||
/// SCEV no-wrap flags, and deduce flag[s] that aren't known yet.
|
||||
|
|
|
@ -242,6 +242,11 @@ static cl::opt<bool>
|
|||
cl::desc("Handle <= and >= in finite loops"),
|
||||
cl::init(true));
|
||||
|
||||
static cl::opt<bool> UseContextForNoWrapFlagInference(
|
||||
"scalar-evolution-use-context-for-no-wrap-flag-strenghening", cl::Hidden,
|
||||
cl::desc("Infer nuw/nsw flags using context where suitable"),
|
||||
cl::init(true));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SCEV class definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2285,7 +2290,8 @@ CollectAddOperandsWithScales(DenseMap<const SCEV *, APInt> &M,
|
|||
}
|
||||
|
||||
bool ScalarEvolution::willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
|
||||
const SCEV *LHS, const SCEV *RHS) {
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const Instruction *CtxI) {
|
||||
const SCEV *(ScalarEvolution::*Operation)(const SCEV *, const SCEV *,
|
||||
SCEV::NoWrapFlags, unsigned);
|
||||
switch (BinOp) {
|
||||
|
@ -2316,7 +2322,30 @@ bool ScalarEvolution::willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
|
|||
const SCEV *LHSB = (this->*Extension)(LHS, WideTy, 0);
|
||||
const SCEV *RHSB = (this->*Extension)(RHS, WideTy, 0);
|
||||
const SCEV *B = (this->*Operation)(LHSB, RHSB, SCEV::FlagAnyWrap, 0);
|
||||
return A == B;
|
||||
if (A == B)
|
||||
return true;
|
||||
// Can we use context to prove the fact we need?
|
||||
if (!CtxI)
|
||||
return false;
|
||||
// We can prove that add(x, constant) doesn't wrap if isKnownPredicateAt can
|
||||
// guarantee that x <= max_int - constant at the given context.
|
||||
// TODO: Support other operations.
|
||||
if (BinOp != Instruction::Add)
|
||||
return false;
|
||||
auto *RHSC = dyn_cast<SCEVConstant>(RHS);
|
||||
// TODO: Lift this limitation.
|
||||
if (!RHSC)
|
||||
return false;
|
||||
APInt C = RHSC->getAPInt();
|
||||
// TODO: Also lift this limitation.
|
||||
if (Signed && C.isNegative())
|
||||
return false;
|
||||
unsigned NumBits = C.getBitWidth();
|
||||
APInt Max =
|
||||
Signed ? APInt::getSignedMaxValue(NumBits) : APInt::getMaxValue(NumBits);
|
||||
APInt Limit = Max - C;
|
||||
ICmpInst::Predicate Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
|
||||
return isKnownPredicateAt(Pred, LHS, getConstant(Limit), CtxI);
|
||||
}
|
||||
|
||||
Optional<SCEV::NoWrapFlags>
|
||||
|
@ -2343,16 +2372,18 @@ ScalarEvolution::getStrengthenedNoWrapFlagsFromBinOp(
|
|||
const SCEV *LHS = getSCEV(OBO->getOperand(0));
|
||||
const SCEV *RHS = getSCEV(OBO->getOperand(1));
|
||||
|
||||
const Instruction *CtxI =
|
||||
UseContextForNoWrapFlagInference ? dyn_cast<Instruction>(OBO) : nullptr;
|
||||
if (!OBO->hasNoUnsignedWrap() &&
|
||||
willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
|
||||
/* Signed */ false, LHS, RHS)) {
|
||||
/* Signed */ false, LHS, RHS, CtxI)) {
|
||||
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
|
||||
Deduced = true;
|
||||
}
|
||||
|
||||
if (!OBO->hasNoSignedWrap() &&
|
||||
willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
|
||||
/* Signed */ true, LHS, RHS)) {
|
||||
/* Signed */ true, LHS, RHS, CtxI)) {
|
||||
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
|
||||
Deduced = true;
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ define i32 @test5(i32* %a, i32 %b) {
|
|||
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i64 [[INDVARS_IV]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
|
||||
; CHECK-NEXT: [[ADD]] = add nsw i32 [[SUM_0]], [[TMP1]]
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw i64 [[INDVARS_IV]], 1
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
||||
; CHECK-NEXT: br label [[FOR_COND]]
|
||||
; CHECK: for.end:
|
||||
; CHECK-NEXT: [[SUM_0_LCSSA:%.*]] = phi i32 [ [[SUM_0]], [[FOR_COND]] ]
|
||||
|
@ -410,7 +410,7 @@ define i32 @test8(i32* %a, i32 %b, i32 %init) {
|
|||
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i64 [[INDVARS_IV]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
|
||||
; CHECK-NEXT: [[ADD]] = add nsw i32 [[SUM_0]], [[TMP2]]
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add i64 [[INDVARS_IV]], 1
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i64 0, [[INDVARS_IV_NEXT]]
|
||||
; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_COND]], label [[FOR_END]]
|
||||
; CHECK: for.end:
|
||||
|
|
|
@ -75,7 +75,7 @@ define void @loop_0_dead(i32* %a) {
|
|||
; CHECK-NEXT: br label [[B18:%.*]]
|
||||
; CHECK: B18:
|
||||
; CHECK-NEXT: [[DOT02:%.*]] = phi i32 [ [[TMP33:%.*]], [[B24:%.*]] ], [ 0, [[B18_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[TMP33]] = add nuw i32 [[DOT02]], 1
|
||||
; CHECK-NEXT: [[TMP33]] = add nuw nsw i32 [[DOT02]], 1
|
||||
; CHECK-NEXT: [[O:%.*]] = getelementptr i32, i32* [[A:%.*]], i32 [[DOT02]]
|
||||
; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[O]], align 4
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp eq i32 [[V]], 0
|
||||
|
@ -167,11 +167,11 @@ define void @loop_2(i32 %size, i32 %nsteps, i32 %hsize, i32* %lined, i8 %tmp1) {
|
|||
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[SIZE]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[HSIZE:%.*]] to i64
|
||||
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[NSTEPS:%.*]], i32 1)
|
||||
; CHECK-NEXT: [[WIDE_TRIP_COUNT11:%.*]] = zext i32 [[SMAX]] to i64
|
||||
; CHECK-NEXT: [[WIDE_TRIP_COUNT14:%.*]] = zext i32 [[SMAX]] to i64
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[INDVARS_IV7:%.*]] = phi i64 [ [[INDVARS_IV_NEXT8:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i64 [[INDVARS_IV7]], [[TMP0]]
|
||||
; CHECK-NEXT: [[INDVARS_IV9:%.*]] = phi i64 [ [[INDVARS_IV_NEXT10:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i64 [[INDVARS_IV9]], [[TMP0]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i64 [[TMP2]], [[TMP1]]
|
||||
; CHECK-NEXT: br i1 [[CMP215]], label [[FOR_BODY2_PREHEADER:%.*]], label [[FOR_INC]]
|
||||
; CHECK: for.body2.preheader:
|
||||
|
@ -188,22 +188,22 @@ define void @loop_2(i32 %size, i32 %nsteps, i32 %hsize, i32* %lined, i8 %tmp1) {
|
|||
; CHECK: for.body3.preheader:
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP3]] to i32
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64
|
||||
; CHECK-NEXT: [[WIDE_TRIP_COUNT5:%.*]] = zext i32 [[SIZE]] to i64
|
||||
; CHECK-NEXT: [[WIDE_TRIP_COUNT7:%.*]] = zext i32 [[SIZE]] to i64
|
||||
; CHECK-NEXT: br label [[FOR_BODY3:%.*]]
|
||||
; CHECK: for.body3:
|
||||
; CHECK-NEXT: [[INDVARS_IV2:%.*]] = phi i64 [ 1, [[FOR_BODY3_PREHEADER]] ], [ [[INDVARS_IV_NEXT3:%.*]], [[FOR_BODY3]] ]
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP6]], [[INDVARS_IV2]]
|
||||
; CHECK-NEXT: [[INDVARS_IV3:%.*]] = phi i64 [ 1, [[FOR_BODY3_PREHEADER]] ], [ [[INDVARS_IV_NEXT4:%.*]], [[FOR_BODY3]] ]
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP6]], [[INDVARS_IV3]]
|
||||
; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i8, i8* [[BC0]], i64 [[TMP7]]
|
||||
; CHECK-NEXT: store i8 [[TMP1]], i8* [[ADD_PTR2]], align 1
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT3]] = add nuw nsw i64 [[INDVARS_IV2]], 1
|
||||
; CHECK-NEXT: [[EXITCOND6:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT3]], [[WIDE_TRIP_COUNT5]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND6]], label [[FOR_BODY3]], label [[FOR_INC_LOOPEXIT:%.*]]
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT4]] = add nuw nsw i64 [[INDVARS_IV3]], 1
|
||||
; CHECK-NEXT: [[EXITCOND8:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT4]], [[WIDE_TRIP_COUNT7]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND8]], label [[FOR_BODY3]], label [[FOR_INC_LOOPEXIT:%.*]]
|
||||
; CHECK: for.inc.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_INC]]
|
||||
; CHECK: for.inc:
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT8]] = add nuw nsw i64 [[INDVARS_IV7]], 1
|
||||
; CHECK-NEXT: [[EXITCOND12:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT8]], [[WIDE_TRIP_COUNT11]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND12]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT10]] = add nuw nsw i64 [[INDVARS_IV9]], 1
|
||||
; CHECK-NEXT: [[EXITCOND15:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT10]], [[WIDE_TRIP_COUNT14]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND15]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
|
||||
; CHECK: for.end.loopexit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
|
@ -77,17 +77,10 @@ define i32 @testRem(i8* %p, i64* %p1) {
|
|||
; CHECK: general_case24:
|
||||
; CHECK-NEXT: br i1 false, label [[LOOP2_PREHEADER:%.*]], label [[LOOP2_EXIT]]
|
||||
; CHECK: loop2.preheader:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = udiv i32 14, [[LOCAL_0_]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = udiv i32 60392, [[TMP0]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], -1
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], [[TMP0]]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = sext i32 [[TMP3]] to i64
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = add nsw i64 [[TMP4]], 60392
|
||||
; CHECK-NEXT: br label [[LOOP2:%.*]]
|
||||
; CHECK: loop2:
|
||||
; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = add nsw i64 [[TMP5]], -1
|
||||
; CHECK-NEXT: [[I4:%.*]] = load atomic i64, i64* [[P1:%.*]] unordered, align 8
|
||||
; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], [[INDVARS_IV_NEXT]]
|
||||
; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], -1
|
||||
; CHECK-NEXT: store atomic i64 [[I6]], i64* [[P1]] unordered, align 8
|
||||
; CHECK-NEXT: br i1 true, label [[LOOP2_EXIT_LOOPEXIT:%.*]], label [[LOOP2]]
|
||||
; CHECK: loop2.exit.loopexit:
|
||||
|
|
|
@ -19,7 +19,7 @@ define void @f() {
|
|||
; CHECK-NEXT: br label [[FOR_BODY2:%.*]]
|
||||
; CHECK: for.body2:
|
||||
; CHECK-NEXT: [[INC2:%.*]] = phi i16 [ undef, [[FOR_BODY]] ], [ [[INC:%.*]], [[FOR_BODY2]] ]
|
||||
; CHECK-NEXT: [[INC]] = add nsw i16 [[INC2]], 1
|
||||
; CHECK-NEXT: [[INC]] = add nuw nsw i16 [[INC2]], 1
|
||||
; CHECK-NEXT: store i16 [[INC]], i16* undef, align 1
|
||||
; CHECK-NEXT: br i1 true, label [[FOR_BODY2]], label [[CRIT_EDGE:%.*]]
|
||||
; CHECK: crit_edge:
|
||||
|
|
|
@ -85,7 +85,7 @@ define i32 @unknown.start(i32 %start, i32* %len.ptr) {
|
|||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
||||
; CHECK: failed.signed:
|
||||
|
@ -161,7 +161,7 @@ define i32 @start.from.sibling.iv(i32* %len.ptr, i32* %sibling.len.ptr) {
|
|||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
||||
; CHECK: failed.signed:
|
||||
|
@ -252,7 +252,7 @@ define i32 @start.from.sibling.iv.wide(i32* %len.ptr, i32* %sibling.len.ptr) {
|
|||
; CHECK: signed.passed:
|
||||
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
||||
; CHECK: failed.signed:
|
||||
|
@ -352,7 +352,7 @@ define i32 @start.from.sibling.iv.wide.cycled.phis(i32* %len.ptr, i32* %sibling.
|
|||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_BACKEDGE]]
|
||||
; CHECK: outer.loop.backedge:
|
||||
|
@ -470,7 +470,7 @@ define i32 @start.from.sibling.iv.wide.cycled.phis.complex.phis(i32* %len.ptr, i
|
|||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_SELECTION:%.*]]
|
||||
; CHECK: outer.loop.selection:
|
||||
|
|
|
@ -638,7 +638,7 @@ define i1 @func_18(i16* %tmp20, i32* %len.addr) {
|
|||
; CHECK-NEXT: [[TMP29:%.*]] = icmp eq i16 [[TMP26]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP29]], label [[BB1]], label [[BB2_LOOPEXIT]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[TMP30]] = add nuw i32 [[VAR_1]], 1
|
||||
; CHECK-NEXT: [[TMP30]] = add nuw nsw i32 [[VAR_1]], 1
|
||||
; CHECK-NEXT: [[TMP31:%.*]] = icmp eq i32 [[VAR_0]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP31]], label [[BB3:%.*]], label [[BB0]]
|
||||
; CHECK: bb2.loopexit:
|
||||
|
@ -1003,7 +1003,7 @@ define i32 @func_26(i32 %start) {
|
|||
; CHECK: checked.2:
|
||||
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 758394
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 758394
|
||||
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond_func()
|
||||
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
||||
; CHECK: fail:
|
||||
|
@ -1055,7 +1055,7 @@ define i32 @func_27(i32 %start) {
|
|||
; CHECK: checked.2:
|
||||
; CHECK-NEXT: br i1 [[C3]], label [[BACKEDGE]], label [[FAIL]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 758394
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 758394
|
||||
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond_func()
|
||||
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
||||
; CHECK: fail:
|
||||
|
|
|
@ -1029,7 +1029,7 @@ define void @slt_guarded_rhs(i16 %n) mustprogress {
|
|||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
|
||||
; CHECK: for.end.loopexit:
|
||||
|
|
|
@ -611,7 +611,7 @@ define i32 @unconditional_latch_with_side_effect(i32* %a, i32 %length) {
|
|||
; CHECK-NEXT: ret i32 -1
|
||||
; CHECK: guarded:
|
||||
; CHECK-NEXT: store volatile i32 0, i32* [[A:%.*]], align 4
|
||||
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
|
||||
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
|
||||
; CHECK-NEXT: br label [[LOOP]]
|
||||
;
|
||||
loop.preheader:
|
||||
|
|
|
@ -17,7 +17,7 @@ define void @test_01(i32 %x) {
|
|||
; CHECK-NEXT: [[CHECK_1:%.*]] = icmp slt i32 [[IV_1]], [[X:%.*]]
|
||||
; CHECK-NEXT: br i1 [[CHECK_1]], label [[GUARDED_1]], label [[FAIL_LOOPEXIT:%.*]]
|
||||
; CHECK: guarded.1:
|
||||
; CHECK-NEXT: [[IV_NEXT_1]] = add nuw i32 [[IV_1]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT_1]] = add nuw nsw i32 [[IV_1]], 1
|
||||
; CHECK-NEXT: [[LOOP_COND_1:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[LOOP_COND_1]], label [[LOOP_1]], label [[EXIT_LOOPEXIT:%.*]]
|
||||
; CHECK: loop.2:
|
||||
|
@ -86,7 +86,7 @@ define void @test_02(i32 %x) {
|
|||
; CHECK-NEXT: [[CHECK_2:%.*]] = icmp slt i32 [[IV_2]], [[X:%.*]]
|
||||
; CHECK-NEXT: br i1 [[CHECK_2]], label [[GUARDED_2]], label [[FAIL_LOOPEXIT1:%.*]]
|
||||
; CHECK: guarded.2:
|
||||
; CHECK-NEXT: [[IV_NEXT_2]] = add nuw i32 [[IV_2]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT_2]] = add nuw nsw i32 [[IV_2]], 1
|
||||
; CHECK-NEXT: [[LOOP_COND_2:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[LOOP_COND_2]], label [[LOOP_2]], label [[EXIT_LOOPEXIT2:%.*]]
|
||||
; CHECK: exit.loopexit:
|
||||
|
|
|
@ -3147,7 +3147,7 @@ define void @unique_exit(i32 %N, i32 %M) {
|
|||
; EPILOG-NEXT: %cmp1.7 = icmp ult i32 %inc.7, %N
|
||||
; EPILOG-NEXT: br i1 %cmp1.7, label %latch.7, label %latchExit.epilog-lcssa.loopexit
|
||||
; EPILOG: latch.7:
|
||||
; EPILOG-NEXT: %niter.next.7 = add i32 %niter.next.6, 1
|
||||
; EPILOG-NEXT: %niter.next.7 = add nuw i32 %niter.next.6, 1
|
||||
; EPILOG-NEXT: %niter.ncmp.7 = icmp ne i32 %niter.next.7, %unroll_iter
|
||||
; EPILOG-NEXT: br i1 %niter.ncmp.7, label %header, label %latchExit.unr-lcssa.loopexit
|
||||
; EPILOG: latchExit.unr-lcssa.loopexit:
|
||||
|
@ -3209,7 +3209,7 @@ define void @unique_exit(i32 %N, i32 %M) {
|
|||
; EPILOG-BLOCK-NEXT: %cmp1.1 = icmp ult i32 %inc.1, %N
|
||||
; EPILOG-BLOCK-NEXT: br i1 %cmp1.1, label %latch.1, label %latchExit.epilog-lcssa.loopexit
|
||||
; EPILOG-BLOCK: latch.1:
|
||||
; EPILOG-BLOCK-NEXT: %niter.next.1 = add i32 %niter.next, 1
|
||||
; EPILOG-BLOCK-NEXT: %niter.next.1 = add nuw i32 %niter.next, 1
|
||||
; EPILOG-BLOCK-NEXT: %niter.ncmp.1 = icmp ne i32 %niter.next.1, %unroll_iter
|
||||
; EPILOG-BLOCK-NEXT: br i1 %niter.ncmp.1, label %header, label %latchExit.unr-lcssa.loopexit, !llvm.loop !8
|
||||
; EPILOG-BLOCK: latchExit.unr-lcssa.loopexit:
|
||||
|
|
Loading…
Reference in New Issue