| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -verify-loop-info -irce-print-changed-loops -passes=irce -S < %s 2>&1 | FileCheck %s |
| ; RUN: opt -verify-loop-info -irce-print-changed-loops -passes='require<branch-prob>,irce' -S < %s 2>&1 | FileCheck %s |
| |
| ; 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: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| ; CHECK: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| ; CHECK: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| ; CHECK: irce: in function test_06: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| ; CHECK-NOT: irce: in function test_07: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| ; CHECK: irce: in function test_08: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> |
| |
| ; IV = 0; IV <s 100; IV += 7; 0 <= Len <= 50. IRCE is allowed. |
| define void @test_01(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_01 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0:![0-9]+]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], 7 |
| ; 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, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], 100 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], 100 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add i32 [[IDX_POSTLOOP]], 7 |
| ; 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:%.*]] |
| ; CHECK: in.bounds.postloop: |
| ; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp slt i32 [[IDX_NEXT_POSTLOOP]], 100 |
| ; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP1:![0-9]+]], !irce.loop.clone !6 |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !0 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, 7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp slt i32 %idx.next, 100 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = 0; IV <s MAX_INT - 7; IV += 7; 0 <= Len <= 50. IRCE is allowed. |
| define void @test_02(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_02 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], 7 |
| ; 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, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], 2147483640 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], 2147483640 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add i32 [[IDX_POSTLOOP]], 7 |
| ; 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:%.*]] |
| ; CHECK: in.bounds.postloop: |
| ; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp slt i32 [[IDX_NEXT_POSTLOOP]], 2147483640 |
| ; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP7:![0-9]+]], !irce.loop.clone !6 |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !0 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, 7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp slt i32 %idx.next, 2147483640 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = 0; IV <s MAX_INT; IV += 7; 0 <= Len <= MAX_INT - 7. This is the greatest |
| ; value of Len for which IRCE is allowed. |
| define void @test_03(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_03 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG8:![0-9]+]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], 7 |
| ; 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, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], 2147483647 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], 2147483647 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add i32 [[IDX_POSTLOOP]], 7 |
| ; 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:%.*]] |
| ; CHECK: in.bounds.postloop: |
| ; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp slt i32 [[IDX_NEXT_POSTLOOP]], 2147483647 |
| ; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP9:![0-9]+]], !irce.loop.clone !6 |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !1 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, 7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp slt i32 %idx.next, 2147483647 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = 0; IV <s MAX_INT; IV += 7; 0 <= Len <= MAX_INT - 6. IRCE is allowed |
| ; because the branch would fail once idx.next == MAX_INT - 1 keeping the |
| ; access in bounds. |
| define void @test_04(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_04 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG10:![0-9]+]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], 7 |
| ; 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, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], 2147483647 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], 2147483647 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add i32 [[IDX_POSTLOOP]], 7 |
| ; 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:%.*]] |
| ; CHECK: in.bounds.postloop: |
| ; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp slt i32 [[IDX_NEXT_POSTLOOP]], 2147483647 |
| ; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP11:![0-9]+]], !irce.loop.clone !6 |
| ; |
| |
| |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !2 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, 7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp slt i32 %idx.next, 2147483647 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = 100; IV >s -1; IV -= 7; 0 <= Len <= 50. IRCE is allowed. |
| define void @test_05(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_05 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] |
| ; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = add nsw i32 [[LEN]], -1 |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 100, [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preloop.preheader: |
| ; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] |
| ; CHECK: mainloop: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], -7 |
| ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[LEN]] |
| ; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] |
| ; CHECK: in.bounds: |
| ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp sgt i32 [[IDX_NEXT]], -1 |
| ; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: loop.preloop: |
| ; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ 100, [[LOOP_PRELOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add i32 [[IDX_PRELOOP]], -7 |
| ; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp slt i32 [[IDX_PRELOOP]], [[LEN]] |
| ; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] |
| ; CHECK: in.bounds.preloop: |
| ; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp sgt i32 [[IDX_NEXT_PRELOOP]], -1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[IDX_NEXT_PRELOOP]], [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP12:![0-9]+]], !irce.loop.clone !6 |
| ; CHECK: preloop.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[IDX_NEXT_PRELOOP_LCSSA]], -1 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] |
| ; CHECK: preloop.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 100, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[MAINLOOP]] |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !0 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, -7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp sgt i32 %idx.next, -1 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = MAX_INT - 7; IV >u 6; IV -= 7; 10 <= Len <= 50. IRCE is allowed. |
| define void @test_06(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_06 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG13:![0-9]+]] |
| ; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = add nsw i32 [[LEN]], -1 |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 2147483640, [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preloop.preheader: |
| ; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] |
| ; CHECK: mainloop: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], -7 |
| ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[LEN]] |
| ; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] |
| ; CHECK: in.bounds: |
| ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 6 |
| ; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: loop.preloop: |
| ; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ 2147483640, [[LOOP_PRELOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add i32 [[IDX_PRELOOP]], -7 |
| ; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp slt i32 [[IDX_PRELOOP]], [[LEN]] |
| ; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] |
| ; CHECK: in.bounds.preloop: |
| ; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 6 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP14:![0-9]+]], !irce.loop.clone !6 |
| ; CHECK: preloop.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP_LCSSA]], 6 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] |
| ; CHECK: preloop.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ 2147483640, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 2147483640, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[MAINLOOP]] |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !3 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 2147483640, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, -7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp ugt i32 %idx.next, 6 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = MAX_INT - 7; IV >u 5; IV -= 7; 10 <= Len <= 50. IRCE is not allowed, |
| ; because we can cross the 0 border. |
| define void @test_07(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_07 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG13]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ 2147483640, [[ENTRY:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], -7 |
| ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[LEN]] |
| ; CHECK-NEXT: br i1 [[ABC]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: in.bounds: |
| ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 5 |
| ; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !3 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 2147483640, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, -7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp ugt i32 %idx.next, 5 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IV = MAX_INT; IV >u 6; IV -= 7; 10 <= Len <= 50. IRCE is allowed. |
| define void @test_08(ptr %arr, ptr %a_len_ptr) { |
| ; CHECK-LABEL: define void @test_08 |
| ; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG13]] |
| ; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = add nsw i32 [[LEN]], -1 |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 2147483647, [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preloop.preheader: |
| ; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] |
| ; CHECK: mainloop: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] |
| ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], -7 |
| ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[LEN]] |
| ; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] |
| ; CHECK: in.bounds: |
| ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 6 |
| ; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] |
| ; CHECK: out.of.bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out.of.bounds.loopexit1: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out.of.bounds: |
| ; CHECK-NEXT: ret void |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; CHECK: loop.preloop: |
| ; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ 2147483647, [[LOOP_PRELOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add i32 [[IDX_PRELOOP]], -7 |
| ; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp slt i32 [[IDX_PRELOOP]], [[LEN]] |
| ; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] |
| ; CHECK: in.bounds.preloop: |
| ; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] |
| ; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 |
| ; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 6 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], [[EXIT_PRELOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP15:![0-9]+]], !irce.loop.clone !6 |
| ; CHECK: preloop.exit.selector: |
| ; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP_LCSSA]], 6 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] |
| ; CHECK: preloop.pseudo.exit: |
| ; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 2147483647, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[MAINLOOP]] |
| ; |
| |
| entry: |
| %len = load i32, ptr %a_len_ptr, !range !3 |
| br label %loop |
| |
| loop: |
| %idx = phi i32 [ 2147483647, %entry ], [ %idx.next, %in.bounds ] |
| %idx.next = add i32 %idx, -7 |
| %abc = icmp slt i32 %idx, %len |
| br i1 %abc, label %in.bounds, label %out.of.bounds |
| |
| in.bounds: |
| %addr = getelementptr i32, ptr %arr, i32 %idx |
| store i32 0, ptr %addr |
| %next = icmp ugt i32 %idx.next, 6 |
| br i1 %next, label %loop, label %exit |
| |
| out.of.bounds: |
| ret void |
| |
| exit: |
| ret void |
| } |
| |
| ; IRCE is legal here. |
| ; Here how it is done if the step was 1: https://godbolt.org/z/jEqWaseWc |
| ; It is also legal for step 4. Proof: |
| ; - Capacity check ensures that iv < limit <= SINT_MAX - 3, meaning that |
| ; iv <= SINT_MAX - 4. |
| ; - Because of this, iv.next is always computed w/o overflow. |
| ; - The loop goes to backedge as long as iv < capacity - 3 && iv < num.elements - 4. |
| ; - So iterating up to smin(capacity - 3, num.elements - 4) should be safe. |
| ; - Proof by alive2: https://alive2.llvm.org/ce/z/vEhMxa |
| define i32 @test_09(ptr %p, ptr %capacity_p, ptr %num_elements_p) { |
| ; CHECK-LABEL: define i32 @test_09 |
| ; CHECK-SAME: (ptr [[P:%.*]], ptr [[CAPACITY_P:%.*]], ptr [[NUM_ELEMENTS_P:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CAPACITY:%.*]] = load i32, ptr [[CAPACITY_P]], align 4, !range [[RNG16:![0-9]+]] |
| ; CHECK-NEXT: [[NUM_ELEMENTS:%.*]] = load i32, ptr [[NUM_ELEMENTS_P]], align 4, !range [[RNG16]] |
| ; CHECK-NEXT: [[LIMIT:%.*]] = sub i32 [[CAPACITY]], 3 |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[CAPACITY]], -3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[CAPACITY]], 2147483646 |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP1]], i32 0) |
| ; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[TMP0]], [[SMAX]] |
| ; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[LIMIT]], i32 0) |
| ; CHECK-NEXT: [[SMAX2:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN]], i32 -1) |
| ; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[SMAX2]], 1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[TMP2]], [[TMP3]] |
| ; CHECK-NEXT: [[SMIN3:%.*]] = call i32 @llvm.smin.i32(i32 [[NUM_ELEMENTS]], i32 [[TMP4]]) |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN3]], i32 0) |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK:%.*]] = icmp slt i32 [[IV]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]], !prof [[PROF17:![0-9]+]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: [[IV_WIDE:%.*]] = zext i32 [[IV]] to i64 |
| ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[IV_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i32 [ [[IV_NEXT]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[IV_NEXT_LCSSA]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[TMP7]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IV_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: [[IV_LCSSA1_PH:%.*]] = phi i32 [ [[IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ], [ [[IV_LCSSA1_PH]], [[EXIT_LOOPEXIT:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA1]] |
| ; CHECK: out_of_bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out_of_bounds.loopexit5: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out_of_bounds: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IV_POSTLOOP]] = phi i32 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK_POSTLOOP:%.*]] = icmp slt i32 [[IV_POSTLOOP]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 [[CAPACITY_CHECK_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]], !prof [[PROF17]] |
| ; CHECK: backedge.postloop: |
| ; CHECK-NEXT: [[IV_WIDE_POSTLOOP:%.*]] = zext i32 [[IV_POSTLOOP]] to i64 |
| ; CHECK-NEXT: [[EL_PTR_POSTLOOP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE_POSTLOOP]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add nuw nsw i32 [[IV_POSTLOOP]], 4 |
| ; CHECK-NEXT: [[LOOP_COND_POSTLOOP:%.*]] = icmp slt i32 [[IV_NEXT_POSTLOOP]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[LOOP_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP18:![0-9]+]], !irce.loop.clone !6 |
| ; |
| entry: |
| %capacity = load i32, ptr %capacity_p, !range !4 |
| %num_elements = load i32, ptr %num_elements_p, !range !4 |
| %limit = sub i32 %capacity, 3 |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %backedge] |
| %capacity_check = icmp slt i32 %iv, %limit |
| br i1 %capacity_check, label %backedge, label %out_of_bounds, !prof !5 |
| |
| backedge: |
| %iv.wide = zext i32 %iv to i64 |
| %el.ptr = getelementptr i32, ptr %p, i64 %iv.wide |
| store i32 1, ptr %el.ptr |
| %iv.next = add nuw nsw i32 %iv, 4 |
| %loop_cond = icmp slt i32 %iv.next, %num_elements |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| |
| out_of_bounds: |
| ret i32 -1 |
| } |
| |
| ; Same as test_09 but range check comparison is inversed. |
| ; IRCE is allowed. |
| define i32 @test_10(ptr %p, ptr %capacity_p, ptr %num_elements_p) { |
| ; CHECK-LABEL: define i32 @test_10 |
| ; CHECK-SAME: (ptr [[P:%.*]], ptr [[CAPACITY_P:%.*]], ptr [[NUM_ELEMENTS_P:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CAPACITY:%.*]] = load i32, ptr [[CAPACITY_P]], align 4, !range [[RNG16]] |
| ; CHECK-NEXT: [[NUM_ELEMENTS:%.*]] = load i32, ptr [[NUM_ELEMENTS_P]], align 4, !range [[RNG16]] |
| ; CHECK-NEXT: [[LIMIT:%.*]] = sub i32 [[CAPACITY]], 3 |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[CAPACITY]], -3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[CAPACITY]], 2147483646 |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP1]], i32 0) |
| ; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[TMP0]], [[SMAX]] |
| ; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[LIMIT]], i32 0) |
| ; CHECK-NEXT: [[SMAX2:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN]], i32 -1) |
| ; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[SMAX2]], 1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[TMP2]], [[TMP3]] |
| ; CHECK-NEXT: [[SMIN3:%.*]] = call i32 @llvm.smin.i32(i32 [[NUM_ELEMENTS]], i32 [[TMP4]]) |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN3]], i32 0) |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK:%.*]] = icmp slt i32 [[IV]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]], !prof [[PROF17]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: [[IV_WIDE:%.*]] = zext i32 [[IV]] to i64 |
| ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[IV_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i32 [ [[IV_NEXT]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[IV_NEXT_LCSSA]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[TMP7]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IV_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: [[IV_LCSSA1_PH:%.*]] = phi i32 [ [[IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ], [ [[IV_LCSSA1_PH]], [[EXIT_LOOPEXIT:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA1]] |
| ; CHECK: out_of_bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out_of_bounds.loopexit5: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out_of_bounds: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IV_POSTLOOP]] = phi i32 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK_POSTLOOP:%.*]] = icmp slt i32 [[IV_POSTLOOP]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 [[CAPACITY_CHECK_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]], !prof [[PROF17]] |
| ; CHECK: backedge.postloop: |
| ; CHECK-NEXT: [[IV_WIDE_POSTLOOP:%.*]] = zext i32 [[IV_POSTLOOP]] to i64 |
| ; CHECK-NEXT: [[EL_PTR_POSTLOOP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE_POSTLOOP]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add nuw nsw i32 [[IV_POSTLOOP]], 4 |
| ; CHECK-NEXT: [[LOOP_COND_POSTLOOP:%.*]] = icmp slt i32 [[IV_NEXT_POSTLOOP]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[LOOP_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP19:![0-9]+]], !irce.loop.clone !6 |
| ; |
| entry: |
| %capacity = load i32, ptr %capacity_p, !range !4 |
| %num_elements = load i32, ptr %num_elements_p, !range !4 |
| %limit = sub i32 %capacity, 3 |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %backedge] |
| %capacity_check = icmp sge i32 %iv, %limit |
| br i1 %capacity_check, label %out_of_bounds, label %backedge, !prof !6 |
| |
| backedge: |
| %iv.wide = zext i32 %iv to i64 |
| %el.ptr = getelementptr i32, ptr %p, i64 %iv.wide |
| store i32 1, ptr %el.ptr |
| %iv.next = add nuw nsw i32 %iv, 4 |
| %loop_cond = icmp slt i32 %iv.next, %num_elements |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| |
| out_of_bounds: |
| ret i32 -1 |
| } |
| |
| ; Same as test_09 but range check comparison is non-strict: |
| ; IRCE is allowed. |
| define i32 @test_11(ptr %p, ptr %capacity_p, ptr %num_elements_p) { |
| ; CHECK-LABEL: define i32 @test_11 |
| ; CHECK-SAME: (ptr [[P:%.*]], ptr [[CAPACITY_P:%.*]], ptr [[NUM_ELEMENTS_P:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CAPACITY:%.*]] = load i32, ptr [[CAPACITY_P]], align 4, !range [[RNG16]] |
| ; CHECK-NEXT: [[NUM_ELEMENTS:%.*]] = load i32, ptr [[NUM_ELEMENTS_P]], align 4, !range [[RNG16]] |
| ; CHECK-NEXT: [[LIMIT:%.*]] = sub i32 [[CAPACITY]], 4 |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[CAPACITY]], -3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[CAPACITY]], 2147483646 |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP1]], i32 0) |
| ; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[TMP0]], [[SMAX]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[CAPACITY]], -3 |
| ; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[TMP3]], i32 0) |
| ; CHECK-NEXT: [[SMAX2:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN]], i32 -1) |
| ; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[SMAX2]], 1 |
| ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP2]], [[TMP4]] |
| ; CHECK-NEXT: [[SMIN3:%.*]] = call i32 @llvm.smin.i32(i32 [[NUM_ELEMENTS]], i32 [[TMP5]]) |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN3]], i32 0) |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.preheader: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK:%.*]] = icmp sle i32 [[IV]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]], !prof [[PROF17]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: [[IV_WIDE:%.*]] = zext i32 [[IV]] to i64 |
| ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[IV_NEXT]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP7]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i32 [ [[IV_NEXT]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] |
| ; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i32 [[IV_NEXT_LCSSA]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[TMP8]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IV_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: [[IV_LCSSA1_PH:%.*]] = phi i32 [ [[IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ], [ [[IV_LCSSA1_PH]], [[EXIT_LOOPEXIT:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA1]] |
| ; CHECK: out_of_bounds.loopexit: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] |
| ; CHECK: out_of_bounds.loopexit5: |
| ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] |
| ; CHECK: out_of_bounds: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] |
| ; CHECK: loop.postloop: |
| ; CHECK-NEXT: [[IV_POSTLOOP]] = phi i32 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ] |
| ; CHECK-NEXT: [[CAPACITY_CHECK_POSTLOOP:%.*]] = icmp sle i32 [[IV_POSTLOOP]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 [[CAPACITY_CHECK_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]], !prof [[PROF17]] |
| ; CHECK: backedge.postloop: |
| ; CHECK-NEXT: [[IV_WIDE_POSTLOOP:%.*]] = zext i32 [[IV_POSTLOOP]] to i64 |
| ; CHECK-NEXT: [[EL_PTR_POSTLOOP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV_WIDE_POSTLOOP]] |
| ; CHECK-NEXT: store i32 1, ptr [[EL_PTR_POSTLOOP]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add nuw nsw i32 [[IV_POSTLOOP]], 4 |
| ; CHECK-NEXT: [[LOOP_COND_POSTLOOP:%.*]] = icmp slt i32 [[IV_NEXT_POSTLOOP]], [[NUM_ELEMENTS]] |
| ; CHECK-NEXT: br i1 [[LOOP_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP20:![0-9]+]], !irce.loop.clone !6 |
| ; |
| entry: |
| %capacity = load i32, ptr %capacity_p, !range !4 |
| %num_elements = load i32, ptr %num_elements_p, !range !4 |
| %limit = sub i32 %capacity, 4 |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %backedge] |
| %capacity_check = icmp sle i32 %iv, %limit |
| br i1 %capacity_check, label %backedge, label %out_of_bounds, !prof !5 |
| |
| backedge: |
| %iv.wide = zext i32 %iv to i64 |
| %el.ptr = getelementptr i32, ptr %p, i64 %iv.wide |
| store i32 1, ptr %el.ptr |
| %iv.next = add nuw nsw i32 %iv, 4 |
| %loop_cond = icmp slt i32 %iv.next, %num_elements |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| |
| out_of_bounds: |
| ret i32 -1 |
| } |
| |
| ; Indvar base is non-overflowing binary 'or': |
| ; check that IRCE isn't trying to add NSW flag on it. |
| define i32 @binop_or_is_iv_base(ptr %p, i32 %end) { |
| ; CHECK-LABEL: define i32 @binop_or_is_iv_base |
| ; CHECK-SAME: (ptr [[P:%.*]], i32 [[END:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[N:%.*]] = load atomic i32, ptr [[P]] unordered, align 8, !range [[RNG8]] |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i32 [[END]], 7 |
| ; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_HEADER_PREHEADER:%.*]], label [[COMMON_RET:%.*]] |
| ; CHECK: loop.header.preheader: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add nuw nsw i32 [[N]], 7 |
| ; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[END]], i32 [[TMP0]]) |
| ; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 [[SMIN]], i32 7) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 7, [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_HEADER_PREHEADER1:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] |
| ; CHECK: loop.header.preheader1: |
| ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] |
| ; CHECK: loop.header: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_ADD:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_HEADER_PREHEADER1]] ] |
| ; CHECK-NEXT: [[CHECK:%.*]] = icmp ult i32 [[IV]], [[N]] |
| ; CHECK-NEXT: br i1 true, label [[GUARDED]], label [[DEOPT_LOOPEXIT2:%.*]] |
| ; CHECK: guarded: |
| ; CHECK-NEXT: [[IV_ADD]] = add i32 [[IV]], 8 |
| ; CHECK-NEXT: [[IV_OR:%.*]] = or i32 [[IV_ADD]], 7 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV_OR]], [[END]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[IV_OR]], [[EXIT_MAINLOOP_AT]] |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_HEADER]], label [[MAIN_EXIT_SELECTOR:%.*]] |
| ; CHECK: main.exit.selector: |
| ; CHECK-NEXT: [[IV_ADD_LCSSA:%.*]] = phi i32 [ [[IV_ADD]], [[GUARDED]] ] |
| ; CHECK-NEXT: [[IV_OR_LCSSA:%.*]] = phi i32 [ [[IV_OR]], [[GUARDED]] ] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[IV_OR_LCSSA]], [[END]] |
| ; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[COMMON_RET_LOOPEXIT:%.*]] |
| ; CHECK: main.pseudo.exit: |
| ; CHECK-NEXT: [[IV_COPY:%.*]] = phi i32 [ 0, [[LOOP_HEADER_PREHEADER]] ], [ [[IV_ADD_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 7, [[LOOP_HEADER_PREHEADER]] ], [ [[IV_OR_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] |
| ; CHECK-NEXT: br label [[POSTLOOP:%.*]] |
| ; CHECK: deopt.loopexit: |
| ; CHECK-NEXT: br label [[DEOPT:%.*]] |
| ; CHECK: deopt.loopexit2: |
| ; CHECK-NEXT: br label [[DEOPT]] |
| ; CHECK: deopt: |
| ; CHECK-NEXT: [[RV:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32(i32 13) [ "deopt"() ] |
| ; CHECK-NEXT: ret i32 [[RV]] |
| ; CHECK: common.ret.loopexit.loopexit: |
| ; CHECK-NEXT: br label [[COMMON_RET_LOOPEXIT]] |
| ; CHECK: common.ret.loopexit: |
| ; CHECK-NEXT: br label [[COMMON_RET]] |
| ; CHECK: common.ret: |
| ; CHECK-NEXT: ret i32 [[END]] |
| ; CHECK: postloop: |
| ; CHECK-NEXT: br label [[LOOP_HEADER_POSTLOOP:%.*]] |
| ; CHECK: loop.header.postloop: |
| ; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i32 [ [[IV_ADD_POSTLOOP:%.*]], [[GUARDED_POSTLOOP:%.*]] ], [ [[IV_COPY]], [[POSTLOOP]] ] |
| ; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp ult i32 [[IV_POSTLOOP]], [[N]] |
| ; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[GUARDED_POSTLOOP]], label [[DEOPT_LOOPEXIT:%.*]] |
| ; CHECK: guarded.postloop: |
| ; CHECK-NEXT: [[IV_ADD_POSTLOOP]] = add i32 [[IV_POSTLOOP]], 8 |
| ; CHECK-NEXT: [[IV_OR_POSTLOOP:%.*]] = or i32 [[IV_ADD_POSTLOOP]], 7 |
| ; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i32 [[IV_OR_POSTLOOP]], [[END]] |
| ; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_HEADER_POSTLOOP]], label [[COMMON_RET_LOOPEXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP21:![0-9]+]], !irce.loop.clone !6 |
| ; |
| entry: |
| %n = load atomic i32, ptr %p unordered, align 8, !range !1 |
| %cmp0 = icmp sgt i32 %end, 7 |
| br i1 %cmp0, label %loop.header, label %common.ret |
| |
| loop.header: |
| %iv = phi i32 [ %iv.add, %guarded ], [ 0, %entry ] |
| %check = icmp ult i32 %iv, %n |
| br i1 %check, label %guarded, label %deopt |
| |
| guarded: |
| %iv.add = add i32 %iv, 8 |
| %iv.or = or i32 %iv.add, 7 |
| %cmp = icmp slt i32 %iv.or, %end |
| br i1 %cmp, label %loop.header, label %common.ret |
| |
| deopt: |
| %rv = call i32 (...) @llvm.experimental.deoptimize.i32(i32 13) [ "deopt"() ] |
| ret i32 %rv |
| |
| common.ret: |
| ret i32 %end |
| } |
| |
| declare i32 @llvm.experimental.deoptimize.i32(...) |
| |
| !0 = !{i32 0, i32 50} |
| !1 = !{i32 0, i32 2147483640} |
| !2 = !{i32 0, i32 2147483641} |
| !3 = !{i32 10, i32 50} |
| !4 = !{i32 1, i32 2147483648} |
| !5 = !{!"branch_weights", i32 1000, i32 1} |
| !6 = !{!"branch_weights", i32 1, i32 1000} |