| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt -S -passes=instcombine < %s | FileCheck %s |
| |
| declare void @use.i1(i1 %x) |
| declare void @use.i64(i64 %x) |
| declare void @use.i64i1({i64, i1} %x) |
| |
| define i1 @umul_greater_than_or_overflow_const(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[IN]], 109802048057794950 |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 168) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, -16 |
| %ret = or i1 %ovf, %cmp |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_i8(i8 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_i8( |
| ; CHECK-SAME: i8 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i8 [[IN]], 10 |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %in, i8 24) |
| %mul = extractvalue { i8, i1 } %mwo, 0 |
| %ovf = extractvalue { i8, i1 } %mwo, 1 |
| %cmp = icmp ugt i8 %mul, -16 |
| %ret = or i1 %ovf, %cmp |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_commuted(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_commuted( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[IN]], 192153584101141162 |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or i1 %cmp, %ovf |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_disjoint(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_disjoint( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[IN]], 230584300921369395 |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 40) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or disjoint i1 %ovf, %cmp |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_multiuse_mul(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_multiuse_mul( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[IN]], 48 |
| ; CHECK-NEXT: [[RET:%.*]] = icmp ugt i64 [[IN]], 192153584101141162 |
| ; CHECK-NEXT: tail call void @use.i64(i64 [[MUL]]) |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or i1 %ovf, %cmp |
| tail call void @use.i64(i64 %mul) |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_multiuse_overflow(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_multiuse_overflow( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[OVF:%.*]] = icmp ugt i64 [[IN]], 384307168202282325 |
| ; CHECK-NEXT: [[RET:%.*]] = icmp ugt i64 [[IN]], 192153584101141162 |
| ; CHECK-NEXT: tail call void @use.i1(i1 [[OVF]]) |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or i1 %ovf, %cmp |
| tail call void @use.i1(i1 %ovf) |
| ret i1 %ret |
| } |
| |
| define i1 @umul_greater_than_or_overflow_const_multiuse_umul_call(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_multiuse_umul_call( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[MWO:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[IN]], i64 48) |
| ; CHECK-NEXT: [[RET:%.*]] = icmp ugt i64 [[IN]], 192153584101141162 |
| ; CHECK-NEXT: tail call void @use.i64i1({ i64, i1 } [[MWO]]) |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or i1 %ovf, %cmp |
| tail call void @use.i64i1({ i64, i1 } %mwo) |
| ret i1 %ret |
| } |
| |
| define <2 x i1> @umul_greater_than_or_overflow_const_vector_splat(<2 x i64> %in) { |
| ; CHECK-LABEL: define <2 x i1> @umul_greater_than_or_overflow_const_vector_splat( |
| ; CHECK-SAME: <2 x i64> [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt <2 x i64> [[IN]], splat (i64 6477087104532848) |
| ; CHECK-NEXT: ret <2 x i1> [[TMP6]] |
| ; |
| %mwo = tail call { <2 x i64>, <2 x i1> } @llvm.umul.with.overflow.v2i64(<2 x i64> %in, <2 x i64> <i64 1424, i64 1424>) |
| %mul = extractvalue { <2 x i64>, <2 x i1> } %mwo, 0 |
| %ovf = extractvalue { <2 x i64>, <2 x i1> } %mwo, 1 |
| %cmp = icmp ugt <2 x i64> %mul, <i64 9223372036854775800, i64 9223372036854775800> |
| %ret = or <2 x i1> %ovf, %cmp |
| ret <2 x i1> %ret |
| } |
| |
| ; Negative test |
| define <4 x i1> @umul_greater_than_or_overflow_const_vector_non_splat_negative(<4 x i64> %in) { |
| ; CHECK-LABEL: define <4 x i1> @umul_greater_than_or_overflow_const_vector_non_splat_negative( |
| ; CHECK-SAME: <4 x i64> [[IN:%.*]]) { |
| ; CHECK-NEXT: [[MWO:%.*]] = tail call { <4 x i64>, <4 x i1> } @llvm.umul.with.overflow.v4i64(<4 x i64> [[IN]], <4 x i64> <i64 24, i64 1424, i64 0, i64 -1>) |
| ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { <4 x i64>, <4 x i1> } [[MWO]], 0 |
| ; CHECK-NEXT: [[OVF:%.*]] = extractvalue { <4 x i64>, <4 x i1> } [[MWO]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <4 x i64> [[MUL]], <i64 9223372036854775000, i64 9223372036854775800, i64 -16, i64 -16> |
| ; CHECK-NEXT: [[RET:%.*]] = or <4 x i1> [[OVF]], [[CMP]] |
| ; CHECK-NEXT: ret <4 x i1> [[RET]] |
| ; |
| %mwo = tail call { <4 x i64>, <4 x i1> } @llvm.umul.with.overflow.v2i64(<4 x i64> %in, <4 x i64> <i64 24, i64 1424, i64 0, i64 -1>) |
| %mul = extractvalue { <4 x i64>, <4 x i1> } %mwo, 0 |
| %ovf = extractvalue { <4 x i64>, <4 x i1> } %mwo, 1 |
| %cmp = icmp ugt <4 x i64> %mul, <i64 9223372036854775000, i64 9223372036854775800, i64 -16, i64 -16> |
| %ret = or <4 x i1> %ovf, %cmp |
| ret <4 x i1> %ret |
| } |
| |
| ; Negative test |
| define <2 x i1> @umul_greater_than_or_overflow_const_vector_poison_non_splat_negative(<2 x i64> %in) { |
| ; CHECK-LABEL: define <2 x i1> @umul_greater_than_or_overflow_const_vector_poison_non_splat_negative( |
| ; CHECK-SAME: <2 x i64> [[IN:%.*]]) { |
| ; CHECK-NEXT: [[MWO:%.*]] = tail call { <2 x i64>, <2 x i1> } @llvm.umul.with.overflow.v2i64(<2 x i64> [[IN]], <2 x i64> <i64 poison, i64 1424>) |
| ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { <2 x i64>, <2 x i1> } [[MWO]], 0 |
| ; CHECK-NEXT: [[OVF:%.*]] = extractvalue { <2 x i64>, <2 x i1> } [[MWO]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i64> [[MUL]], <i64 9223372036854775800, i64 poison> |
| ; CHECK-NEXT: [[RET:%.*]] = or <2 x i1> [[OVF]], [[CMP]] |
| ; CHECK-NEXT: ret <2 x i1> [[RET]] |
| ; |
| %mwo = tail call { <2 x i64>, <2 x i1> } @llvm.umul.with.overflow.v2i64(<2 x i64> %in, <2 x i64> <i64 poison, i64 1424>) |
| %mul = extractvalue { <2 x i64>, <2 x i1> } %mwo, 0 |
| %ovf = extractvalue { <2 x i64>, <2 x i1> } %mwo, 1 |
| %cmp = icmp ugt <2 x i64> %mul, <i64 9223372036854775800, i64 poison> |
| %ret = or <2 x i1> %ovf, %cmp |
| ret <2 x i1> %ret |
| } |
| |
| ; Negative test |
| define i1 @umul_greater_than_and_overflow_const_negative(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_and_overflow_const_negative( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP2:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[IN]], i64 48) |
| ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 |
| ; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i64 [[TMP3]], 9223372036854775800 |
| ; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP4]], [[TMP5]] |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ult i64 %mul, 9223372036854775800 |
| %ret = and i1 %ovf, %cmp |
| ret i1 %ret |
| } |
| |
| ; Negative test |
| define i1 @umul_less_than_or_overflow_const_negative(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_less_than_or_overflow_const_negative( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP2:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[IN]], i64 48) |
| ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 |
| ; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i64 [[TMP3]], 9223372036854775800 |
| ; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP4]], [[TMP5]] |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ult i64 %mul, 9223372036854775800 |
| %ret = or i1 %ovf, %cmp |
| ret i1 %ret |
| } |
| |
| ; Negative test |
| define i1 @umul_greater_than_or_overflow_const_multiuse_icmp_negative(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_multiuse_icmp_negative( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: [[TMP2:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[IN]], i64 48) |
| ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 |
| ; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[TMP3]], 9223372036854775800 |
| ; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP4]], [[TMP5]] |
| ; CHECK-NEXT: tail call void @use.i1(i1 [[TMP5]]) |
| ; CHECK-NEXT: ret i1 [[TMP6]] |
| ; |
| %mwo = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 48) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 9223372036854775800 |
| %ret = or i1 %ovf, %cmp |
| tail call void @use.i1(i1 %cmp) |
| ret i1 %ret |
| } |
| |
| ; Negative test. The umul.with.overflow should be folded away before. |
| define i1 @umul_greater_than_or_overflow_const_0_negative(i64 %in) { |
| ; CHECK-LABEL: define i1 @umul_greater_than_or_overflow_const_0_negative( |
| ; CHECK-SAME: i64 [[IN:%.*]]) { |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %mwo = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %in, i64 0) |
| %mul = extractvalue { i64, i1 } %mwo, 0 |
| %ovf = extractvalue { i64, i1 } %mwo, 1 |
| %cmp = icmp ugt i64 %mul, 0 |
| %ret = or i1 %ovf, %cmp |
| ret i1 %ret |
| } |