Don't try to simplify urem and srem using arithmetic rules that don't work

under modulo (overflow). Fixes PR1933.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47987 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nick Lewycky 2008-03-06 06:48:30 +00:00
parent 4cb8bd8eff
commit c1a2a61201
2 changed files with 129 additions and 69 deletions

View File

@ -834,6 +834,49 @@ static void ComputeMaskedBits(Value *V, const APInt &Mask, APInt& KnownZero,
return;
}
break;
case Instruction::SRem:
if (ConstantInt *Rem = dyn_cast<ConstantInt>(I->getOperand(1))) {
APInt RA = Rem->getValue();
if (RA.isPowerOf2() || (-RA).isPowerOf2()) {
APInt LowBits = RA.isStrictlyPositive() ? ((RA - 1) | RA) : ~RA;
APInt Mask2 = LowBits | APInt::getSignBit(BitWidth);
ComputeMaskedBits(I->getOperand(0), Mask2,KnownZero2,KnownOne2,Depth+1);
// The sign of a remainder is equal to the sign of the first
// operand (zero being positive).
if (KnownZero2[BitWidth-1] || ((KnownZero2 & LowBits) == LowBits))
KnownZero2 |= ~LowBits;
else if (KnownOne2[BitWidth-1])
KnownOne2 |= ~LowBits;
KnownZero |= KnownZero2 & Mask;
KnownOne |= KnownOne2 & Mask;
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
}
}
break;
case Instruction::URem:
if (ConstantInt *Rem = dyn_cast<ConstantInt>(I->getOperand(1))) {
APInt RA = Rem->getValue();
if (RA.isStrictlyPositive() && RA.isPowerOf2()) {
APInt LowBits = (RA - 1) | RA;
APInt Mask2 = LowBits & Mask;
KnownZero |= ~LowBits & Mask;
ComputeMaskedBits(I->getOperand(0), Mask2, KnownZero, KnownOne,Depth+1);
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
}
} else {
// Since the result is less than or equal to RHS, any leading zero bits
// in RHS must also exist in the result.
APInt AllOnes = APInt::getAllOnesValue(BitWidth);
ComputeMaskedBits(I->getOperand(1), AllOnes, KnownZero2, KnownOne2, Depth+1);
uint32_t Leaders = KnownZero2.countLeadingOnes();
KnownZero |= APInt::getHighBitsSet(BitWidth, Leaders) & Mask;
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
}
break;
}
}
@ -1418,6 +1461,52 @@ bool InstCombiner::SimplifyDemandedBits(Value *V, APInt DemandedMask,
}
}
break;
case Instruction::SRem:
if (ConstantInt *Rem = dyn_cast<ConstantInt>(I->getOperand(1))) {
APInt RA = Rem->getValue();
if (RA.isPowerOf2() || (-RA).isPowerOf2()) {
APInt LowBits = RA.isStrictlyPositive() ? (RA - 1) | RA : ~RA;
APInt Mask2 = LowBits | APInt::getSignBit(BitWidth);
if (SimplifyDemandedBits(I->getOperand(0), Mask2,
LHSKnownZero, LHSKnownOne, Depth+1))
return true;
if (LHSKnownZero[BitWidth-1] || ((LHSKnownZero & LowBits) == LowBits))
LHSKnownZero |= ~LowBits;
else if (LHSKnownOne[BitWidth-1])
LHSKnownOne |= ~LowBits;
KnownZero |= LHSKnownZero & DemandedMask;
KnownOne |= LHSKnownOne & DemandedMask;
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
}
}
break;
case Instruction::URem:
if (ConstantInt *Rem = dyn_cast<ConstantInt>(I->getOperand(1))) {
APInt RA = Rem->getValue();
if (RA.isPowerOf2()) {
APInt LowBits = (RA - 1) | RA;
APInt Mask2 = LowBits & DemandedMask;
KnownZero |= ~LowBits & DemandedMask;
if (SimplifyDemandedBits(I->getOperand(0), Mask2,
KnownZero, KnownOne, Depth+1))
return true;
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
}
} else {
APInt KnownZero2(BitWidth, 0), KnownOne2(BitWidth, 0);
APInt AllOnes = APInt::getAllOnesValue(BitWidth);
if (SimplifyDemandedBits(I->getOperand(1), AllOnes,
KnownZero2, KnownOne2, Depth+1))
return true;
uint32_t Leaders = KnownZero2.countLeadingOnes();
KnownZero |= APInt::getHighBitsSet(BitWidth, Leaders) & DemandedMask;
}
break;
}
// If the client is only demanding bits that we know, return the known
@ -2780,46 +2869,6 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
return commonDivTransforms(I);
}
/// GetFactor - If we can prove that the specified value is at least a multiple
/// of some factor, return that factor.
static Constant *GetFactor(Value *V) {
if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
return CI;
// Unless we can be tricky, we know this is a multiple of 1.
Constant *Result = ConstantInt::get(V->getType(), 1);
Instruction *I = dyn_cast<Instruction>(V);
if (!I) return Result;
if (I->getOpcode() == Instruction::Mul) {
// Handle multiplies by a constant, etc.
return ConstantExpr::getMul(GetFactor(I->getOperand(0)),
GetFactor(I->getOperand(1)));
} else if (I->getOpcode() == Instruction::Shl) {
// (X<<C) -> X * (1 << C)
if (Constant *ShRHS = dyn_cast<Constant>(I->getOperand(1))) {
ShRHS = ConstantExpr::getShl(Result, ShRHS);
return ConstantExpr::getMul(GetFactor(I->getOperand(0)), ShRHS);
}
} else if (I->getOpcode() == Instruction::And) {
if (ConstantInt *RHS = dyn_cast<ConstantInt>(I->getOperand(1))) {
// X & 0xFFF0 is known to be a multiple of 16.
uint32_t Zeros = RHS->getValue().countTrailingZeros();
if (Zeros != V->getType()->getPrimitiveSizeInBits())// don't shift by "32"
return ConstantExpr::getShl(Result,
ConstantInt::get(Result->getType(), Zeros));
}
} else if (CastInst *CI = dyn_cast<CastInst>(I)) {
// Only handle int->int casts.
if (!CI->isIntegerCast())
return Result;
Value *Op = CI->getOperand(0);
return ConstantExpr::getCast(CI->getOpcode(), GetFactor(Op), V->getType());
}
return Result;
}
/// This function implements the transforms on rem instructions that work
/// regardless of the kind of rem instruction it is (urem, srem, or frem). It
/// is used by the visitors to those instructions.
@ -2901,9 +2950,13 @@ Instruction *InstCombiner::commonIRemTransforms(BinaryOperator &I) {
if (Instruction *NV = FoldOpIntoPhi(I))
return NV;
}
// (X * C1) % C2 --> 0 iff C1 % C2 == 0
if (ConstantExpr::getSRem(GetFactor(Op0I), RHS)->isNullValue())
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
// See if we can fold away this rem instruction.
uint32_t BitWidth = cast<IntegerType>(I.getType())->getBitWidth();
APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0);
if (SimplifyDemandedBits(&I, APInt::getAllOnesValue(BitWidth),
KnownZero, KnownOne))
return &I;
}
}

View File

@ -1,76 +1,83 @@
; This test makes sure that these instructions are properly eliminated.
;
; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep rem
; END.
define i32 @test1(i32 %A) {
%B = srem i32 %A, 1 ; <i32> [#uses=1]
%B = srem i32 %A, 1 ; ISA constant 0
ret i32 %B
}
define i32 @test2(i32 %A) {
%B = srem i32 0, %A ; <i32> [#uses=1]
define i32 @test2(i32 %A) { ; 0 % X = 0, we don't need to preserve traps
%B = srem i32 0, %A
ret i32 %B
}
define i32 @test3(i32 %A) {
%B = urem i32 %A, 8 ; <i32> [#uses=1]
%B = urem i32 %A, 8
ret i32 %B
}
define i1 @test3a(i32 %A) {
%B = srem i32 %A, -8 ; <i32> [#uses=1]
%C = icmp ne i32 %B, 0 ; <i1> [#uses=1]
%B = srem i32 %A, -8
%C = icmp ne i32 %B, 0
ret i1 %C
}
define i32 @test4(i32 %X, i1 %C) {
%V = select i1 %C, i32 1, i32 8 ; <i32> [#uses=1]
%R = urem i32 %X, %V ; <i32> [#uses=1]
%V = select i1 %C, i32 1, i32 8
%R = urem i32 %X, %V
ret i32 %R
}
define i32 @test5(i32 %X, i8 %B) {
%shift.upgrd.1 = zext i8 %B to i32 ; <i32> [#uses=1]
%Amt = shl i32 32, %shift.upgrd.1 ; <i32> [#uses=1]
%V = urem i32 %X, %Amt ; <i32> [#uses=1]
%shift.upgrd.1 = zext i8 %B to i32
%Amt = shl i32 32, %shift.upgrd.1
%V = urem i32 %X, %Amt
ret i32 %V
}
define i32 @test6(i32 %A) {
%B = srem i32 %A, 0 ; <i32> [#uses=1]
%B = srem i32 %A, 0 ;; undef
ret i32 %B
}
define i32 @test7(i32 %A) {
%B = mul i32 %A, 26 ; <i32> [#uses=1]
%C = srem i32 %B, 13 ; <i32> [#uses=1]
%B = mul i32 %A, 8
%C = srem i32 %B, 4
ret i32 %C
}
define i32 @test8(i32 %A) {
%B = shl i32 %A, 4 ; <i32> [#uses=1]
%C = srem i32 %B, 8 ; <i32> [#uses=1]
%B = shl i32 %A, 4
%C = srem i32 %B, 8
ret i32 %C
}
define i32 @test9(i32 %A) {
%B = mul i32 %A, 124 ; <i32> [#uses=1]
%C = urem i32 %B, 62 ; <i32> [#uses=1]
%B = mul i32 %A, 64
%C = urem i32 %B, 32
ret i32 %C
}
define i32 @test10(i8 %c) {
%tmp.1 = zext i8 %c to i32 ; <i32> [#uses=1]
%tmp.2 = mul i32 %tmp.1, 3 ; <i32> [#uses=1]
%tmp.3 = sext i32 %tmp.2 to i64 ; <i64> [#uses=1]
%tmp.5 = urem i64 %tmp.3, 3 ; <i64> [#uses=1]
%tmp.6 = trunc i64 %tmp.5 to i32 ; <i32> [#uses=1]
%tmp.1 = zext i8 %c to i32
%tmp.2 = mul i32 %tmp.1, 4
%tmp.3 = sext i32 %tmp.2 to i64
%tmp.5 = urem i64 %tmp.3, 4
%tmp.6 = trunc i64 %tmp.5 to i32
ret i32 %tmp.6
}
define i32 @test11(i32 %i) {
%tmp.1 = and i32 %i, -2 ; <i32> [#uses=1]
%tmp.3 = mul i32 %tmp.1, 3 ; <i32> [#uses=1]
%tmp.5 = srem i32 %tmp.3, 6 ; <i32> [#uses=1]
%tmp.1 = and i32 %i, -2
%tmp.3 = mul i32 %tmp.1, 2
%tmp.5 = urem i32 %tmp.3, 4
ret i32 %tmp.5
}
define i32 @test12(i32 %i) {
%tmp.1 = and i32 %i, -4
%tmp.5 = srem i32 %tmp.1, 2
ret i32 %tmp.5
}