mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[InstSimplify] fold sdiv/srem based on compare of dividend and divisor
This should bring signed div/rem analysis up to the same level as unsigned. We use icmp simplification to determine when the divisor is known greater than the dividend. Each positive test is followed by a negative test to show that we're not overstepping the boundaries of the known bits. There are extra tests for the signed-min-value special cases. Alive proofs: http://rise4fun.com/Alive/WI5 Differential Revision: https://reviews.llvm.org/D37713 llvm-svn: 313264
This commit is contained in:
parent
1ca614cedd
commit
3e2b1fd515
@ -917,20 +917,54 @@ static bool isICmpTrue(ICmpInst::Predicate Pred, Value *LHS, Value *RHS,
|
||||
|
||||
/// 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.
|
||||
|
@ -532,24 +532,21 @@ define i32 @shrink_no(i8 %x) {
|
||||
ret i32 %div
|
||||
}
|
||||
|
||||
; When the divisor is known larger than the quotient,
|
||||
; InstSimplify should kill it before InstCombine sees it.
|
||||
|
||||
define i32 @shrink_no2(i8 %x) {
|
||||
; CHECK-LABEL: @shrink_no2(
|
||||
; 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
|
||||
ret i32 %div
|
||||
}
|
||||
|
||||
; 17 bits are needed to represent 65535 as a signed value, so this shouldn't fold.
|
||||
|
||||
define i32 @shrink_no3(i16 %x) {
|
||||
; CHECK-LABEL: @shrink_no3(
|
||||
; CHECK-NEXT: [[CONV:%.*]] = sext i16 %x to i32
|
||||
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 65535
|
||||
; CHECK-NEXT: ret i32 [[DIV]]
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%conv = sext i16 %x to i32
|
||||
%div = sdiv i32 %conv, 65535
|
||||
|
@ -60,9 +60,7 @@ define i32 @div1(i32 %V) {
|
||||
|
||||
define i32 @div2(i32 %V) {
|
||||
; CHECK-LABEL: @div2(
|
||||
; CHECK-NEXT: [[A:%.*]] = sdiv i32 %V, -1
|
||||
; CHECK-NEXT: [[B:%.*]] = sdiv i32 [[A]], -2147483648
|
||||
; CHECK-NEXT: ret i32 [[B]]
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%A = sdiv i32 %V, -1
|
||||
%B = sdiv i32 %A, -2147483648
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
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
|
||||
@ -24,9 +22,7 @@ define i32 @not_sdiv_sext_big_divisor(i8 %x) {
|
||||
|
||||
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
|
||||
@ -46,9 +42,7 @@ define i32 @not_sdiv_sext_small_divisor(i8 %x) {
|
||||
|
||||
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
|
||||
@ -68,9 +62,7 @@ define i32 @not_sdiv_zext_big_divisor(i8 %x) {
|
||||
|
||||
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
|
||||
@ -90,9 +82,7 @@ define i32 @not_sdiv_zext_small_divisor(i8 %x) {
|
||||
|
||||
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
|
||||
@ -112,9 +102,7 @@ define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x)
|
||||
|
||||
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
|
||||
@ -134,9 +122,7 @@ define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x)
|
||||
|
||||
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
|
||||
@ -156,9 +142,7 @@ define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
|
||||
|
||||
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
|
||||
@ -179,8 +163,7 @@ define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
|
||||
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
|
||||
@ -201,8 +184,7 @@ define i32 @not_srem_sext_big_divisor(i8 %x) {
|
||||
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
|
||||
@ -223,8 +205,7 @@ define i32 @not_srem_sext_small_divisor(i8 %x) {
|
||||
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
|
||||
@ -245,8 +226,7 @@ define i32 @not_srem_zext_big_divisor(i8 %x) {
|
||||
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
|
||||
@ -267,8 +247,7 @@ define i32 @not_srem_zext_small_divisor(i8 %x) {
|
||||
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
|
||||
@ -289,8 +268,7 @@ define i32 @not_srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x)
|
||||
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
|
||||
@ -311,8 +289,7 @@ define i32 @not_srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x)
|
||||
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
|
||||
@ -333,8 +310,7 @@ define i32 @not_srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
|
||||
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
|
||||
@ -352,3 +328,27 @@ define i32 @not_srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user