return new ICmpInst(ICmpInst::ICMP_NE, Builder.CreateAnd(X, ~C),
ConstantExpr::getNeg(cast<Constant>(Y)));
+ // The range test idiom can use either ult or ugt. Arbitrarily canonicalize
+ // to the ult form.
+ // X+C2 >u C -> X+(C2-C-1) <u ~C
+ if (Pred == ICmpInst::ICMP_UGT)
+ return new ICmpInst(ICmpInst::ICMP_ULT,
+ Builder.CreateAdd(X, ConstantInt::get(Ty, *C2 - C - 1)),
+ ConstantInt::get(Ty, ~C));
+
return nullptr;
}
// Said condition must be one-use.
if (!Cmp0.hasOneUse())
return nullptr;
+ ICmpInst::Predicate Pred0 = Cmp0.getPredicate();
Value *Cmp00 = Cmp0.getOperand(0);
Constant *C0;
if (!match(Cmp0.getOperand(1),
m_CombineAnd(m_AnyIntegralConstant(), m_Constant(C0))))
return nullptr;
- // Canonicalize Cmp0 into the form we expect.
+
+ if (!isa<SelectInst>(Sel1)) {
+ Pred0 = ICmpInst::getInversePredicate(Pred0);
+ std::swap(X, Sel1);
+ }
+
+ // Canonicalize Cmp0 into ult or uge.
// FIXME: we shouldn't care about lanes that are 'undef' in the end?
- switch (Cmp0.getPredicate()) {
+ switch (Pred0) {
case ICmpInst::Predicate::ICMP_ULT:
+ case ICmpInst::Predicate::ICMP_UGE:
// Although icmp ult %x, 0 is an unusual thing to try and should generally
// have been simplified, it does not verify with undef inputs so ensure we
// are not in a strange state.
return nullptr;
break; // Great!
case ICmpInst::Predicate::ICMP_ULE:
- // We'd have to increment C0 by one, and for that it must not have all-ones
- // element, but then it would have been canonicalized to 'ult' before
- // we get here. So we can't do anything useful with 'ule'.
- return nullptr;
case ICmpInst::Predicate::ICMP_UGT:
- // We want to canonicalize it to 'ult', so we'll need to increment C0,
- // which again means it must not have any all-ones elements.
+ // We want to canonicalize it to 'ult' or 'uge', so we'll need to increment
+ // C0, which again means it must not have any all-ones elements.
if (!match(C0,
m_SpecificInt_ICMP(
ICmpInst::Predicate::ICMP_NE,
APInt::getAllOnes(C0->getType()->getScalarSizeInBits()))))
return nullptr; // Can't do, have all-ones element[s].
C0 = InstCombiner::AddOne(C0);
- std::swap(X, Sel1);
break;
- case ICmpInst::Predicate::ICMP_UGE:
- // The only way we'd get this predicate if this `icmp` has extra uses,
- // but then we won't be able to do this fold.
- return nullptr;
default:
return nullptr; // Unknown predicate.
}
// The thresholds of this clamp-like pattern.
auto *ThresholdLowIncl = ConstantExpr::getNeg(C1);
auto *ThresholdHighExcl = ConstantExpr::getSub(C0, C1);
+ if (Pred0 == ICmpInst::Predicate::ICMP_UGE)
+ std::swap(ThresholdLowIncl, ThresholdHighExcl);
// The fold has a precondition 1: C2 s>= ThresholdLow
auto *Precond1 = ConstantExpr::getICmp(ICmpInst::Predicate::ICMP_SGE, C2,
; CHECK: if [[REG2]] s> [[REG1]] goto
; CHECK: if [[REG1]] s> 7 goto
-; CHECK-DISABLE: [[REG1:r[0-9]+]] += -1
+; CHECK-DISABLE: [[REG1:r[0-9]+]] += -8
; CHECK-DISABLE: [[REG1]] <<= 32
; CHECK-DISABLE: [[REG1]] >>= 32
-; CHECK-DISABLE: if [[REG1]] > 6 goto
+; CHECK-DISABLE: [[REG2:r[0-9]+]] = 4294967289
+; CHECK-DISABLE: if [[REG2]] > [[REG1]] goto
lor.lhs.false: ; preds = %entry
%2 = load i32, i32* %ret, align 4, !tbaa !2
; CHECK: if [[REG2]] s> [[REG1]] goto
; CHECK: if [[REG1]] s> 7 goto
-; CHECK-DISABLE: [[REG1:r[0-9]+]] += -1
+; CHECK-DISABLE: [[REG1:r[0-9]+]] += -8
; CHECK-DISABLE: [[REG1]] <<= 32
; CHECK-DISABLE: [[REG1]] >>= 32
-; CHECK-DISABLE: if [[REG1]] > 6 goto
+; CHECK-DISABLE: [[REG2:r[0-9]+]] = 4294967289
+; CHECK-DISABLE: if [[REG2]] > [[REG1]] goto
if.then: ; preds = %entry
store i32 0, i32* %retval, align 4
; CHECK: cond_true:
; CHECK-NEXT: [[TMP15:%.*]] = getelementptr [17 x i32], [17 x i32]* @r, i32 0, i32 [[TMP12_RELOAD:%.*]]
; CHECK-NEXT: [[TMP16]] = load i32, i32* [[TMP15]], align 4
-; CHECK-NEXT: [[TMP16_OFF:%.*]] = add i32 [[TMP16]], 31
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[TMP16_OFF]], 62
-; CHECK-NEXT: br i1 [[TMP0]], label [[BB27_EXITSTUB:%.*]], label [[COND_NEXT23_EXITSTUB:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[TMP16]], -32
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], -63
+; CHECK-NEXT: br i1 [[TMP1]], label [[BB27_EXITSTUB:%.*]], label [[COND_NEXT23_EXITSTUB:%.*]]
;
newFuncRoot:
br label %cond_true
; CHECK: cond_true:
; CHECK-NEXT: [[TMP15:%.*]] = getelementptr [17 x i32], [17 x i32]* @r, i32 0, i32 [[TMP12_RELOAD:%.*]]
; CHECK-NEXT: [[TMP16]] = load i32, i32* [[TMP15]], align 4
-; CHECK-NEXT: [[TMP16_OFF:%.*]] = add i32 [[TMP16]], 31
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[TMP16_OFF]], 62
-; CHECK-NEXT: br i1 [[TMP0]], label [[BB27_EXITSTUB:%.*]], label [[COND_NEXT23_EXITSTUB:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[TMP16]], -32
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], -63
+; CHECK-NEXT: br i1 [[TMP1]], label [[BB27_EXITSTUB:%.*]], label [[COND_NEXT23_EXITSTUB:%.*]]
;
newFuncRoot:
br label %cond_true
define i1 @test(i32 %tmp6) {
; CHECK-LABEL: @test(
-; CHECK-NEXT: [[TMP6_OFF:%.*]] = add i32 %tmp6, 83
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[TMP6_OFF]], 11
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP6:%.*]], 71
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -12
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%tmp7 = sdiv i32 %tmp6, 12
icmp ne i32 %tmp7, -6
define <2 x i1> @test_vec(<2 x i32> %tmp6) {
; CHECK-LABEL: @test_vec(
-; CHECK-NEXT: [[TMP6_OFF:%.*]] = add <2 x i32> %tmp6, <i32 83, i32 83>
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i32> [[TMP6_OFF]], <i32 11, i32 11>
-; CHECK-NEXT: ret <2 x i1> [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[TMP6:%.*]], <i32 71, i32 71>
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -12, i32 -12>
+; CHECK-NEXT: ret <2 x i1> [[TMP2]]
;
%tmp7 = sdiv <2 x i32> %tmp6, <i32 12, i32 12>
icmp ne <2 x i32> %tmp7, <i32 -6, i32 -6>
; CHECK-NEXT: br label [[BB:%.*]]
; CHECK: bb:
; CHECK-NEXT: [[L1:%.*]] = load i8, i8* [[X:%.*]], align 1
-; CHECK-NEXT: [[S1:%.*]] = add i8 [[L1]], -6
-; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[S1]], 2
-; CHECK-NEXT: [[S2:%.*]] = add i8 [[L1]], -10
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[S2]], 2
+; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[L1]], -9
+; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[TMP0]], -3
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[L1]], -13
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[TMP1]], -3
; CHECK-NEXT: [[A1:%.*]] = and i1 [[C1]], [[C2]]
; CHECK-NEXT: br i1 [[A1]], label [[INCOMPATIBLE:%.*]], label [[OKAY:%.*]]
; CHECK: okay:
; CHECK-NEXT: br label [[BB:%.*]]
; CHECK: bb:
; CHECK-NEXT: [[L1:%.*]] = load i8, i8* [[X:%.*]], align 1
-; CHECK-NEXT: [[S1:%.*]] = add i8 [[L1]], -6
-; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[S1]], 2
-; CHECK-NEXT: [[S2:%.*]] = add i8 [[L1]], -10
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[S2]], 2
+; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[L1]], -9
+; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[TMP0]], -3
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[L1]], -13
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[TMP1]], -3
; CHECK-NEXT: [[A1:%.*]] = and i1 [[C1]], [[C2]]
; CHECK-NEXT: br i1 [[A1]], label [[INCOMPATIBLE:%.*]], label [[OKAY:%.*]]
; CHECK: okay:
define i1 @and_ne_with_diff_one(i32 %x) {
; CHECK-LABEL: @and_ne_with_diff_one(
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -39
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -41
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i32 %x, 40
define i1 @and_ne_with_diff_one_logical(i32 %x) {
; CHECK-LABEL: @and_ne_with_diff_one_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -39
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -41
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i32 %x, 40
define i1 @and_ne_with_diff_one_signed(i64 %x) {
; CHECK-LABEL: @and_ne_with_diff_one_signed(
-; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP1]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i64 %x, -1
define i1 @and_ne_with_diff_one_signed_logical(i64 %x) {
; CHECK-LABEL: @and_ne_with_diff_one_signed_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP1]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i64 %x, -1
define <2 x i1> @and_ne_with_diff_one_splatvec(<2 x i32> %x) {
; CHECK-LABEL: @and_ne_with_diff_one_splatvec(
-; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -39, i32 -39>
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt <2 x i32> [[TMP1]], <i32 1, i32 1>
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -41, i32 -41>
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -2, i32 -2>
; CHECK-NEXT: ret <2 x i1> [[TMP2]]
;
%cmp1 = icmp ne <2 x i32> %x, <i32 40, i32 40>
define i1 @PR42691_5(i32 %x) {
; CHECK-LABEL: @PR42691_5(
-; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X_OFF]], 2147483645
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -2147483647
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2147483646
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%c1 = icmp slt i32 %x, 1
%c2 = icmp eq i32 %x, 2147483647
define i1 @PR42691_5_logical(i32 %x) {
; CHECK-LABEL: @PR42691_5_logical(
-; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X_OFF]], 2147483645
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -2147483647
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2147483646
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%c1 = icmp slt i32 %x, 1
%c2 = icmp eq i32 %x, 2147483647
define i1 @PR42691_6(i32 %x) {
; CHECK-LABEL: @PR42691_6(
-; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], 2147483647
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X_OFF]], 2147483645
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2147483646
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%c1 = icmp ult i32 %x, 2147483649
%c2 = icmp eq i32 %x, 4294967295
define i1 @PR42691_6_logical(i32 %x) {
; CHECK-LABEL: @PR42691_6_logical(
-; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], 2147483647
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X_OFF]], 2147483645
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -2147483646
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%c1 = icmp ult i32 %x, 2147483649
%c2 = icmp eq i32 %x, 4294967295
define i1 @p0(i8 %x) {
; CHECK-LABEL: @p0(
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], 4
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -4
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], -8
; CHECK-NEXT: ret i1 [[TMP2]]
;
%tmp0 = shl i8 %x, 5
define <2 x i1> @p1_vec_splat(<2 x i8> %x) {
; CHECK-LABEL: @p1_vec_splat(
-; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 4, i8 4>
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt <2 x i8> [[TMP1]], <i8 7, i8 7>
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 -4, i8 -4>
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult <2 x i8> [[TMP1]], <i8 -8, i8 -8>
; CHECK-NEXT: ret <2 x i1> [[TMP2]]
;
%tmp0 = shl <2 x i8> %x, <i8 5, i8 5>
define i1 @c0() {
; CHECK-LABEL: @c0(
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], 4
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -4
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], -8
; CHECK-NEXT: ret i1 [[TMP2]]
;
%x = call i8 @gen8()
; CHECK-LABEL: @n_oneuse0(
; CHECK-NEXT: [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
; CHECK-NEXT: call void @use8(i8 [[TMP0]])
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], 4
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -4
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], -8
; CHECK-NEXT: ret i1 [[TMP2]]
;
%tmp0 = shl i8 %x, 5
define i1 @uge_add_nonuw(i32 %in) {
; CHECK-LABEL: @uge_add_nonuw(
-; CHECK-NEXT: [[A6:%.*]] = add i32 [[IN:%.*]], 3
-; CHECK-NEXT: [[A18:%.*]] = icmp ugt i32 [[A6]], 11
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[IN:%.*]], -9
+; CHECK-NEXT: [[A18:%.*]] = icmp ult i32 [[TMP1]], -12
; CHECK-NEXT: ret i1 [[A18]]
;
%a6 = add i32 %in, 3
define i1 @ugt_wrong_offset(i8 %a) {
; CHECK-LABEL: @ugt_wrong_offset(
-; CHECK-NEXT: [[T:%.*]] = add i8 [[A:%.*]], 123
-; CHECK-NEXT: [[OV:%.*]] = icmp ugt i8 [[T]], -5
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], 127
+; CHECK-NEXT: [[OV:%.*]] = icmp ult i8 [[TMP1]], 4
; CHECK-NEXT: ret i1 [[OV]]
;
%t = add i8 %a, 123
define i1 @test_negative_nsw_and_unsigned_pred(i64 %x) {
; CHECK-LABEL: @test_negative_nsw_and_unsigned_pred(
-; CHECK-NEXT: [[NOTSUB:%.*]] = add nsw i64 [[X:%.*]], -11
-; CHECK-NEXT: [[Z:%.*]] = icmp ugt i64 [[NOTSUB]], -4
+; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], -8
+; CHECK-NEXT: [[Z:%.*]] = icmp ult i64 [[TMP1]], 3
; CHECK-NEXT: ret i1 [[Z]]
;
%y = sub nsw i64 10, %x
define i1 @testi16i8_ne(i16 %add) {
; CHECK-LABEL: @testi16i8_ne(
-; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD:%.*]], 128
-; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ugt i16 [[TMP1]], 255
+; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD:%.*]], -128
+; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i16 [[TMP1]], -256
; CHECK-NEXT: ret i1 [[CMP_NOT_I]]
;
%sh = lshr i16 %add, 8
define i1 @testi16i8_ne_com(i16 %add) {
; CHECK-LABEL: @testi16i8_ne_com(
-; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD:%.*]], 128
-; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ugt i16 [[TMP1]], 255
+; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD:%.*]], -128
+; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i16 [[TMP1]], -256
; CHECK-NEXT: ret i1 [[CMP_NOT_I]]
;
%sh = lshr i16 %add, 8
define i1 @testi64i32_ne(i64 %add) {
; CHECK-LABEL: @testi64i32_ne(
-; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD:%.*]], 2147483648
-; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ugt i64 [[TMP1]], 4294967295
+; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD:%.*]], -2147483648
+; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], -4294967296
; CHECK-NEXT: ret i1 [[CMP_NOT_I]]
;
%sh = lshr i64 %add, 32
define i1 @test7(i32 %X) {
; CHECK-LABEL: @test7(
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -1
-; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[TMP1]], 2
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -4
+; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[TMP1]], -3
; CHECK-NEXT: ret i1 [[R]]
;
%P = getelementptr inbounds [6 x double], [6 x double]* @GD, i32 0, i32 %X
; Negative test
+; Without the nuw that would allow pushing the add through the umax, the
+; add + icmp ugt combination can be interpreted as a range check, and would
+; normally be canonicalized to use ult instead. However, this is not done when
+; used as part of a umax to avoid breaking the SPF pattern.
define i32 @add_umax_wrong_wrap(i32 %x) {
; CHECK-LABEL: @add_umax_wrong_wrap(
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 15
define i1 @test18(i32 %A) {
; CHECK-LABEL: @test18(
-; CHECK-NEXT: [[A_OFF:%.*]] = add i32 [[A:%.*]], -50
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A_OFF]], 49
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -100
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -50
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%B = icmp sge i32 %A, 100
%C = icmp slt i32 %A, 50
define i1 @test18_logical(i32 %A) {
; CHECK-LABEL: @test18_logical(
-; CHECK-NEXT: [[A_OFF:%.*]] = add i32 [[A:%.*]], -50
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A_OFF]], 49
-; CHECK-NEXT: ret i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -100
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -50
+; CHECK-NEXT: ret i1 [[TMP2]]
;
%B = icmp sge i32 %A, 100
%C = icmp slt i32 %A, 50
; CHECK-NEXT: [[TMP0:%.*]] = extractvalue { i32, i1 } [[SADD]], 1
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #2
+; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2:[0-9]+]]
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[SADD_RESULT:%.*]] = extractvalue { i32, i1 } [[SADD]], 0
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i64 [[ADD_OFF]], 4294967295
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #2
+; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2]]
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[CONV9:%.*]] = trunc i64 [[ADD]] to i32
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[A:%.*]] to i64
; CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[B:%.*]] to i64
; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[CONV2]], [[CONV]]
-; CHECK-NEXT: [[ADD_OFF:%.*]] = add nsw i64 [[ADD]], 2147483648
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i64 [[ADD_OFF]], 4294967295
-; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[ADD]], -2147483648
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], -4294967296
+; CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #2
+; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2]]
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret i64 [[ADD]]
; CHECK-NEXT: [[CMP:%.*]] = extractvalue { i8, i1 } [[SADD]], 1
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #2
+; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2]]
; CHECK-NEXT: unreachable
; CHECK: if.end:
; CHECK-NEXT: [[SADD_RESULT:%.*]] = extractvalue { i8, i1 } [[SADD]], 0
; CHECK-LABEL: @test8(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[ADD_OFF:%.*]] = add i64 [[ADD]], 2147483648
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i64 [[ADD_OFF]], 4294967295
-; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[ADD]], -2147483648
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], -4294967296
+; CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #2
+; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2]]
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[CONV9:%.*]] = trunc i64 [[ADD]] to i32
define i1 @test_constant3(i8 %a) {
; CHECK-LABEL: @test_constant3(
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], 42
-; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ugt i8 [[TMP1]], 84
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], -43
+; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ult i8 [[TMP1]], -85
; CHECK-NEXT: ret i1 [[OVERFLOW]]
;
%res = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 3)
define i1 @test_constant4(i8 %a) {
; CHECK-LABEL: @test_constant4(
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], 32
-; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ugt i8 [[TMP1]], 63
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], -32
+; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ult i8 [[TMP1]], -64
; CHECK-NEXT: ret i1 [[OVERFLOW]]
;
%res = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 4)
define i1 @test_constant127(i8 %a) {
; CHECK-LABEL: @test_constant127(
-; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], 1
-; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ugt i8 [[TMP1]], 2
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[A:%.*]], -2
+; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ult i8 [[TMP1]], -3
; CHECK-NEXT: ret i1 [[OVERFLOW]]
;
%res = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 127)