llvm.org GIT mirror llvm / c35c115
[LoopPredication] Handle the case when the guard and the latch IV have different offsets This is a follow up change for D37569. Currently the transformation is limited to the case when: * The loop has a single latch with the condition of the form: ++i <pred> latchLimit, where <pred> is u<, u<=, s<, or s<=. * The step of the IV used in the latch condition is 1. * The IV of the latch condition is the same as the post increment IV of the guard condition. * The guard condition is of the form i u< guardLimit. This patch enables the transform in the case when the latch is latchStart + i <pred> latchLimit, where <pred> is u<, u<=, s<, or s<=. And the guard is guardStart + i u< guardLimit Reviewed By: anna Differential Revision: https://reviews.llvm.org/D39097 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316768 91177308-0d34-0410-b5e6-96231b3b80d8 Artur Pilipenko 1 year, 10 months ago
2 changed file(s) with 328 addition(s) and 71 deletion(s). Raw diff Collapse all Expand all
5252 // One of the ways to reason about this problem is to use an inductive proof
5353 // approach. Given the loop:
5454 //
55 // if (B(Start)) {
55 // if (B(0)) {
5656 // do {
57 // I = PHI(Start, I.INC)
57 // I = PHI(0, I.INC)
5858 // I.INC = I + Step
5959 // guard(G(I));
60 // } while (B(I.INC));
60 // } while (B(I));
6161 // }
6262 //
6363 // where B(x) and G(x) are predicates that map integers to booleans, we want a
6464 // loop invariant expression M such the following program has the same semantics
6565 // as the above:
6666 //
67 // if (B(Start)) {
67 // if (B(0)) {
6868 // do {
69 // I = PHI(Start, I.INC)
69 // I = PHI(0, I.INC)
7070 // I.INC = I + Step
71 // guard(G(Start) && M);
72 // } while (B(I.INC));
71 // guard(G(0) && M);
72 // } while (B(I));
7373 // }
7474 //
75 // One solution for M is M = forall X . (G(X) && B(X + Step)) => G(X + Step)
75 // One solution for M is M = forall X . (G(X) && B(X)) => G(X + Step)
7676 //
7777 // Informal proof that the transformation above is correct:
7878 //
7979 // By the definition of guards we can rewrite the guard condition to:
80 // G(I) && G(Start) && M
80 // G(I) && G(0) && M
8181 //
8282 // Let's prove that for each iteration of the loop:
83 // G(Start) && M => G(I)
83 // G(0) && M => G(I)
8484 // And the condition above can be simplified to G(Start) && M.
8585 //
8686 // Induction base.
87 // G(Start) && M => G(Start)
88 //
89 // Induction step. Assuming G(Start) && M => G(I) on the subsequent
87 // G(0) && M => G(0)
88 //
89 // Induction step. Assuming G(0) && M => G(I) on the subsequent
9090 // iteration:
9191 //
92 // B(I + Step) is true because it's the backedge condition.
92 // B(I) is true because it's the backedge condition.
9393 // G(I) is true because the backedge is guarded by this condition.
9494 //
95 // So M = forall X . (G(X) && B(X + Step)) => G(X + Step) implies
96 // G(I + Step).
95 // So M = forall X . (G(X) && B(X)) => G(X + Step) implies G(I + Step).
9796 //
9897 // Note that we can use anything stronger than M, i.e. any condition which
9998 // implies M.
10099 //
101100 // For now the transformation is limited to the following case:
102101 // * The loop has a single latch with the condition of the form:
103 // ++i latchLimit, where is u<, u<=, s<, or s<=.
102 // B(X) = latchStart + X latchLimit,
103 // where is u<, u<=, s<, or s<=.
104104 // * The step of the IV used in the latch condition is 1.
105 // * The IV of the latch condition is the same as the post increment IV of the
106 // guard condition.
107 // * The guard condition is
108 // i u< guardLimit.
105 // * The guard condition is of the form
106 // G(X) = guardStart + X u< guardLimit
109107 //
110108 // For the ult latch comparison case M is:
111 // forall X . X u< guardLimit && (X + 1) u< latchLimit =>
112 // (X + 1) u< guardLimit
113 //
114 // This is true if latchLimit u<= guardLimit since then
115 // (X + 1) u< latchLimit u<= guardLimit == (X + 1) u< guardLimit.
116 //
117 // So for ult condition the widened condition is:
118 // i.start u< guardLimit && latchLimit u<= guardLimit
119 // Similarly for ule condition the widened condition is:
120 // i.start u< guardLimit && latchLimit u< guardLimit
121 //
122 // For the signed latch comparison case M is:
123 // forall X . X u< guardLimit && (X + 1) s< latchLimit =>
124 // (X + 1) u< guardLimit
125 //
126 // The only way the antecedent can be true and the consequent can be false is
109 // forall X . guardStart + X u< guardLimit && latchStart + X
110 // guardStart + X + 1 u< guardLimit
111 //
112 // The only way the antecedent can be true and the consequent can be false is
127113 // if
128 // X == guardLimit - 1
114 // X == guardLimit - 1 - guardStart
129115 // (and guardLimit is non-zero, but we won't use this latter fact).
130 // If X == guardLimit - 1 then the second half of the antecedent is
131 // guardLimit s< latchLimit
116 // If X == guardLimit - 1 - guardStart then the second half of the antecedent is
117 // latchStart + guardLimit - 1 - guardStart u< latchLimit
132118 // and its negation is
133 // latchLimit s<= guardLimit.
134 //
135 // In other words, if latchLimit s<= guardLimit then:
119 // latchStart + guardLimit - 1 - guardStart u>= latchLimit
120 //
121 // In other words, if
122 // latchLimit u<= latchStart + guardLimit - 1 - guardStart
123 // then:
136124 // (the ranges below are written in ConstantRange notation, where [A, B) is the
137125 // set for (I = A; I != B; I++ /*maywrap*/) yield(I);)
138126 //
139 // forall X . X u< guardLimit && (X + 1) s< latchLimit => (X + 1) u< guardLimit
140 // == forall X . X u< guardLimit && (X + 1) s< guardLimit => (X + 1) u< guardLimit
141 // == forall X . X in [0, guardLimit) && (X + 1) in [INT_MIN, guardLimit) => (X + 1) in [0, guardLimit)
142 // == forall X . X in [0, guardLimit) && X in [INT_MAX, guardLimit-1) => X in [-1, guardLimit-1)
143 // == forall X . X in [0, guardLimit-1) => X in [-1, guardLimit-1)
127 // forall X . guardStart + X u< guardLimit &&
128 // latchStart + X u< latchLimit =>
129 // guardStart + X + 1 u< guardLimit
130 // == forall X . guardStart + X u< guardLimit &&
131 // latchStart + X u< latchStart + guardLimit - 1 - guardStart =>
132 // guardStart + X + 1 u< guardLimit
133 // == forall X . (guardStart + X) in [0, guardLimit) &&
134 // (latchStart + X) in [0, latchStart + guardLimit - 1 - guardStart) =>
135 // (guardStart + X + 1) in [0, guardLimit)
136 // == forall X . X in [-guardStart, guardLimit - guardStart) &&
137 // X in [-latchStart, guardLimit - 1 - guardStart) =>
138 // X in [-guardStart - 1, guardLimit - guardStart - 1)
144139 // == true
145140 //
146141 // So the widened condition is:
147 // i.start u< guardLimit && latchLimit s<= guardLimit
148 // Similarly for sle condition the widened condition is:
149 // i.start u< guardLimit && latchLimit s< guardLimit
142 // guardStart u< guardLimit &&
143 // latchStart + guardLimit - 1 - guardStart u>= latchLimit
144 // Similarly for ule condition the widened condition is:
145 // guardStart u< guardLimit &&
146 // latchStart + guardLimit - 1 - guardStart u> latchLimit
147 // For slt condition the widened condition is:
148 // guardStart u< guardLimit &&
149 // latchStart + guardLimit - 1 - guardStart s>= latchLimit
150 // For sle condition the widened condition is:
151 // guardStart u< guardLimit &&
152 // latchStart + guardLimit - 1 - guardStart s> latchLimit
150153 //
151154 //===----------------------------------------------------------------------===//
152155
321324 return None;
322325 }
323326 auto *RangeCheckIV = RangeCheck->IV;
324 auto *PostIncRangeCheckIV = RangeCheckIV->getPostIncExpr(*SE);
325 if (LatchCheck.IV != PostIncRangeCheckIV) {
326 DEBUG(dbgs() << "Post increment range check IV (" << *PostIncRangeCheckIV
327 << ") is not the same as latch IV (" << *LatchCheck.IV
328 << ")!\n");
329 return None;
330 }
331 assert(RangeCheckIV->getStepRecurrence(*SE)->isOne() && "must be one");
332 const SCEV *Start = RangeCheckIV->getStart();
327 auto *Ty = RangeCheckIV->getType();
328 if (Ty != LatchCheck.IV->getType()) {
329 DEBUG(dbgs() << "Type mismatch between range check and latch IVs!\n");
330 return None;
331 }
332 if (!RangeCheckIV->isAffine()) {
333 DEBUG(dbgs() << "Range check IV is not affine!\n");
334 return None;
335 }
336 auto *Step = RangeCheckIV->getStepRecurrence(*SE);
337 if (Step != LatchCheck.IV->getStepRecurrence(*SE)) {
338 DEBUG(dbgs() << "Range check and latch have IVs different steps!\n");
339 return None;
340 }
341 assert(Step->isOne() && "must be one");
333342
334343 // Generate the widened condition:
335 // i.start u< guardLimit && latchLimit guardLimit
344 // guardStart u< guardLimit &&
345 // latchLimit guardLimit - 1 - guardStart + latchStart
336346 // where depends on the latch condition predicate. See the file
337347 // header comment for the reasoning.
348 const SCEV *GuardStart = RangeCheckIV->getStart();
349 const SCEV *GuardLimit = RangeCheck->Limit;
350 const SCEV *LatchStart = LatchCheck.IV->getStart();
351 const SCEV *LatchLimit = LatchCheck.Limit;
352
353 // guardLimit - guardStart + latchStart - 1
354 const SCEV *RHS =
355 SE->getAddExpr(SE->getMinusSCEV(GuardLimit, GuardStart),
356 SE->getMinusSCEV(LatchStart, SE->getOne(Ty)));
357
338358 ICmpInst::Predicate LimitCheckPred;
339359 switch (LatchCheck.Pred) {
340360 case ICmpInst::ICMP_ULT:
353373 llvm_unreachable("Unsupported loop latch!");
354374 }
355375
376 DEBUG(dbgs() << "LHS: " << *LatchLimit << "\n");
377 DEBUG(dbgs() << "RHS: " << *RHS << "\n");
378 DEBUG(dbgs() << "Pred: " << LimitCheckPred << "\n");
379
356380 auto CanExpand = [this](const SCEV *S) {
357381 return SE->isLoopInvariant(S, L) && isSafeToExpand(S, *SE);
358382 };
359 if (!CanExpand(Start) || !CanExpand(LatchCheck.Limit) ||
360 !CanExpand(RangeCheck->Limit))
361 return None;
383 if (!CanExpand(GuardStart) || !CanExpand(GuardLimit) ||
384 !CanExpand(LatchLimit) || !CanExpand(RHS)) {
385 DEBUG(dbgs() << "Can't expand limit check!\n");
386 return None;
387 }
362388
363389 Instruction *InsertAt = Preheader->getTerminator();
364 auto *LimitCheck = expandCheck(Expander, Builder, LimitCheckPred,
365 LatchCheck.Limit, RangeCheck->Limit, InsertAt);
390 auto *LimitCheck =
391 expandCheck(Expander, Builder, LimitCheckPred, LatchLimit, RHS, InsertAt);
366392 auto *FirstIterationCheck = expandCheck(Expander, Builder, RangeCheck->Pred,
367 Start, RangeCheck->Limit, InsertAt);
393 GuardStart, GuardLimit, InsertAt);
368394 return Builder.CreateAnd(FirstIterationCheck, LimitCheck);
369395 }
370396
247247
248248 %i.next = add nuw i32 %i, 1
249249 %continue = icmp sle i32 %i.next, %n
250 br i1 %continue, label %loop, label %exit
251
252 exit:
253 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
254 ret i32 %result
255 }
256
257 define i32 @signed_loop_0_to_n_preincrement_latch_check(i32* %array, i32 %length, i32 %n) {
258 ; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check
259 entry:
260 %tmp5 = icmp sle i32 %n, 0
261 br i1 %tmp5, label %exit, label %loop.preheader
262
263 loop.preheader:
264 ; CHECK: loop.preheader:
265 ; CHECK: [[length_minus_1:[^ ]+]] = add i32 %length, -1
266 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[length_minus_1]]
267 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 0, %length
268 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]]
269 ; CHECK-NEXT: br label %loop
270 br label %loop
271
272 loop:
273 ; CHECK: loop:
274 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
275 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
276 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
277 %within.bounds = icmp ult i32 %i, %length
278 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
279
280 %i.i64 = zext i32 %i to i64
281 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
282 %array.i = load i32, i32* %array.i.ptr, align 4
283 %loop.acc.next = add i32 %loop.acc, %array.i
284
285 %i.next = add i32 %i, 1
286 %continue = icmp slt i32 %i, %n
287 br i1 %continue, label %loop, label %exit
288
289 exit:
290 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
291 ret i32 %result
292 }
293
294 define i32 @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check(i32* %array, i32 %length, i32 %n) {
295 ; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check
296 entry:
297 %tmp5 = icmp sle i32 %n, 0
298 br i1 %tmp5, label %exit, label %loop.preheader
299
300 loop.preheader:
301 ; CHECK: loop.preheader:
302 ; CHECK: [[length_minus_2:[^ ]+]] = add i32 %length, -2
303 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[length_minus_2]]
304 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length
305 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]]
306 ; CHECK-NEXT: br label %loop
307 br label %loop
308
309 loop:
310 ; CHECK: loop:
311 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
312 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
313 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
314
315 %i.next = add i32 %i, 1
316 %within.bounds = icmp ult i32 %i.next, %length
317 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
318
319 %i.i64 = zext i32 %i to i64
320 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
321 %array.i = load i32, i32* %array.i.ptr, align 4
322 %loop.acc.next = add i32 %loop.acc, %array.i
323
324 %continue = icmp slt i32 %i, %n
325 br i1 %continue, label %loop, label %exit
326
327 exit:
328 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
329 ret i32 %result
330 }
331
332 define i32 @signed_loop_0_to_n_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) {
333 ; CHECK-LABEL: @signed_loop_0_to_n_sle_latch_offset_ult_check
334 entry:
335 %tmp5 = icmp sle i32 %n, 0
336 br i1 %tmp5, label %exit, label %loop.preheader
337
338 loop.preheader:
339 ; CHECK: loop.preheader:
340 ; CHECK: [[length_minus_1:[^ ]+]] = add i32 %length, -1
341 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp slt i32 %n, [[length_minus_1]]
342 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length
343 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]]
344 ; CHECK-NEXT: br label %loop
345 br label %loop
346
347 loop:
348 ; CHECK: loop:
349 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
350 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
351 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
352 %i.offset = add i32 %i, 1
353 %within.bounds = icmp ult i32 %i.offset, %length
354 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
355
356 %i.i64 = zext i32 %i to i64
357 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
358 %array.i = load i32, i32* %array.i.ptr, align 4
359 %loop.acc.next = add i32 %loop.acc, %array.i
360
361 %i.next = add i32 %i, 1
362 %continue = icmp sle i32 %i.next, %n
363 br i1 %continue, label %loop, label %exit
364
365 exit:
366 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
367 ret i32 %result
368 }
369
370 define i32 @signed_loop_0_to_n_offset_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) {
371 ; CHECK-LABEL: @signed_loop_0_to_n_offset_sle_latch_offset_ult_check
372 entry:
373 %tmp5 = icmp sle i32 %n, 0
374 br i1 %tmp5, label %exit, label %loop.preheader
375
376 loop.preheader:
377 ; CHECK: loop.preheader:
378 ; CHECK: [[limit_check:[^ ]+]] = icmp slt i32 %n, %length
379 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length
380 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]]
381 ; CHECK-NEXT: br label %loop
382 br label %loop
383
384 loop:
385 ; CHECK: loop:
386 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
387 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
388 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
389 %i.offset = add i32 %i, 1
390 %within.bounds = icmp ult i32 %i.offset, %length
391 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
392
393 %i.i64 = zext i32 %i to i64
394 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
395 %array.i = load i32, i32* %array.i.ptr, align 4
396 %loop.acc.next = add i32 %loop.acc, %array.i
397
398 %i.next = add i32 %i, 1
399 %i.next.offset = add i32 %i.next, 1
400 %continue = icmp sle i32 %i.next.offset, %n
250401 br i1 %continue, label %loop, label %exit
251402
252403 exit:
361512 ret i32 %result
362513 }
363514
364 define i32 @signed_loop_0_to_n_unrelated_iv_range_check(i32* %array, i32 %start, i32 %length, i32 %n) {
365 ; CHECK-LABEL: @signed_loop_0_to_n_unrelated_iv_range_check
515 define i32 @signed_loop_start_to_n_offset_iv_range_check(i32* %array, i32 %start.i,
516 i32 %start.j, i32 %length,
517 i32 %n) {
518 ; CHECK-LABEL: @signed_loop_start_to_n_offset_iv_range_check
519 entry:
520 %tmp5 = icmp sle i32 %n, 0
521 br i1 %tmp5, label %exit, label %loop.preheader
522
523 loop.preheader:
524 ; CHECK: loop.preheader:
525 ; CHECK: [[length_plus_start_i:[^ ]+]] = add i32 %length, %start.i
526 ; CHECK-NEXT: [[limit:[^ ]+]] = sub i32 [[length_plus_start_i]], %start.j
527 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[limit]]
528 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 %start.j, %length
529 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]]
530 ; CHECK-NEXT: br label %loop
531 br label %loop
532
533 loop:
534 ; CHECK: loop:
535 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
536 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
537 %i = phi i32 [ %i.next, %loop ], [ %start.i, %loop.preheader ]
538 %j = phi i32 [ %j.next, %loop ], [ %start.j, %loop.preheader ]
539
540 %within.bounds = icmp ult i32 %j, %length
541 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
542
543 %i.i64 = zext i32 %i to i64
544 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
545 %array.i = load i32, i32* %array.i.ptr, align 4
546 %loop.acc.next = add i32 %loop.acc, %array.i
547
548 %j.next = add i32 %j, 1
549 %i.next = add i32 %i, 1
550 %continue = icmp slt i32 %i.next, %n
551 br i1 %continue, label %loop, label %exit
552
553 exit:
554 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
555 ret i32 %result
556 }
557
558 define i32 @signed_loop_0_to_n_different_iv_types(i32* %array, i16 %length, i32 %n) {
559 ; CHECK-LABEL: @signed_loop_0_to_n_different_iv_types
560 entry:
561 %tmp5 = icmp sle i32 %n, 0
562 br i1 %tmp5, label %exit, label %loop.preheader
563
564 loop.preheader:
565 ; CHECK: loop.preheader:
566 ; CHECK-NEXT: br label %loop
567 br label %loop
568
569 loop:
570 ; CHECK: loop:
571 ; CHECK: %within.bounds = icmp ult i16 %j, %length
572 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
573 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
574 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
575 %j = phi i16 [ %j.next, %loop ], [ 0, %loop.preheader ]
576
577 %within.bounds = icmp ult i16 %j, %length
578 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
579
580 %i.i64 = zext i32 %i to i64
581 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
582 %array.i = load i32, i32* %array.i.ptr, align 4
583 %loop.acc.next = add i32 %loop.acc, %array.i
584
585 %j.next = add i16 %j, 1
586 %i.next = add i32 %i, 1
587 %continue = icmp slt i32 %i.next, %n
588 br i1 %continue, label %loop, label %exit
589
590 exit:
591 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
592 ret i32 %result
593 }
594
595 define i32 @signed_loop_0_to_n_different_iv_strides(i32* %array, i32 %length, i32 %n) {
596 ; CHECK-LABEL: @signed_loop_0_to_n_different_iv_strides
366597 entry:
367598 %tmp5 = icmp sle i32 %n, 0
368599 br i1 %tmp5, label %exit, label %loop.preheader
378609 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
379610 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
380611 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
381 %j = phi i32 [ %j.next, %loop ], [ %start, %loop.preheader ]
612 %j = phi i32 [ %j.next, %loop ], [ 0, %loop.preheader ]
382613
383614 %within.bounds = icmp ult i32 %j, %length
384615 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
388619 %array.i = load i32, i32* %array.i.ptr, align 4
389620 %loop.acc.next = add i32 %loop.acc, %array.i
390621
391 %j.next = add nsw i32 %j, 1
622 %j.next = add nsw i32 %j, 2
392623 %i.next = add nsw i32 %i, 1
393624 %continue = icmp slt i32 %i.next, %n
394625 br i1 %continue, label %loop, label %exit