Constant::getNullValue(Mul->getType()));
}
+ // If the multiply does not wrap, try to divide the compare constant by the
+ // multiplication factor.
+ if (Cmp.isEquality() && !MulC->isNullValue()) {
+ // (mul nsw X, MulC) == C --> X == C /s MulC
+ if (Mul->hasNoSignedWrap() && C.srem(*MulC).isNullValue()) {
+ Constant *NewC = ConstantInt::get(Mul->getType(), C.sdiv(*MulC));
+ return new ICmpInst(Pred, Mul->getOperand(0), NewC);
+ }
+ // (mul nuw X, MulC) == C --> X == C /u MulC
+ if (Mul->hasNoUnsignedWrap() && C.urem(*MulC).isNullValue()) {
+ Constant *NewC = ConstantInt::get(Mul->getType(), C.udiv(*MulC));
+ return new ICmpInst(Pred, Mul->getOperand(0), NewC);
+ }
+ }
+
return nullptr;
}
}
break;
}
- case Instruction::Mul:
- if (C.isNullValue() && BO->hasNoSignedWrap()) {
- const APInt *BOC;
- if (match(BOp1, m_APInt(BOC)) && !BOC->isNullValue()) {
- // The trivial case (mul X, 0) is handled by InstSimplify.
- // General case : (mul X, C) != 0 iff X != 0
- // (mul X, C) == 0 iff X == 0
- return new ICmpInst(Pred, BOp0, Constant::getNullValue(RHS->getType()));
- }
- }
- break;
case Instruction::UDiv:
if (C.isNullValue()) {
// (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A)
define i1 @eq_nsw_rem_zero(i8 %x) {
; CHECK-LABEL: @eq_nsw_rem_zero(
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X:%.*]], -5
-; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[X:%.*]], -4
; CHECK-NEXT: ret i1 [[B]]
;
%a = mul nsw i8 %x, -5
define <2 x i1> @ne_nsw_rem_zero(<2 x i8> %x) {
; CHECK-LABEL: @ne_nsw_rem_zero(
-; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 5>
-; CHECK-NEXT: [[B:%.*]] = icmp ne <2 x i8> [[A]], <i8 -30, i8 -30>
+; CHECK-NEXT: [[B:%.*]] = icmp ne <2 x i8> [[X:%.*]], <i8 -6, i8 -6>
; CHECK-NEXT: ret <2 x i1> [[B]]
;
%a = mul nsw <2 x i8> %x, <i8 5, i8 5>
ret <2 x i1> %b
}
+; TODO: Missed fold with undef.
+
define <2 x i1> @ne_nsw_rem_zero_undef1(<2 x i8> %x) {
; CHECK-LABEL: @ne_nsw_rem_zero_undef1(
; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 undef>
ret <2 x i1> %b
}
+; TODO: Missed fold with undef.
+
define <2 x i1> @ne_nsw_rem_zero_undef2(<2 x i8> %x) {
; CHECK-LABEL: @ne_nsw_rem_zero_undef2(
; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 5>
; CHECK-LABEL: @eq_nsw_rem_zero_uses(
; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X:%.*]], -5
; CHECK-NEXT: call void @use(i8 [[A]])
-; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[X]], -4
; CHECK-NEXT: ret i1 [[B]]
;
%a = mul nsw i8 %x, -5
define <2 x i1> @eq_nuw_rem_zero(<2 x i8> %x) {
; CHECK-LABEL: @eq_nuw_rem_zero(
-; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 5, i8 5>
-; CHECK-NEXT: [[B:%.*]] = icmp eq <2 x i8> [[A]], <i8 20, i8 20>
+; CHECK-NEXT: [[B:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 4, i8 4>
; CHECK-NEXT: ret <2 x i1> [[B]]
;
%a = mul nuw <2 x i8> %x, <i8 5, i8 5>
ret <2 x i1> %b
}
+; TODO: Missed fold with undef.
+
define <2 x i1> @eq_nuw_rem_zero_undef1(<2 x i8> %x) {
; CHECK-LABEL: @eq_nuw_rem_zero_undef1(
; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 undef, i8 5>
ret <2 x i1> %b
}
+; TODO: Missed fold with undef.
+
define <2 x i1> @eq_nuw_rem_zero_undef2(<2 x i8> %x) {
; CHECK-LABEL: @eq_nuw_rem_zero_undef2(
; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 5, i8 5>
define i1 @ne_nuw_rem_zero(i8 %x) {
; CHECK-LABEL: @ne_nuw_rem_zero(
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
-; CHECK-NEXT: [[B:%.*]] = icmp ne i8 [[A]], -126
+; CHECK-NEXT: [[B:%.*]] = icmp ne i8 [[X:%.*]], 26
; CHECK-NEXT: ret i1 [[B]]
;
%a = mul nuw i8 %x, 5
; CHECK-LABEL: @ne_nuw_rem_zero_uses(
; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
; CHECK-NEXT: call void @use(i8 [[A]])
-; CHECK-NEXT: [[B:%.*]] = icmp ne i8 [[A]], -126
+; CHECK-NEXT: [[B:%.*]] = icmp ne i8 [[X]], 26
; CHECK-NEXT: ret i1 [[B]]
;
%a = mul nuw i8 %x, 5