/// Return true if we can simplify X / Y to 0. Remainder can adapt that answer
/// to simplify X % Y to X.
-static bool isDivZero(Value *Op0, Value *Op1, const SimplifyQuery &Q,
+static bool isDivZero(Value *X, Value *Y, const SimplifyQuery &Q,
unsigned MaxRecurse, bool IsSigned) {
// Recursion is always used, so bail out at once if we already hit the limit.
if (!MaxRecurse--)
return false;
if (IsSigned) {
- // TODO: Handle signed.
+ // |X| / |Y| --> 0
+ //
+ // We require that 1 operand is a simple constant. That could be extended to
+ // 2 variables if we computed the sign bit for each.
+ //
+ // Make sure that a constant is not the minimum signed value because taking
+ // the abs() of that is undefined.
+ Type *Ty = X->getType();
+ const APInt *C;
+ if (match(X, m_APInt(C)) && !C->isMinSignedValue()) {
+ // Is the variable divisor magnitude always greater than the constant
+ // dividend magnitude?
+ // |Y| > |C| --> Y < -abs(C) or Y > abs(C)
+ Constant *PosDividendC = ConstantInt::get(Ty, C->abs());
+ Constant *NegDividendC = ConstantInt::get(Ty, -C->abs());
+ if (isICmpTrue(CmpInst::ICMP_SLT, Y, NegDividendC, Q, MaxRecurse) ||
+ isICmpTrue(CmpInst::ICMP_SGT, Y, PosDividendC, Q, MaxRecurse))
+ return true;
+ }
+ if (match(Y, m_APInt(C))) {
+ // Special-case: we can't take the abs() of a minimum signed value. If
+ // that's the divisor, then all we have to do is prove that the dividend
+ // is also not the minimum signed value.
+ if (C->isMinSignedValue())
+ return isICmpTrue(CmpInst::ICMP_NE, X, Y, Q, MaxRecurse);
+
+ // Is the variable dividend magnitude always less than the constant
+ // divisor magnitude?
+ // |X| < |C| --> X > -abs(C) and X < abs(C)
+ Constant *PosDivisorC = ConstantInt::get(Ty, C->abs());
+ Constant *NegDivisorC = ConstantInt::get(Ty, -C->abs());
+ if (isICmpTrue(CmpInst::ICMP_SGT, X, NegDivisorC, Q, MaxRecurse) &&
+ isICmpTrue(CmpInst::ICMP_SLT, X, PosDivisorC, Q, MaxRecurse))
+ return true;
+ }
return false;
}
// IsSigned == false.
- // Is the quotient unsigned less than the divisor?
- return isICmpTrue(ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse);
+ // Is the dividend unsigned less than the divisor?
+ return isICmpTrue(ICmpInst::ICMP_ULT, X, Y, Q, MaxRecurse);
}
/// These are simplifications common to SDiv and UDiv.
define i32 @sdiv_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_sext_big_divisor(
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 129
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, 129
define i32 @sdiv_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_sext_small_divisor(
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -129
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, -129
define i32 @sdiv_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_zext_big_divisor(
-; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 256
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, 256
define i32 @sdiv_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_zext_small_divisor(
-; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -256
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, -256
define i32 @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(
-; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], 254
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%and = and i32 %x, 253
%div = sdiv i32 %and, 254
define i32 @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(
-; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], -254
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%and = and i32 %x, 253
%div = sdiv i32 %and, -254
define i32 @sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_set_bits(
-; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], 254
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%or = or i32 %x, -253
%div = sdiv i32 %or, 254
define i32 @sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_set_bits(
-; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], -254
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: ret i32 0
;
%or = or i32 %x, -253
%div = sdiv i32 %or, -254
define i32 @srem_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @srem_sext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 129
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, 129
define i32 @srem_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @srem_sext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -129
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, -129
define i32 @srem_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @srem_zext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 256
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, 256
define i32 @srem_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @srem_zext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -256
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, -256
define i32 @srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], 254
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, 254
define i32 @srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], -254
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, -254
define i32 @srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], 254
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, 254
define i32 @srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
-; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], -254
-; CHECK-NEXT: ret i32 [[REM]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, -254
ret i32 %rem
}
+; Make sure that we're handling the minimum signed constant correctly - can't fold this.
+
+define i16 @sdiv_min_dividend(i8 %x) {
+; CHECK-LABEL: @sdiv_min_dividend(
+; CHECK-NEXT: [[Z:%.*]] = zext i8 %x to i16
+; CHECK-NEXT: [[D:%.*]] = sdiv i16 -32768, [[Z]]
+; CHECK-NEXT: ret i16 [[D]]
+;
+ %z = zext i8 %x to i16
+ %d = sdiv i16 -32768, %z
+ ret i16 %d
+}
+
+; If the quotient is known to not be -32768, then this can fold.
+
+define i16 @sdiv_min_divisor(i8 %x) {
+; CHECK-LABEL: @sdiv_min_divisor(
+; CHECK-NEXT: ret i16 0
+;
+ %z = zext i8 %x to i16
+ %d = sdiv i16 %z, -32768
+ ret i16 %d
+}
+