| ; 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 |
| } |