| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes=indvars -S %s | FileCheck %s |
| |
| target datalayout = "n8:16:32:64" |
| |
| define i32 @nuw_kept(i32 %start, i32 %step, i32 %n) { |
| ; CHECK-LABEL: define i32 @nuw_kept( |
| ; CHECK-SAME: i32 [[START:%.*]], i32 [[STEP:%.*]], i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]] |
| ; CHECK: [[LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[STEP]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[START]], [[TMP0]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %v = phi i32 [ %start, %entry ], [ %v.next, %latch ] |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit, label %latch |
| |
| latch: |
| %v.next = add nuw i32 %v, %step |
| %i.next = add i32 %i, 1 |
| br label %loop |
| |
| exit: |
| ret i32 %v |
| } |
| |
| ; Signed recurrence with %start and %step are both known non-negative. |
| define i32 @nsw_kept_same_sign(i32 %start.in, i32 %step.in, i32 %n) { |
| ; CHECK-LABEL: define i32 @nsw_kept_same_sign( |
| ; CHECK-SAME: i32 [[START_IN:%.*]], i32 [[STEP_IN:%.*]], i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[START:%.*]] = and i32 [[START_IN]], 1023 |
| ; CHECK-NEXT: [[STEP:%.*]] = and i32 [[STEP_IN]], 1023 |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]] |
| ; CHECK: [[LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[STEP]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[TMP0]], [[START]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| entry: |
| %start = and i32 %start.in, 1023 |
| %step = and i32 %step.in, 1023 |
| br label %loop |
| |
| loop: |
| %v = phi i32 [ %start, %entry ], [ %v.next, %latch ] |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit, label %latch |
| |
| latch: |
| %v.next = add nsw i32 %v, %step |
| %i.next = add i32 %i, 1 |
| br label %loop |
| |
| exit: |
| ret i32 %v |
| } |
| |
| ; Start is non-negative but Step is negative. |
| define i32 @nsw_dropped_mixed_signs(i32 %start.in, i32 %step.in, i32 %n) { |
| ; CHECK-LABEL: define i32 @nsw_dropped_mixed_signs( |
| ; CHECK-SAME: i32 [[START_IN:%.*]], i32 [[STEP_IN:%.*]], i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[START:%.*]] = and i32 [[START_IN]], 1023 |
| ; CHECK-NEXT: [[STEP_POS:%.*]] = and i32 [[STEP_IN]], 1023 |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]] |
| ; CHECK: [[LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[STEP_POS]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[START]], [[TMP0]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| entry: |
| %start = and i32 %start.in, 1023 |
| %step.pos = and i32 %step.in, 1023 |
| %step = sub nsw i32 0, %step.pos |
| br label %loop |
| |
| loop: |
| %v = phi i32 [ %start, %entry ], [ %v.next, %latch ] |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit, label %latch |
| |
| latch: |
| %v.next = add nsw i32 %v, %step |
| %i.next = add i32 %i, 1 |
| br label %loop |
| |
| exit: |
| ret i32 %v |
| } |
| |
| ; The exit count is (-1 + %n) and Start is 0, so the sum folds away completely. |
| define i32 @nuw_dropped_sum_folded_away(i32 %n) { |
| ; CHECK-LABEL: define i32 @nuw_dropped_sum_folded_away( |
| ; CHECK-SAME: i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], -1 |
| ; CHECK-NEXT: ret i32 [[TMP0]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] |
| %i.next = add nuw i32 %i, 1 |
| %c = icmp eq i32 %i.next, %n |
| br i1 %c, label %exit, label %loop |
| |
| exit: |
| ret i32 %i |
| } |
| |
| ; Start is a sum, so computing the exit value inlines it into %start + BTC. |
| define i32 @nuw_dropped_sum_flattened(i32 %a, i32 %b, i32 %n) { |
| ; CHECK-LABEL: define i32 @nuw_dropped_sum_flattened( |
| ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]] |
| ; CHECK: [[LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], [[B]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], [[A]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| entry: |
| %start = add i32 %a, %b |
| br label %loop |
| |
| loop: |
| %v = phi i32 [ %start, %entry ], [ %v.next, %latch ] |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit, label %latch |
| |
| latch: |
| %v.next = add nuw i32 %v, 1 |
| %i.next = add i32 %i, 1 |
| br label %loop |
| |
| exit: |
| ret i32 %v |
| } |
| |
| ; Step is a product, so computing the exit value inlines it into BTC * Step. |
| define i32 @nuw_dropped_product_flattened(i32 %s1, i32 %s2, i32 %n) { |
| ; CHECK-LABEL: define i32 @nuw_dropped_product_flattened( |
| ; CHECK-SAME: i32 [[S1:%.*]], i32 [[S2:%.*]], i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]] |
| ; CHECK: [[LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[S2]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], [[S1]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| entry: |
| %step = mul i32 %s1, %s2 |
| br label %loop |
| |
| loop: |
| %v = phi i32 [ 0, %entry ], [ %v.next, %latch ] |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit, label %latch |
| |
| latch: |
| %v.next = add nuw i32 %v, %step |
| %i.next = add i32 %i, 1 |
| br label %loop |
| |
| exit: |
| ret i32 %v |
| } |
| |
| @A = external global i32 |
| |
| ; LFTR computes the limit for one exit of a multi-exit loop. %n is the count for |
| ; the latch exit alone; the loop can leave through the %iv2 == 20 exit first, so |
| ; that iteration is not necessarily reached. |
| define void @lftr_limit_multi_exit(i32 %n) { |
| ; CHECK-LABEL: define void @lftr_limit_multi_exit( |
| ; CHECK-SAME: i32 [[N:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], 1 |
| ; CHECK-NEXT: br label %[[OUTER:.*]] |
| ; CHECK: [[OUTER]]: |
| ; CHECK-NEXT: [[IV1:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV1_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: store volatile i32 [[IV1]], ptr @A, align 4 |
| ; CHECK-NEXT: [[IV1_NEXT]] = add nuw nsw i32 [[IV1]], 1 |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, %[[OUTER]] ], [ [[IV2_NEXT:%.*]], %[[INNER_LATCH:.*]] ] |
| ; CHECK-NEXT: store volatile i32 [[IV2]], ptr @A, align 4 |
| ; CHECK-NEXT: [[IV2_NEXT]] = add nuw nsw i32 [[IV2]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], 20 |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[INNER_LATCH]], label %[[EXIT_LOOPEXIT:.*]] |
| ; CHECK: [[INNER_LATCH]]: |
| ; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV2_NEXT]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[EXITCOND2]], label %[[INNER_HEADER]], label %[[OUTER_LATCH]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[EXITCOND3:%.*]] = icmp ne i32 [[IV1_NEXT]], 21 |
| ; CHECK-NEXT: br i1 [[EXITCOND3]], label %[[OUTER]], label %[[EXIT_LOOPEXIT1:.*]] |
| ; CHECK: [[EXIT_LOOPEXIT]]: |
| ; CHECK-NEXT: br label %[[EXIT:.*]] |
| ; CHECK: [[EXIT_LOOPEXIT1]]: |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %iv1 = phi i32 [ 0, %entry ], [ %iv1.next, %outer.latch ] |
| store volatile i32 %iv1, ptr @A |
| %iv1.next = add i32 %iv1, 1 |
| br label %inner.header |
| |
| inner.header: |
| %iv2 = phi i32 [ 0, %outer.header ], [ %iv2.next, %inner.latch ] |
| store volatile i32 %iv2, ptr @A |
| %iv2.next = add i32 %iv2, 1 |
| %inner.ec.1 = icmp ult i32 %iv2, 20 |
| br i1 %inner.ec.1, label %inner.latch, label %exit |
| |
| inner.latch: |
| %inner.ec.2 = icmp ult i32 %iv2, %n |
| br i1 %inner.ec.2, label %inner.header, label %outer.latch |
| |
| outer.latch: |
| %outertest = icmp ult i32 %iv1, 20 |
| br i1 %outertest, label %outer.header, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define i32 @no_flag_leak_through_shared_udiv(i32 %start, i32 %n, i1 %c) { |
| ; CHECK-LABEL: define i32 @no_flag_leak_through_shared_udiv( |
| ; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br i1 [[C]], label %[[PH_1:.*]], label %[[PH_2:.*]] |
| ; CHECK: [[PH_1]]: |
| ; CHECK-NEXT: br label %[[LOOP_1_HEADER:.*]] |
| ; CHECK: [[LOOP_1_HEADER]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT_1:.*]], label %[[LOOP_1_LATCH:.*]] |
| ; CHECK: [[LOOP_1_LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP_1_HEADER]] |
| ; CHECK: [[EXIT_1]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], [[START]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = udiv i32 [[TMP0]], 3 |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; CHECK: [[PH_2]]: |
| ; CHECK-NEXT: br label %[[LOOP_2_HEADER:.*]] |
| ; CHECK: [[LOOP_2_HEADER]]: |
| ; CHECK-NEXT: br i1 true, label %[[EXIT_2:.*]], label %[[LOOP_2_LATCH:.*]] |
| ; CHECK: [[LOOP_2_LATCH]]: |
| ; CHECK-NEXT: br label %[[LOOP_2_HEADER]] |
| ; CHECK: [[EXIT_2]]: |
| ; CHECK-NEXT: [[TMP2:%.*]] = add nuw i32 [[N]], [[START]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = udiv i32 [[TMP2]], 3 |
| ; CHECK-NEXT: ret i32 [[TMP3]] |
| ; |
| entry: |
| br i1 %c, label %ph.1, label %ph.2 |
| |
| ph.1: |
| br label %loop.1.header |
| |
| loop.1.header: |
| %v = phi i32 [ %start, %ph.1 ], [ %v.next, %loop.1.latch ] |
| %i = phi i32 [ 0, %ph.1 ], [ %i.next, %loop.1.latch ] |
| %dv = udiv i32 %v, 3 |
| %done = icmp eq i32 %i, %n |
| br i1 %done, label %exit.1, label %loop.1.latch |
| |
| loop.1.latch: |
| %v.next = add i32 %v, 1 |
| %i.next = add i32 %i, 1 |
| br label %loop.1.header |
| |
| exit.1: |
| ret i32 %dv |
| |
| ph.2: |
| br label %loop.2.header |
| |
| loop.2.header: |
| %v2 = phi i32 [ %start, %ph.2 ], [ %v2.next, %loop.2.latch ] |
| %i2 = phi i32 [ 0, %ph.2 ], [ %i2.next, %loop.2.latch ] |
| %dv2 = udiv i32 %v2, 3 |
| %done2 = icmp eq i32 %i2, %n |
| br i1 %done2, label %exit.2, label %loop.2.latch |
| |
| loop.2.latch: |
| %v2.next = add nuw i32 %v2, 1 |
| %i2.next = add i32 %i2, 1 |
| br label %loop.2.header |
| |
| exit.2: |
| ret i32 %dv2 |
| } |
| |
| |
| define ptr @exit_value_mul(ptr %first, ptr %last) { |
| ; CHECK-LABEL: define ptr @exit_value_mul( |
| ; CHECK-SAME: ptr [[FIRST:%.*]], ptr [[LAST:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[FIRST2:%.*]] = ptrtoaddr ptr [[FIRST]] to i64 |
| ; CHECK-NEXT: [[LAST1:%.*]] = ptrtoaddr ptr [[LAST]] to i64 |
| ; CHECK-NEXT: [[C0:%.*]] = icmp ult ptr [[FIRST]], [[LAST]] |
| ; CHECK-NEXT: br i1 [[C0]], label %[[LOOP_PREHEADER:.*]], label %[[DONE:.*]] |
| ; CHECK: [[LOOP_PREHEADER]]: |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT:.*]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[FIRST2]], 24 |
| ; CHECK-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[LAST1]], i64 [[TMP0]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[UMAX]], -24 |
| ; CHECK-NEXT: [[TMP2:%.*]] = sub i64 [[TMP1]], [[FIRST2]] |
| ; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP2]], i64 1) |
| ; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[UMIN]] |
| ; CHECK-NEXT: [[TMP4:%.*]] = udiv i64 [[TMP3]], 24 |
| ; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[UMIN]], [[TMP4]] |
| ; CHECK-NEXT: [[TMP6:%.*]] = mul i64 [[TMP5]], 24 |
| ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[FIRST]], i64 [[TMP6]] |
| ; CHECK-NEXT: ret ptr [[SCEVGEP]] |
| ; CHECK: [[DONE]]: |
| ; CHECK-NEXT: ret ptr [[FIRST]] |
| ; |
| entry: |
| %c0 = icmp ult ptr %first, %last |
| br i1 %c0, label %loop, label %done |
| |
| loop: |
| %p = phi ptr [ %first, %entry ], [ %p.next, %loop ] |
| %p.next = getelementptr inbounds nuw i8, ptr %p, i64 24 |
| %c = icmp ult ptr %p.next, %last |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| %lc = phi ptr [ %p, %loop ] |
| ret ptr %lc |
| |
| done: |
| ret ptr %first |
| } |