mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-22 13:29:44 +00:00
Enhance MVIZ in three ways:
1. Teach it new tricks: in particular how to propagate through signed shr and sexts. 2. Teach it to return a bitset of known-1 and known-0 bits, instead of just zero. 3. Teach instcombine (AND X, C) to fold when we know all C bits of X. This implements Regression/Transforms/InstCombine/bittest.ll, and allows future things to be simplified. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26087 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
12f7de8222
commit
68d5ff2b83
@ -406,88 +406,182 @@ static ConstantInt *SubOne(ConstantInt *C) {
|
|||||||
ConstantInt::get(C->getType(), 1)));
|
ConstantInt::get(C->getType(), 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ComputeMaskedNonZeroBits - Determine which of the bits specified in Mask are
|
/// ComputeMaskedBits - Determine which of the bits specified in Mask are
|
||||||
/// not known to be zero and return them as a bitmask. The bits that we can
|
/// known to be either zero or one and return them in the KnownZero/KnownOne
|
||||||
/// guarantee to be zero are returned as zero bits in the result.
|
/// bitsets. This code only analyzes bits in Mask, in order to short-circuit
|
||||||
static uint64_t ComputeMaskedNonZeroBits(Value *V, uint64_t Mask,
|
/// processing.
|
||||||
unsigned Depth = 0) {
|
static void ComputeMaskedBits(Value *V, uint64_t Mask, uint64_t &KnownZero,
|
||||||
|
uint64_t &KnownOne, unsigned Depth = 0) {
|
||||||
// Note, we cannot consider 'undef' to be "IsZero" here. The problem is that
|
// Note, we cannot consider 'undef' to be "IsZero" here. The problem is that
|
||||||
// we cannot optimize based on the assumption that it is zero without changing
|
// we cannot optimize based on the assumption that it is zero without changing
|
||||||
// it to be an explicit zero. If we don't change it to zero, other code could
|
// it to be an explicit zero. If we don't change it to zero, other code could
|
||||||
// optimized based on the contradictory assumption that it is non-zero.
|
// optimized based on the contradictory assumption that it is non-zero.
|
||||||
// Because instcombine aggressively folds operations with undef args anyway,
|
// Because instcombine aggressively folds operations with undef args anyway,
|
||||||
// this won't lose us code quality.
|
// this won't lose us code quality.
|
||||||
if (ConstantIntegral *CI = dyn_cast<ConstantIntegral>(V))
|
if (ConstantIntegral *CI = dyn_cast<ConstantIntegral>(V)) {
|
||||||
return CI->getRawValue() & Mask;
|
// We know all of the bits for a constant!
|
||||||
|
KnownOne = CI->getZExtValue();
|
||||||
|
KnownZero = ~KnownOne & Mask;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KnownZero = KnownOne = 0; // Don't know anything.
|
||||||
if (Depth == 6 || Mask == 0)
|
if (Depth == 6 || Mask == 0)
|
||||||
return Mask; // Limit search depth.
|
return; // Limit search depth.
|
||||||
|
|
||||||
|
uint64_t KnownZero2, KnownOne2;
|
||||||
if (Instruction *I = dyn_cast<Instruction>(V)) {
|
if (Instruction *I = dyn_cast<Instruction>(V)) {
|
||||||
switch (I->getOpcode()) {
|
switch (I->getOpcode()) {
|
||||||
case Instruction::And:
|
case Instruction::And:
|
||||||
// (X & C1) & C2 == 0 iff C1 & C2 == 0.
|
// If either the LHS or the RHS are Zero, the result is zero.
|
||||||
if (ConstantIntegral *CI = dyn_cast<ConstantIntegral>(I->getOperand(1)))
|
ComputeMaskedBits(I->getOperand(1), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(0),
|
Mask &= ~KnownZero;
|
||||||
CI->getRawValue() & Mask, Depth+1);
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero2, KnownOne2, Depth+1);
|
||||||
// If either the LHS or the RHS are MaskedValueIsZero, the result is zero.
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
Mask = ComputeMaskedNonZeroBits(I->getOperand(1), Mask, Depth+1);
|
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");
|
||||||
Mask = ComputeMaskedNonZeroBits(I->getOperand(0), Mask, Depth+1);
|
|
||||||
return Mask;
|
// Output known-1 bits are only known if set in both the LHS & RHS.
|
||||||
|
KnownOne &= KnownOne2;
|
||||||
|
// Output known-0 are known to be clear if zero in either the LHS | RHS.
|
||||||
|
KnownZero |= KnownZero2;
|
||||||
|
return;
|
||||||
case Instruction::Or:
|
case Instruction::Or:
|
||||||
case Instruction::Xor:
|
ComputeMaskedBits(I->getOperand(1), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
// Any non-zero bits in the LHS or RHS are potentially non-zero in the
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero2, KnownOne2, Depth+1);
|
||||||
// result.
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(1), Mask, Depth+1) |
|
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");
|
||||||
ComputeMaskedNonZeroBits(I->getOperand(0), Mask, Depth+1);
|
|
||||||
|
// Output known-0 bits are only known if clear in both the LHS & RHS.
|
||||||
|
KnownZero &= KnownZero2;
|
||||||
|
// Output known-1 are known to be set if set in either the LHS | RHS.
|
||||||
|
KnownOne |= KnownOne2;
|
||||||
|
return;
|
||||||
|
case Instruction::Xor: {
|
||||||
|
ComputeMaskedBits(I->getOperand(1), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero2, KnownOne2, Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
|
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");
|
||||||
|
|
||||||
|
// Output known-0 bits are known if clear or set in both the LHS & RHS.
|
||||||
|
uint64_t KnownZeroOut = (KnownZero & KnownZero2) | (KnownOne & KnownOne2);
|
||||||
|
// Output known-1 are known to be set if set in only one of the LHS, RHS.
|
||||||
|
KnownOne = (KnownZero & KnownOne2) | (KnownOne & KnownZero2);
|
||||||
|
KnownZero = KnownZeroOut;
|
||||||
|
return;
|
||||||
|
}
|
||||||
case Instruction::Select:
|
case Instruction::Select:
|
||||||
// Any non-zero bits in the T or F values are potentially non-zero in the
|
ComputeMaskedBits(I->getOperand(2), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
// result.
|
ComputeMaskedBits(I->getOperand(1), Mask, KnownZero2, KnownOne2, Depth+1);
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(2), Mask, Depth+1) |
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
ComputeMaskedNonZeroBits(I->getOperand(1), Mask, Depth+1);
|
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");
|
||||||
|
|
||||||
|
// Only known if known in both the LHS and RHS.
|
||||||
|
KnownOne &= KnownOne2;
|
||||||
|
KnownZero &= KnownZero2;
|
||||||
|
return;
|
||||||
case Instruction::Cast: {
|
case Instruction::Cast: {
|
||||||
const Type *SrcTy = I->getOperand(0)->getType();
|
const Type *SrcTy = I->getOperand(0)->getType();
|
||||||
if (SrcTy == Type::BoolTy)
|
if (!SrcTy->isIntegral()) return;
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(0), Mask & 1, Depth+1);
|
|
||||||
if (!SrcTy->isInteger()) return Mask;
|
|
||||||
|
|
||||||
// (cast <ty> X to int) & C2 == 0 iff <ty> could not have contained C2.
|
// If this is an integer truncate or noop, just look in the input.
|
||||||
if (SrcTy->isUnsigned() || // Only handle zero ext/trunc/noop
|
if (SrcTy->getPrimitiveSizeInBits() >=
|
||||||
SrcTy->getPrimitiveSizeInBits() >=
|
I->getType()->getPrimitiveSizeInBits()) {
|
||||||
I->getType()->getPrimitiveSizeInBits()) {
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
Mask &= SrcTy->getIntegralTypeMask();
|
return;
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(0), Mask, Depth+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: handle sext casts.
|
// Sign or Zero extension. Compute the bits in the result that are not
|
||||||
break;
|
// present in the input.
|
||||||
|
uint64_t NotIn = ~SrcTy->getIntegralTypeMask();
|
||||||
|
uint64_t NewBits = I->getType()->getIntegralTypeMask() & NotIn;
|
||||||
|
|
||||||
|
// Handle zero extension.
|
||||||
|
if (!SrcTy->isSigned()) {
|
||||||
|
Mask &= SrcTy->getIntegralTypeMask();
|
||||||
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
|
// The top bits are known to be zero.
|
||||||
|
KnownZero |= NewBits;
|
||||||
|
} else {
|
||||||
|
// Sign extension.
|
||||||
|
Mask &= SrcTy->getIntegralTypeMask();
|
||||||
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
|
|
||||||
|
// If the sign bit of the input is known set or clear, then we know the
|
||||||
|
// top bits of the result.
|
||||||
|
uint64_t InSignBit = 1ULL << (SrcTy->getPrimitiveSizeInBits()-1);
|
||||||
|
if (KnownZero & InSignBit) { // Input sign bit known zero
|
||||||
|
KnownZero |= NewBits;
|
||||||
|
KnownOne &= ~NewBits;
|
||||||
|
} else if (KnownOne & InSignBit) { // Input sign bit known set
|
||||||
|
KnownOne |= NewBits;
|
||||||
|
KnownZero &= ~NewBits;
|
||||||
|
} else { // Input sign bit unknown
|
||||||
|
KnownZero &= ~NewBits;
|
||||||
|
KnownOne &= ~NewBits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
case Instruction::Shl:
|
case Instruction::Shl:
|
||||||
// (shl X, C1) & C2 == 0 iff (X & C2 >>u C1) == 0
|
// (shl X, C1) & C2 == 0 iff (X & C2 >>u C1) == 0
|
||||||
if (ConstantUInt *SA = dyn_cast<ConstantUInt>(I->getOperand(1)))
|
if (ConstantUInt *SA = dyn_cast<ConstantUInt>(I->getOperand(1))) {
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(0),Mask >> SA->getValue(),
|
Mask >> SA->getValue();
|
||||||
Depth+1) << SA->getValue();
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero, KnownOne, Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
|
KnownZero <<= SA->getValue();
|
||||||
|
KnownOne <<= SA->getValue();
|
||||||
|
KnownZero |= (1ULL << SA->getValue())-1; // low bits known zero.
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Instruction::Shr:
|
case Instruction::Shr:
|
||||||
// (ushr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0
|
// (ushr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0
|
||||||
if (ConstantUInt *SA = dyn_cast<ConstantUInt>(I->getOperand(1)))
|
if (ConstantUInt *SA = dyn_cast<ConstantUInt>(I->getOperand(1))) {
|
||||||
if (I->getType()->isUnsigned()) {
|
// Compute the new bits that are at the top now.
|
||||||
Mask <<= SA->getValue();
|
uint64_t HighBits = (1ULL << SA->getValue())-1;
|
||||||
Mask &= I->getType()->getIntegralTypeMask();
|
HighBits <<= I->getType()->getPrimitiveSizeInBits()-SA->getValue();
|
||||||
return ComputeMaskedNonZeroBits(I->getOperand(0), Mask, Depth+1)
|
|
||||||
>> SA->getValue();
|
if (I->getType()->isUnsigned()) { // Unsigned shift right.
|
||||||
|
Mask << SA->getValue();
|
||||||
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero,KnownOne,Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
|
||||||
|
KnownZero >>= SA->getValue();
|
||||||
|
KnownOne >>= SA->getValue();
|
||||||
|
KnownZero |= HighBits; // high bits known zero.
|
||||||
|
} else {
|
||||||
|
Mask << SA->getValue();
|
||||||
|
ComputeMaskedBits(I->getOperand(0), Mask, KnownZero,KnownOne,Depth+1);
|
||||||
|
assert((KnownZero & KnownOne) == 0&&"Bits known to be one AND zero?");
|
||||||
|
KnownZero >>= SA->getValue();
|
||||||
|
KnownOne >>= SA->getValue();
|
||||||
|
|
||||||
|
// Handle the sign bits.
|
||||||
|
uint64_t SignBit = 1ULL << (I->getType()->getPrimitiveSizeInBits()-1);
|
||||||
|
SignBit >>= SA->getValue(); // Adjust to where it is now in the mask.
|
||||||
|
|
||||||
|
if (KnownZero & SignBit) { // New bits are known zero.
|
||||||
|
KnownZero |= HighBits;
|
||||||
|
} else if (KnownOne & SignBit) { // New bits are known one.
|
||||||
|
KnownOne |= HighBits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use
|
/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use
|
||||||
/// this predicate to simplify operations downstream. Mask is known to be zero
|
/// this predicate to simplify operations downstream. Mask is known to be zero
|
||||||
/// for bits that V cannot have.
|
/// for bits that V cannot have.
|
||||||
static bool MaskedValueIsZero(Value *V, uint64_t Mask, unsigned Depth = 0) {
|
static bool MaskedValueIsZero(Value *V, uint64_t Mask, unsigned Depth = 0) {
|
||||||
return ComputeMaskedNonZeroBits(V, Mask, Depth) == 0;
|
uint64_t KnownZero, KnownOne;
|
||||||
|
ComputeMaskedBits(V, Mask, KnownZero, KnownOne, Depth);
|
||||||
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||||
|
return (KnownZero & Mask) == Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SimplifyDemandedBits - Look at V. At this point, we know that only the Mask
|
/// SimplifyDemandedBits - Look at V. At this point, we know that only the Mask
|
||||||
@ -879,8 +973,9 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
|
|||||||
}
|
}
|
||||||
if (Found) {
|
if (Found) {
|
||||||
// This is a sign extend if the top bits are known zero.
|
// This is a sign extend if the top bits are known zero.
|
||||||
uint64_t Mask = XorLHS->getType()->getIntegralTypeMask();
|
uint64_t Mask = ~0ULL;
|
||||||
Mask <<= 64-(TySizeBits-Size);
|
Mask <<= 64-(TySizeBits-Size);
|
||||||
|
Mask &= XorLHS->getType()->getIntegralTypeMask();
|
||||||
if (!MaskedValueIsZero(XorLHS, Mask))
|
if (!MaskedValueIsZero(XorLHS, Mask))
|
||||||
Size = 0; // Not a sign ext, but can't be any others either.
|
Size = 0; // Not a sign ext, but can't be any others either.
|
||||||
goto FoundSExt;
|
goto FoundSExt;
|
||||||
@ -1949,22 +2044,29 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
|||||||
|
|
||||||
// Figure out which of the input bits are not known to be zero, and which
|
// Figure out which of the input bits are not known to be zero, and which
|
||||||
// bits are known to be zero.
|
// bits are known to be zero.
|
||||||
uint64_t NonZeroBits = ComputeMaskedNonZeroBits(Op0, TypeMask);
|
uint64_t KnownZeroBits, KnownOneBits;
|
||||||
uint64_t ZeroBits = NonZeroBits^TypeMask;
|
ComputeMaskedBits(Op0, TypeMask, KnownZeroBits, KnownOneBits);
|
||||||
|
|
||||||
// If the mask is not masking out any bits (i.e. all of the zeros in the
|
// If the mask is not masking out any bits (i.e. all of the zeros in the
|
||||||
// mask are already known to be zero), there is no reason to do the and in
|
// mask are already known to be zero), there is no reason to do the and in
|
||||||
// the first place.
|
// the first place.
|
||||||
uint64_t NotAndRHS = AndRHSMask^TypeMask;
|
uint64_t NotAndRHS = AndRHSMask^TypeMask;
|
||||||
if ((NotAndRHS & ZeroBits) == NotAndRHS)
|
if ((NotAndRHS & KnownZeroBits) == NotAndRHS)
|
||||||
return ReplaceInstUsesWith(I, Op0);
|
return ReplaceInstUsesWith(I, Op0);
|
||||||
|
|
||||||
|
// If the AND'd bits are all known, turn this AND into a constant.
|
||||||
|
if ((AndRHSMask & (KnownOneBits|KnownZeroBits)) == AndRHSMask) {
|
||||||
|
Constant *NewRHS = ConstantUInt::get(Type::ULongTy,
|
||||||
|
AndRHSMask & KnownOneBits);
|
||||||
|
return ReplaceInstUsesWith(I, ConstantExpr::getCast(NewRHS, I.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
// If the AND mask contains bits that are known zero, remove them. A
|
// If the AND mask contains bits that are known zero, remove them. A
|
||||||
// special case is when there are no bits in common, in which case we
|
// special case is when there are no bits in common, in which case we
|
||||||
// implicitly turn this into an AND X, 0, which is later simplified into 0.
|
// implicitly turn this into an AND X, 0, which is later simplified into 0.
|
||||||
if ((AndRHSMask & NonZeroBits) != AndRHSMask) {
|
if ((AndRHSMask & ~KnownZeroBits) != AndRHSMask) {
|
||||||
Constant *NewRHS =
|
Constant *NewRHS =
|
||||||
ConstantUInt::get(Type::ULongTy, AndRHSMask & NonZeroBits);
|
ConstantUInt::get(Type::ULongTy, AndRHSMask & ~KnownZeroBits);
|
||||||
I.setOperand(1, ConstantExpr::getCast(NewRHS, I.getType()));
|
I.setOperand(1, ConstantExpr::getCast(NewRHS, I.getType()));
|
||||||
return &I;
|
return &I;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user