; 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> ) %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> ) %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> ) ; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> ) ; 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> ) %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> ) %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> ) ; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> ) ; 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> ) %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> ) %cmp = icmp eq <2 x i32> %v2, %x ret <2 x i1> %cmp }