| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S %s -passes='loop-mssa(licm)' -verify-memoryssa | FileCheck %s |
| |
| ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ult(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: pointer types. |
| define ptr @test_ult_ptr_neg(ptr %start, ptr %inv_1, ptr %inv_2) { |
| ; CHECK-LABEL: @test_ult_ptr_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi ptr [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult ptr [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult ptr [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = getelementptr i32, ptr [[IV]], i64 4 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi ptr [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret ptr [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi ptr [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult ptr %iv, %inv_1 |
| %cmp_2 = icmp ult ptr %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = getelementptr i32, ptr %iv, i64 4 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret ptr %iv |
| } |
| |
| ; turn to %iv <=u umin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ule(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ule( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ule i32 %iv, %inv_1 |
| %cmp_2 = icmp ule i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <s smin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_slt(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_slt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp slt i32 %iv, %inv_1 |
| %cmp_2 = icmp slt i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <=s smin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sle(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sle( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sle i32 %iv, %inv_1 |
| %cmp_2 = icmp sle i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >u umax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ugt(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ugt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ugt i32 %iv, %inv_1 |
| %cmp_2 = icmp ugt i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_uge(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_uge( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp uge i32 %iv, %inv_1 |
| %cmp_2 = icmp uge i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sgt(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sgt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sgt i32 %iv, %inv_1 |
| %cmp_2 = icmp sgt i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sge(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sge( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sge i32 %iv, %inv_1 |
| %cmp_2 = icmp sge i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_ult_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_ule_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ule_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ule i32 %iv, %inv_1 |
| %cmp_2 = icmp ule i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_slt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_slt_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp slt i32 %iv, %inv_1 |
| %cmp_2 = icmp slt i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_sle_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sle_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sle i32 %iv, %inv_1 |
| %cmp_2 = icmp sle i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_ugt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ugt_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ugt i32 %iv, %inv_1 |
| %cmp_2 = icmp ugt i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_uge_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_uge_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp uge i32 %iv, %inv_1 |
| %cmp_2 = icmp uge i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_sgt_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sgt_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sgt i32 %iv, %inv_1 |
| %cmp_2 = icmp sgt i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Turn OR to AND and handle accordingly. |
| define i32 @test_sge_inv(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sge_inv( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sge i32 %iv, %inv_1 |
| %cmp_2 = icmp sge i32 %iv, %inv_2 |
| %loop_cond = or i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ult_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ugt i32 %inv_1, %iv |
| %cmp_2 = icmp ugt i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <=u umin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ule_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ule_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp uge i32 %inv_1, %iv |
| %cmp_2 = icmp uge i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <s smin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_slt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_slt_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sgt i32 %inv_1, %iv |
| %cmp_2 = icmp sgt i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <=s smin(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sle_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sle_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sge i32 %inv_1, %iv |
| %cmp_2 = icmp sge i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >u umax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_ugt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ugt_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %inv_1, %iv |
| %cmp_2 = icmp ult i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_uge_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_uge_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ule i32 %inv_1, %iv |
| %cmp_2 = icmp ule i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sgt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sgt_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp slt i32 %inv_1, %iv |
| %cmp_2 = icmp slt i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop. |
| define i32 @test_sge_swapped(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_sge_swapped( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp sle i32 %inv_1, %iv |
| %cmp_2 = icmp sle i32 %inv_2, %iv |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; inv_2 needs freeze because hoisted umax would create a new use that didn't exist before. |
| ; Counter-example: %cmp_1 = false, %inv_2 = poison. |
| define i32 @test_logical_and_ult_needs_freeze(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_logical_and_ult_needs_freeze( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]] |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = select i1 %cmp_1, i1 %cmp_2, i1 false |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop. |
| ; https://alive2.llvm.org/ce/z/mhKGtT |
| define i32 @test_logical_and_ult_pos(i32 %start, i32 %inv_1, i32 noundef %inv_2) { |
| ; CHECK-LABEL: @test_logical_and_ult_pos( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]] |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = select i1 %cmp_1, i1 %cmp_2, i1 false |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; inv_2 needs freeze because hoisted umax would create a new use that didn't exist before. |
| define i32 @test_logical_or_ult_inv_needs_freeze(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_logical_or_ult_inv_needs_freeze( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]] |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = select i1 %cmp_1, i1 true, i1 %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; turn to %iv <u umax(inv_1, inv_2) and hoist it out of loop. |
| ; https://alive2.llvm.org/ce/z/zgyG5N |
| define i32 @test_logical_or_ult_inv_pos(i32 %start, i32 %inv_1, i32 noundef %inv_2) { |
| ; CHECK-LABEL: @test_logical_or_ult_inv_pos( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]] |
| ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = select i1 %cmp_1, i1 true, i1 %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Mismatched predicates, do not optimize. |
| define i32 @test_mismatched_predicates_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_mismatched_predicates_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ule i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; TODO: Turn ule against constant into ult against constant, then do the same as in test_ult. |
| ; https://alive2.llvm.org/ce/z/rucunQ |
| define i32 @test_mismatched_predicates_constant_pos_1(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_mismatched_predicates_constant_pos_1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], 100 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ule i32 %iv, 100 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; TODO: Turn ult against a constant into ule, then do the same as in test_ule. |
| ; https://alive2.llvm.org/ce/z/-ht-pU |
| define i32 @test_mismatched_predicates_constant_pos_2(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_mismatched_predicates_constant_pos_2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], 100 |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, 100 |
| %cmp_2 = icmp ule i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: `ule -1` cannot be turned into `ult 0` because of overflow. |
| ; However, this condition is trivially true anyways, so do not bother about it. |
| define i32 @test_mismatched_predicates_constant_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_mismatched_predicates_constant_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], -1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ule i32 %iv, -1 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: predicate eq. |
| define i32 @test_eq_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_eq_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp eq i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp eq i32 %iv, %inv_1 |
| %cmp_2 = icmp eq i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: predicate ne. |
| define i32 @test_ne_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ne_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ne i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ne i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ne i32 %iv, %inv_1 |
| %cmp_2 = icmp ne i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: extra use. |
| define i32 @test_ult_extra_use_1_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_extra_use_1_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1_LCSSA:%.*]] = phi i1 [ [[CMP_1]], [[LOOP]] ] |
| ; CHECK-NEXT: call void @use(i1 [[CMP_1_LCSSA]]) |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| call void @use(i1 %cmp_1) |
| ret i32 %iv |
| } |
| |
| define i32 @test_ult_extra_use_2_neg(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_extra_use_2_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_2_LCSSA:%.*]] = phi i1 [ [[CMP_2]], [[LOOP]] ] |
| ; CHECK-NEXT: call void @use(i1 [[CMP_2_LCSSA]]) |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| call void @use(i1 %cmp_2) |
| ret i32 %iv |
| } |
| |
| ; This can be optimized, despite the fact that loop_cond has other uses. |
| define i32 @test_ult_extra_use_result_pos(i32 %start, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_extra_use_result_pos( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ] |
| ; CHECK-NEXT: [[LOOP_COND_LCSSA:%.*]] = phi i1 [ [[LOOP_COND]], [[LOOP]] ] |
| ; CHECK-NEXT: call void @use(i1 [[LOOP_COND_LCSSA]]) |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [%start, %entry], [%iv.next, %loop] |
| %cmp_1 = icmp ult i32 %iv, %inv_1 |
| %cmp_2 = icmp ult i32 %iv, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv.next = add i32 %iv, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| call void @use(i1 %loop_cond) |
| ret i32 %iv |
| } |
| |
| ; Do not optimize: comparison against different variant values. |
| define i32 @test_ult_different_variants_neg(i32 %start_1, i32 %start_2, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_different_variants_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV_1:%.*]] = phi i32 [ [[START_1:%.*]], [[ENTRY:%.*]] ], [ [[IV_1_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_2:%.*]] = phi i32 [ [[START_2:%.*]], [[ENTRY]] ], [ [[IV_2_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV_1]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV_2]], [[INV_2:%.*]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_1_NEXT]] = add i32 [[IV_1]], 1 |
| ; CHECK-NEXT: [[IV_2_NEXT]] = add i32 [[IV_2]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i32 [ [[IV_1]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_1_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv_1 = phi i32 [%start_1, %entry], [%iv_1.next, %loop] |
| %iv_2 = phi i32 [%start_2, %entry], [%iv_2.next, %loop] |
| %cmp_1 = icmp ult i32 %iv_1, %inv_1 |
| %cmp_2 = icmp ult i32 %iv_2, %inv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv_1.next = add i32 %iv_1, 1 |
| %iv_2.next = add i32 %iv_2, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv_1 |
| } |
| |
| ; Do not optimize: one of comparisons is against loop-variant. |
| define i32 @test_ult_compare_against_variant_neg(i32 %start_1, i32 %start_2, i32 %inv_1, i32 %inv_2) { |
| ; CHECK-LABEL: @test_ult_compare_against_variant_neg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV_1:%.*]] = phi i32 [ [[START_1:%.*]], [[ENTRY:%.*]] ], [ [[IV_1_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_2:%.*]] = phi i32 [ [[START_2:%.*]], [[ENTRY]] ], [ [[IV_2_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV_1]], [[INV_1:%.*]] |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV_1]], [[IV_2]] |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]] |
| ; CHECK-NEXT: [[IV_1_NEXT]] = add i32 [[IV_1]], 1 |
| ; CHECK-NEXT: [[IV_2_NEXT]] = add i32 [[IV_2]], 1 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i32 [ [[IV_1]], [[LOOP]] ] |
| ; CHECK-NEXT: ret i32 [[IV_1_LCSSA]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %iv_1 = phi i32 [%start_1, %entry], [%iv_1.next, %loop] |
| %iv_2 = phi i32 [%start_2, %entry], [%iv_2.next, %loop] |
| %cmp_1 = icmp ult i32 %iv_1, %inv_1 |
| %cmp_2 = icmp ult i32 %iv_1, %iv_2 |
| %loop_cond = and i1 %cmp_1, %cmp_2 |
| %iv_1.next = add i32 %iv_1, 1 |
| %iv_2.next = add i32 %iv_2, 1 |
| br i1 %loop_cond, label %loop, label %exit |
| |
| exit: |
| ret i32 %iv_1 |
| } |
| |
| declare void @use(i1) |