| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes=indvars -S %s | FileCheck %s |
| |
| define i8 @smax_exit_from_smin(i32 %start, i32 %limit) { |
| ; CHECK-LABEL: define i8 @smax_exit_from_smin( |
| ; CHECK-SAME: i32 [[START:%.*]], i32 [[LIMIT:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[CMP13:%.*]] = icmp slt i32 [[START]], 0 |
| ; CHECK-NEXT: br i1 [[CMP13]], label %[[PH1:.*]], label %[[EXIT_A:.*]] |
| ; CHECK: [[PH1]]: |
| ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i32 [[START]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[EXIT_B:.*]], label %[[PH2:.*]] |
| ; CHECK: [[PH2]]: |
| ; CHECK-NEXT: [[SMIN:%.*]] = tail call i32 @llvm.smin.i32(i32 [[LIMIT]], i32 0) |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: [[K:%.*]] = phi i32 [ [[INC:%.*]], %[[LOOP]] ], [ [[START]], %[[PH2]] ] |
| ; CHECK-NEXT: call void @use() |
| ; CHECK-NEXT: [[INC]] = add i32 [[K]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[K]], [[SMIN]] |
| ; CHECK-NEXT: br i1 [[COND]], label %[[LOOP]], label %[[LOOP_EXIT:.*]] |
| ; CHECK: [[LOOP_EXIT]]: |
| ; CHECK-NEXT: ret i8 0 |
| ; CHECK: [[EXIT_B]]: |
| ; CHECK-NEXT: ret i8 1 |
| ; CHECK: [[EXIT_A]]: |
| ; CHECK-NEXT: ret i8 2 |
| ; |
| entry: |
| %cmp13 = icmp slt i32 %start, 0 |
| br i1 %cmp13, label %ph1, label %exit.a |
| |
| ph1: |
| %cmp.not = icmp sgt i32 %start, %limit |
| br i1 %cmp.not, label %exit.b, label %ph2 |
| |
| ph2: |
| %smin = tail call i32 @llvm.smin.i32(i32 %limit, i32 0) |
| br label %loop |
| |
| loop: |
| %k = phi i32 [ %inc, %loop ], [ %start, %ph2 ] |
| call void @use() |
| %inc = add i32 %k, 1 |
| %cond = icmp slt i32 %k, %smin |
| br i1 %cond, label %loop, label %loop.exit |
| |
| loop.exit: |
| ret i8 0 |
| |
| exit.b: |
| ret i8 1 |
| |
| exit.a: |
| ret i8 2 |
| } |
| |
| ; TODO: Unsigned counterpart of @smax_exit_from_smin; umax should be folded. |
| define i8 @umax_exit_from_umin(i32 %start, i32 %limit) { |
| ; CHECK-LABEL: define i8 @umax_exit_from_umin( |
| ; CHECK-SAME: i32 [[START:%.*]], i32 [[LIMIT:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[CMP13:%.*]] = icmp ult i32 [[START]], 100 |
| ; CHECK-NEXT: br i1 [[CMP13]], label %[[PH1:.*]], label %[[EXIT_A:.*]] |
| ; CHECK: [[PH1]]: |
| ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp ugt i32 [[START]], [[LIMIT]] |
| ; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[EXIT_B:.*]], label %[[PH2:.*]] |
| ; CHECK: [[PH2]]: |
| ; CHECK-NEXT: [[UMIN:%.*]] = tail call i32 @llvm.umin.i32(i32 [[LIMIT]], i32 100) |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: [[K:%.*]] = phi i32 [ [[INC:%.*]], %[[LOOP]] ], [ [[START]], %[[PH2]] ] |
| ; CHECK-NEXT: call void @use() |
| ; CHECK-NEXT: [[INC]] = add i32 [[K]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[K]], [[UMIN]] |
| ; CHECK-NEXT: br i1 [[COND]], label %[[LOOP]], label %[[LOOP_EXIT:.*]] |
| ; CHECK: [[LOOP_EXIT]]: |
| ; CHECK-NEXT: ret i8 0 |
| ; CHECK: [[EXIT_B]]: |
| ; CHECK-NEXT: ret i8 1 |
| ; CHECK: [[EXIT_A]]: |
| ; CHECK-NEXT: ret i8 2 |
| ; |
| entry: |
| %cmp13 = icmp ult i32 %start, 100 |
| br i1 %cmp13, label %ph1, label %exit.a |
| |
| ph1: |
| %cmp.not = icmp ugt i32 %start, %limit |
| br i1 %cmp.not, label %exit.b, label %ph2 |
| |
| ph2: |
| %umin = tail call i32 @llvm.umin.i32(i32 %limit, i32 100) |
| br label %loop |
| |
| loop: |
| %k = phi i32 [ %inc, %loop ], [ %start, %ph2 ] |
| call void @use() |
| %inc = add i32 %k, 1 |
| %cond = icmp ult i32 %k, %umin |
| br i1 %cond, label %loop, label %loop.exit |
| |
| loop.exit: |
| ret i8 0 |
| |
| exit.b: |
| ret i8 1 |
| |
| exit.a: |
| ret i8 2 |
| } |
| |
| ; Negative test: signed exit with an unsigned-max bound must not be folded. |
| define i8 @signed_exit_not_eliminated_from_umax(i32 %start, i32 %a, i32 %b) { |
| ; CHECK-LABEL: define i8 @signed_exit_not_eliminated_from_umax( |
| ; CHECK-SAME: i32 [[START:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[G:%.*]] = icmp sgt i32 [[START]], [[A]] |
| ; CHECK-NEXT: br i1 [[G]], label %[[EXIT_B:.*]], label %[[PH2:.*]] |
| ; CHECK: [[PH2]]: |
| ; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 [[B]]) |
| ; CHECK-NEXT: [[PRE:%.*]] = icmp slt i32 [[START]], [[UMAX]] |
| ; CHECK-NEXT: br i1 [[PRE]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT_B]] |
| ; CHECK: [[LOOP_PREHEADER]]: |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: [[K:%.*]] = phi i32 [ [[INC:%.*]], %[[LOOP]] ], [ [[START]], %[[LOOP_PREHEADER]] ] |
| ; CHECK-NEXT: call void @use() |
| ; CHECK-NEXT: [[INC]] = add i32 [[K]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[K]], [[UMAX]] |
| ; CHECK-NEXT: br i1 [[COND]], label %[[LOOP]], label %[[LOOP_EXIT:.*]] |
| ; CHECK: [[LOOP_EXIT]]: |
| ; CHECK-NEXT: ret i8 0 |
| ; CHECK: [[EXIT_B]]: |
| ; CHECK-NEXT: ret i8 1 |
| ; |
| entry: |
| %g = icmp sgt i32 %start, %a |
| br i1 %g, label %exit.b, label %ph2 |
| |
| ph2: |
| %umax = call i32 @llvm.umax.i32(i32 %a, i32 %b) |
| %pre = icmp slt i32 %start, %umax |
| br i1 %pre, label %loop, label %exit.b |
| |
| loop: |
| %k = phi i32 [ %inc, %loop ], [ %start, %ph2 ] |
| call void @use() |
| %inc = add i32 %k, 1 |
| %cond = icmp slt i32 %k, %umax |
| br i1 %cond, label %loop, label %loop.exit |
| |
| loop.exit: |
| ret i8 0 |
| |
| exit.b: |
| ret i8 1 |
| } |
| |
| declare void @use() |