| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -passes=indvars -S < %s | FileCheck %s | |
| ; Check that an exit condition is proven from a guard with a predicate of | |
| ; different signedness. | |
| target datalayout = "e-m:e-i64:64-n8:16:32:64-S128" | |
| ; If x <u y, x <s 0 and y <s 0, then x <s y, which implies | |
| ; smin(x, w) <s y + 1. | |
| define void @same_sign(ptr %px, ptr %py, i32 %w) { | |
| ; CHECK-LABEL: define void @same_sign( | |
| ; CHECK-SAME: ptr [[PX:%.*]], ptr [[PY:%.*]], i32 [[W:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[PX]], align 4, !range [[RNG0:![0-9]+]] | |
| ; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[PY]], align 4, !range [[RNG0]] | |
| ; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X]], [[Y]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] | |
| ; CHECK: [[LOOP_PREHEADER]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], %[[LATCH:.*]] ], [ 0, %[[LOOP_PREHEADER]] ] | |
| ; CHECK-NEXT: br i1 false, label %[[EXIT_LOOPEXIT:.*]], label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: call void @side() | |
| ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1 | |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[I_NEXT]], 100 | |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[LOOP]], label %[[EXIT_LOOPEXIT]] | |
| ; CHECK: [[EXIT_LOOPEXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %x = load i32, ptr %px, !range !1 | |
| %y = load i32, ptr %py, !range !1 | |
| %c = icmp ult i32 %x, %y | |
| br i1 %c, label %loop, label %exit | |
| loop: | |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] | |
| %m = call i32 @llvm.smin.i32(i32 %x, i32 %w) | |
| %y.1 = add nsw i32 %y, 1 | |
| %q = icmp sle i32 %y.1, %m | |
| br i1 %q, label %exit, label %latch | |
| latch: | |
| call void @side() | |
| %i.next = add nuw nsw i32 %i, 1 | |
| %ec = icmp ult i32 %i.next, 100 | |
| br i1 %ec, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| ; If x <u y and y <u INT_MAX - 1, then umin(x, w) <u y + 1 and y + 1 >=s 0, | |
| ; which implies umin(x, w) <s y + 1. | |
| define void @ult_nonneg(i32 %x, ptr %py, i32 %w) { | |
| ; CHECK-LABEL: define void @ult_nonneg( | |
| ; CHECK-SAME: i32 [[X:%.*]], ptr [[PY:%.*]], i32 [[W:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[PY]], align 4, !range [[RNG1:![0-9]+]] | |
| ; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X]], [[Y]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] | |
| ; CHECK: [[LOOP_PREHEADER]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], %[[LATCH:.*]] ], [ 0, %[[LOOP_PREHEADER]] ] | |
| ; CHECK-NEXT: br i1 false, label %[[EXIT_LOOPEXIT:.*]], label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: call void @side() | |
| ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1 | |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[I_NEXT]], 100 | |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[LOOP]], label %[[EXIT_LOOPEXIT]] | |
| ; CHECK: [[EXIT_LOOPEXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %y = load i32, ptr %py, !range !0 | |
| %c = icmp ult i32 %x, %y | |
| br i1 %c, label %loop, label %exit | |
| loop: | |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] | |
| %m = call i32 @llvm.umin.i32(i32 %x, i32 %w) | |
| %y.1 = add nuw nsw i32 %y, 1 | |
| %q = icmp sle i32 %y.1, %m | |
| br i1 %q, label %exit, label %latch | |
| latch: | |
| call void @side() | |
| %i.next = add nuw nsw i32 %i, 1 | |
| %ec = icmp ult i32 %i.next, 100 | |
| br i1 %ec, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| ; If x <s y and y <s -1, then smin(x, w) <s y + 1 and y + 1 <s 0, which | |
| ; implies smin(x, w) <u y + 1. | |
| define void @slt_neg(i32 %x, ptr %py, i32 %w) { | |
| ; CHECK-LABEL: define void @slt_neg( | |
| ; CHECK-SAME: i32 [[X:%.*]], ptr [[PY:%.*]], i32 [[W:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[PY]], align 4, !range [[RNG0]] | |
| ; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[X]], [[Y]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]] | |
| ; CHECK: [[LOOP_PREHEADER]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], %[[LATCH:.*]] ], [ 0, %[[LOOP_PREHEADER]] ] | |
| ; CHECK-NEXT: br i1 false, label %[[EXIT_LOOPEXIT:.*]], label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: call void @side() | |
| ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1 | |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[I_NEXT]], 100 | |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[LOOP]], label %[[EXIT_LOOPEXIT]] | |
| ; CHECK: [[EXIT_LOOPEXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %y = load i32, ptr %py, !range !1 | |
| %c = icmp slt i32 %x, %y | |
| br i1 %c, label %loop, label %exit | |
| loop: | |
| %i = phi i32 [ 0, %entry ], [ %i.next, %latch ] | |
| %m = call i32 @llvm.smin.i32(i32 %x, i32 %w) | |
| %y.1 = add nsw i32 %y, 1 | |
| %q = icmp ule i32 %y.1, %m | |
| br i1 %q, label %exit, label %latch | |
| latch: | |
| call void @side() | |
| %i.next = add nuw nsw i32 %i, 1 | |
| %ec = icmp ult i32 %i.next, 100 | |
| br i1 %ec, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| declare void @side() | |
| ; [0, INT_MAX - 1) | |
| !0 = !{i32 0, i32 2147483646} | |
| ; [-100, -1) | |
| !1 = !{i32 -100, i32 -1} | |
| ;. | |
| ; CHECK: [[RNG0]] = !{i32 -100, i32 -1} | |
| ; CHECK: [[RNG1]] = !{i32 0, i32 2147483646} | |
| ;. |