blob: 4866dbffb567a98da02123fd662b56678bb20800 [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare void @use(i32)
define i1 @test_i32_eq(i32 %x) {
; CHECK-LABEL: define i1 @test_i32_eq(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 95
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 256
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
define i1 @test_i32_ne(i32 %x) {
; CHECK-LABEL: define i1 @test_i32_ne(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -161
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -256
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp ne i32 %v2, %x
ret i1 %cmp
}
define i1 @test_i32_eq_no_add(i32 %x) {
; CHECK-LABEL: define i1 @test_i32_eq_no_add(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X]], 161
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
define i1 @test_i32_ne_no_add(i32 %x) {
; CHECK-LABEL: define i1 @test_i32_ne_no_add(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 160
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp ne i32 %v2, %x
ret i1 %cmp
}
define i1 @test_unsigned_eq(i32 %x) {
; CHECK-LABEL: define i1 @test_unsigned_eq(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -10
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 91
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
define i1 @test_unsigned_ne(i32 %x) {
; CHECK-LABEL: define i1 @test_unsigned_ne(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -101
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -91
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
%cmp = icmp ne i32 %v2, %x
ret i1 %cmp
}
; Different bit widths
define i1 @test_i8_eq(i8 %x) {
; CHECK-LABEL: define i1 @test_i8_eq(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], 50
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], 101
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i8 @llvm.smax.i8(i8 %x, i8 -50)
%v2 = tail call i8 @llvm.smin.i8(i8 %v1, i8 50)
%cmp = icmp eq i8 %v2, %x
ret i1 %cmp
}
define i1 @test_i16_eq(i16 %x) {
; CHECK-LABEL: define i1 @test_i16_eq(
; CHECK-SAME: i16 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[X]], 1000
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[TMP1]], 2001
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i16 @llvm.smax.i16(i16 %x, i16 -1000)
%v2 = tail call i16 @llvm.smin.i16(i16 %v1, i16 1000)
%cmp = icmp eq i16 %v2, %x
ret i1 %cmp
}
define i1 @test_i64_eq(i64 %x) {
; CHECK-LABEL: define i1 @test_i64_eq(
; CHECK-SAME: i64 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i64 @llvm.smax.i64(i64 %x, i64 -1)
%v2 = tail call i64 @llvm.smin.i64(i64 %v1, i64 9223372036854775806)
%cmp = icmp eq i64 %v2, %x
ret i1 %cmp
}
; Negative tests - wrong predicate
define i1 @test_wrong_pred_slt(i32 %x) {
; CHECK-LABEL: define i1 @test_wrong_pred_slt(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], 160
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp slt i32 %v2, %x
ret i1 %cmp
}
; Negative tests - not a clamp pattern
define i1 @test_not_clamp_pattern(i32 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_not_clamp_pattern(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[Y]], i32 -95)
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %y, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Negative tests - Lo >= Hi
define i1 @test_invalid_range(i32 %x) {
; CHECK-LABEL: define i1 @test_invalid_range(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 50
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 100)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 50)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Negative tests - Lo is minimum signed value
define i1 @test_lo_min_signed(i32 %x) {
; CHECK-LABEL: define i1 @test_lo_min_signed(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 161
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -2147483648)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Negative tests - Hi is maximum signed value
define i1 @test_hi_max_signed(i32 %x) {
; CHECK-LABEL: define i1 @test_hi_max_signed(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], -96
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 2147483647)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Negative tests - Hi is maximum unsigned value
define i1 @test_hi_max_unsigned(i32 %x) {
; CHECK-LABEL: define i1 @test_hi_max_unsigned(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 9
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 4294967295)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Multi-use tests - multiple uses of max
define i1 @test_multi_use_max(i32 %x) {
; CHECK-LABEL: define i1 @test_multi_use_max(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
; CHECK-NEXT: call void @use(i32 [[V1]])
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
call void @use(i32 %v1)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Multi-use tests - multiple uses of min
define i1 @test_multi_use_min(i32 %x) {
; CHECK-LABEL: define i1 @test_multi_use_min(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
; CHECK-NEXT: call void @use(i32 [[V2]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
call void @use(i32 %v2)
%cmp = icmp eq i32 %v2, %x
ret i1 %cmp
}
; Commuted tests
define i1 @test_commuted_eq(i32 %x) {
; CHECK-LABEL: define i1 @test_commuted_eq(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 95
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 256
; CHECK-NEXT: ret i1 [[CMP]]
;
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
%cmp = icmp eq i32 %x, %v2
ret i1 %cmp
}
; Vector tests - splat constants
define <2 x i1> @test_vec_splat_eq(<2 x i32> %x) {
; CHECK-LABEL: define <2 x i1> @test_vec_splat_eq(
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X]], splat (i32 50)
; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i32> [[TMP1]], splat (i32 101)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -50>)
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 50>)
%cmp = icmp eq <2 x i32> %v2, %x
ret <2 x i1> %cmp
}
; Vector tests - poison elements
define <2 x i1> @test_vec_poison_eq(<2 x i32> %x) {
; CHECK-LABEL: define <2 x i1> @test_vec_poison_eq(
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 poison>)
; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 poison>)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 poison>)
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 poison>)
%cmp = icmp eq <2 x i32> %v2, %x
ret <2 x i1> %cmp
}
; Vector tests - non-splat
define <2 x i1> @test_vec_non_splat_eq(<2 x i32> %x) {
; CHECK-LABEL: define <2 x i1> @test_vec_non_splat_eq(
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 -30>)
; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 70>)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -30>)
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 70>)
%cmp = icmp eq <2 x i32> %v2, %x
ret <2 x i1> %cmp
}