blob: bff7996785c2746195af2fc60dcff8cfbc6ace94 [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
; If x <u y and y <=u INT_MIN, then x >=s 0.
; If x <=u y and y <=u INT_MAX, then x >=s 0.
; In these tests the guard compares y with x, and the exit compares
; smax(x, w) with a constant.
target datalayout = "e-m:e-i64:64-n8:16:32:64-S128"
; If y >u x and y <=u INT_MIN, then x >=s 0, which implies smax(x, w) >s -1.
define void @ugt_smin(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @ugt_smin(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]]
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Y]], [[X]]
; 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 %p, !range !2
%c = icmp ugt i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp slt i32 %m, 0
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 y >=u x and y <=u INT_MAX, then x >=s 0, which implies smax(x, w) >s -1.
define void @uge(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @uge(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1:![0-9]+]]
; CHECK-NEXT: [[C:%.*]] = icmp uge i32 [[Y]], [[X]]
; 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 %p, !range !1
%c = icmp uge i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp slt i32 %m, 0
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 y >u x and y <u INT_MAX, then x >=s 0, which implies smax(x, w) >s -1.
define void @ugt_sle(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @ugt_sle(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG2:![0-9]+]]
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Y]], [[X]]
; 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 %p, !range !0
%c = icmp ugt i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp sle i32 %m, -1
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 y >u x and y <u INT_MAX, then x >=s 0, which implies smax(x, w) >=s 0.
define void @ugt_sge(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @ugt_sge(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG2]]
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Y]], [[X]]
; 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 true, 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 %p, !range !0
%c = icmp ugt i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp sge i32 %m, 0
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 y >u x and y <u INT_MAX, then x >=s 0, which implies smax(x, w) >=s -5.
define void @ugt_weaker(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @ugt_weaker(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG2]]
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Y]], [[X]]
; 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 %p, !range !0
%c = icmp ugt i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp slt i32 %m, -5
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 y >u x and y <=u INT_MIN + 1, x may be INT_MIN. So smax(x, w) <s 0 cannot
; be folded.
define void @neg_ugt_smin_plus_1(i32 %x, i32 %w, ptr %p) {
; CHECK-LABEL: define void @neg_ugt_smin_plus_1(
; CHECK-SAME: i32 [[X:%.*]], i32 [[W:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG3:![0-9]+]]
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Y]], [[X]]
; 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: [[M:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 [[W]])
; CHECK-NEXT: [[Q:%.*]] = icmp slt i32 [[M]], 0
; CHECK-NEXT: br i1 [[Q]], 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 %p, !range !3
%c = icmp ugt i32 %y, %x
br i1 %c, label %loop, label %exit
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
%m = call i32 @llvm.smax.i32(i32 %x, i32 %w)
%q = icmp slt i32 %m, 0
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)
!0 = !{i32 0, i32 2147483647}
; [0, INT_MAX]
!1 = !{i32 0, i32 -2147483648}
; [0, INT_MIN] as unsigned
!2 = !{i32 0, i32 -2147483647}
; [0, INT_MIN + 1] as unsigned
!3 = !{i32 0, i32 -2147483646}
;.
; CHECK: [[RNG0]] = !{i32 0, i32 -2147483647}
; CHECK: [[RNG1]] = !{i32 0, i32 -2147483648}
; CHECK: [[RNG2]] = !{i32 0, i32 2147483647}
; CHECK: [[RNG3]] = !{i32 0, i32 -2147483646}
;.