blob: c8551aae63a1c51387499e0216c78186d8163479 [file] [edit]
; 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}
;.