mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-28 22:20:43 +00:00
Factor out common parts of LVI and Float2Int into ConstantRange [NFCI]
This just extracts out the transfer rules for constant ranges into a single shared point. As it happens, neither bit of code actually overlaps in terms of the handled operators, but with this change that could easily be tweaked in the future. I also want to have this separated out to make experimenting with a eager value info implementation and possibly a ValueTracking-like fixed depth recursion peephole version. There's no reason all four of these can't share a common implementation which reduces the chances of bugs. Differential Revision: https://reviews.llvm.org/D27294 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@288413 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e126eb1e0d
commit
c0d2319dda
@ -233,6 +233,15 @@ public:
|
||||
///
|
||||
ConstantRange unionWith(const ConstantRange &CR) const;
|
||||
|
||||
/// Return a new range representing the possible values resulting
|
||||
/// from an application of the specified cast operator to this range. \p
|
||||
/// BitWidth is the target bitwidth of the cast. For casts which don't
|
||||
/// change bitwidth, it must be the same as the source bitwidth. For casts
|
||||
/// which do change bitwidth, the bitwidth must be consistent with the
|
||||
/// requested cast and source bitwidth.
|
||||
ConstantRange castOp(Instruction::CastOps CastOp,
|
||||
uint32_t BitWidth) const;
|
||||
|
||||
/// Return a new range in the specified integer type, which must
|
||||
/// be strictly larger than the current type. The returned range will
|
||||
/// correspond to the possible range of values if the source range had been
|
||||
@ -259,6 +268,12 @@ public:
|
||||
/// value is sign extended, truncated, or left alone to make it that width.
|
||||
ConstantRange sextOrTrunc(uint32_t BitWidth) const;
|
||||
|
||||
/// Return a new range representing the possible values resulting
|
||||
/// from an application of the specified binary operator to an left hand side
|
||||
/// of this range and a right hand side of \p Other.
|
||||
ConstantRange binaryOp(Instruction::BinaryOps BinOp,
|
||||
const ConstantRange &Other) const;
|
||||
|
||||
/// Return a new range representing the possible values resulting
|
||||
/// from an addition of a value in this range and a value in \p Other.
|
||||
ConstantRange add(const ConstantRange &Other) const;
|
||||
|
@ -1160,25 +1160,8 @@ bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
|
||||
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||
// more definitions.
|
||||
LVILatticeVal Result;
|
||||
switch (BBI->getOpcode()) {
|
||||
case Instruction::Trunc:
|
||||
Result.markConstantRange(LHSRange.truncate(ResultBitWidth));
|
||||
break;
|
||||
case Instruction::SExt:
|
||||
Result.markConstantRange(LHSRange.signExtend(ResultBitWidth));
|
||||
break;
|
||||
case Instruction::ZExt:
|
||||
Result.markConstantRange(LHSRange.zeroExtend(ResultBitWidth));
|
||||
break;
|
||||
case Instruction::BitCast:
|
||||
Result.markConstantRange(LHSRange);
|
||||
break;
|
||||
default:
|
||||
// Should be dead if the code above is correct
|
||||
llvm_unreachable("inconsistent with above");
|
||||
break;
|
||||
}
|
||||
|
||||
auto CastOp = (Instruction::CastOps) BBI->getOpcode();
|
||||
Result.markConstantRange(LHSRange.castOp(CastOp, ResultBitWidth));
|
||||
BBLV = Result;
|
||||
return true;
|
||||
}
|
||||
@ -1238,37 +1221,8 @@ bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
|
||||
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||
// more definitions.
|
||||
LVILatticeVal Result;
|
||||
switch (BBI->getOpcode()) {
|
||||
case Instruction::Add:
|
||||
Result.markConstantRange(LHSRange.add(RHSRange));
|
||||
break;
|
||||
case Instruction::Sub:
|
||||
Result.markConstantRange(LHSRange.sub(RHSRange));
|
||||
break;
|
||||
case Instruction::Mul:
|
||||
Result.markConstantRange(LHSRange.multiply(RHSRange));
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
Result.markConstantRange(LHSRange.udiv(RHSRange));
|
||||
break;
|
||||
case Instruction::Shl:
|
||||
Result.markConstantRange(LHSRange.shl(RHSRange));
|
||||
break;
|
||||
case Instruction::LShr:
|
||||
Result.markConstantRange(LHSRange.lshr(RHSRange));
|
||||
break;
|
||||
case Instruction::And:
|
||||
Result.markConstantRange(LHSRange.binaryAnd(RHSRange));
|
||||
break;
|
||||
case Instruction::Or:
|
||||
Result.markConstantRange(LHSRange.binaryOr(RHSRange));
|
||||
break;
|
||||
default:
|
||||
// Should be dead if the code above is correct
|
||||
llvm_unreachable("inconsistent with above");
|
||||
break;
|
||||
}
|
||||
|
||||
auto BinOp = (Instruction::BinaryOps) BBI->getOpcode();
|
||||
Result.markConstantRange(LHSRange.binaryOp(BinOp, RHSRange));
|
||||
BBLV = Result;
|
||||
return true;
|
||||
}
|
||||
|
@ -534,6 +534,49 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const {
|
||||
return ConstantRange(L, U);
|
||||
}
|
||||
|
||||
ConstantRange ConstantRange::castOp(Instruction::CastOps CastOp,
|
||||
uint32_t ResultBitWidth) const {
|
||||
switch (CastOp) {
|
||||
default:
|
||||
llvm_unreachable("unsupported cast type");
|
||||
case Instruction::Trunc:
|
||||
return truncate(ResultBitWidth);
|
||||
case Instruction::SExt:
|
||||
return signExtend(ResultBitWidth);
|
||||
case Instruction::ZExt:
|
||||
return zeroExtend(ResultBitWidth);
|
||||
case Instruction::BitCast:
|
||||
return *this;
|
||||
case Instruction::FPToUI:
|
||||
case Instruction::FPToSI:
|
||||
if (getBitWidth() == ResultBitWidth)
|
||||
return *this;
|
||||
else
|
||||
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
|
||||
case Instruction::UIToFP: {
|
||||
// TODO: use input range if available
|
||||
auto BW = getBitWidth();
|
||||
APInt Min = APInt::getMinValue(BW).zextOrSelf(ResultBitWidth);
|
||||
APInt Max = APInt::getMaxValue(BW).zextOrSelf(ResultBitWidth);
|
||||
return ConstantRange(Min, Max);
|
||||
}
|
||||
case Instruction::SIToFP: {
|
||||
// TODO: use input range if available
|
||||
auto BW = getBitWidth();
|
||||
APInt SMin = APInt::getSignedMinValue(BW).sextOrSelf(ResultBitWidth);
|
||||
APInt SMax = APInt::getSignedMaxValue(BW).sextOrSelf(ResultBitWidth);
|
||||
return ConstantRange(SMin, SMax);
|
||||
}
|
||||
case Instruction::FPTrunc:
|
||||
case Instruction::FPExt:
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::PtrToInt:
|
||||
case Instruction::AddrSpaceCast:
|
||||
// Conservatively return full set.
|
||||
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
|
||||
};
|
||||
}
|
||||
|
||||
/// zeroExtend - Return a new range in the specified integer type, which must
|
||||
/// be strictly larger than the current type. The returned range will
|
||||
/// correspond to the possible range of values as if the source range had been
|
||||
@ -653,6 +696,42 @@ ConstantRange ConstantRange::sextOrTrunc(uint32_t DstTySize) const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConstantRange ConstantRange::binaryOp(Instruction::BinaryOps BinOp,
|
||||
const ConstantRange &Other) const {
|
||||
assert(BinOp >= Instruction::BinaryOpsBegin &&
|
||||
BinOp < Instruction::BinaryOpsEnd && "Binary operators only!");
|
||||
|
||||
switch (BinOp) {
|
||||
case Instruction::Add:
|
||||
return add(Other);
|
||||
case Instruction::Sub:
|
||||
return sub(Other);
|
||||
case Instruction::Mul:
|
||||
return multiply(Other);
|
||||
case Instruction::UDiv:
|
||||
return udiv(Other);
|
||||
case Instruction::Shl:
|
||||
return shl(Other);
|
||||
case Instruction::LShr:
|
||||
return lshr(Other);
|
||||
case Instruction::And:
|
||||
return binaryAnd(Other);
|
||||
case Instruction::Or:
|
||||
return binaryOr(Other);
|
||||
// Note: floating point operations applied to abstract ranges are just
|
||||
// ideal integer operations with a lossy representation
|
||||
case Instruction::FAdd:
|
||||
return add(Other);
|
||||
case Instruction::FSub:
|
||||
return sub(Other);
|
||||
case Instruction::FMul:
|
||||
return multiply(Other);
|
||||
default:
|
||||
// Conservatively return full set.
|
||||
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
ConstantRange
|
||||
ConstantRange::add(const ConstantRange &Other) const {
|
||||
if (isEmptySet() || Other.isEmptySet())
|
||||
|
@ -190,21 +190,14 @@ void Float2IntPass::walkBackwards(const SmallPtrSetImpl<Instruction*> &Roots) {
|
||||
seen(I, badRange());
|
||||
break;
|
||||
|
||||
case Instruction::UIToFP: {
|
||||
// Path terminated cleanly.
|
||||
unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
|
||||
APInt Min = APInt::getMinValue(BW).zextOrSelf(MaxIntegerBW+1);
|
||||
APInt Max = APInt::getMaxValue(BW).zextOrSelf(MaxIntegerBW+1);
|
||||
seen(I, validateRange(ConstantRange(Min, Max)));
|
||||
continue;
|
||||
}
|
||||
|
||||
case Instruction::UIToFP:
|
||||
case Instruction::SIToFP: {
|
||||
// Path terminated cleanly.
|
||||
// Path terminated cleanly - use the type of the integer input to seed
|
||||
// the analysis.
|
||||
unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
|
||||
APInt SMin = APInt::getSignedMinValue(BW).sextOrSelf(MaxIntegerBW+1);
|
||||
APInt SMax = APInt::getSignedMaxValue(BW).sextOrSelf(MaxIntegerBW+1);
|
||||
seen(I, validateRange(ConstantRange(SMin, SMax)));
|
||||
auto Input = ConstantRange(BW, true);
|
||||
auto CastOp = (Instruction::CastOps)I->getOpcode();
|
||||
seen(I, validateRange(Input.castOp(CastOp, MaxIntegerBW+1)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -249,23 +242,12 @@ void Float2IntPass::walkForwards() {
|
||||
llvm_unreachable("Should have been handled in walkForwards!");
|
||||
|
||||
case Instruction::FAdd:
|
||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
||||
assert(Ops.size() == 2 && "FAdd is a binary operator!");
|
||||
return Ops[0].add(Ops[1]);
|
||||
};
|
||||
break;
|
||||
|
||||
case Instruction::FSub:
|
||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
||||
assert(Ops.size() == 2 && "FSub is a binary operator!");
|
||||
return Ops[0].sub(Ops[1]);
|
||||
};
|
||||
break;
|
||||
|
||||
case Instruction::FMul:
|
||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
||||
assert(Ops.size() == 2 && "FMul is a binary operator!");
|
||||
return Ops[0].multiply(Ops[1]);
|
||||
Op = [I](ArrayRef<ConstantRange> Ops) {
|
||||
assert(Ops.size() == 2 && "its a binary operator!");
|
||||
auto BinOp = (Instruction::BinaryOps) I->getOpcode();
|
||||
return Ops[0].binaryOp(BinOp, Ops[1]);
|
||||
};
|
||||
break;
|
||||
|
||||
@ -275,9 +257,12 @@ void Float2IntPass::walkForwards() {
|
||||
//
|
||||
case Instruction::FPToUI:
|
||||
case Instruction::FPToSI:
|
||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
||||
Op = [I](ArrayRef<ConstantRange> Ops) {
|
||||
assert(Ops.size() == 1 && "FPTo[US]I is a unary operator!");
|
||||
return Ops[0];
|
||||
// Note: We're ignoring the casts output size here as that's what the
|
||||
// caller expects.
|
||||
auto CastOp = (Instruction::CastOps)I->getOpcode();
|
||||
return Ops[0].castOp(CastOp, MaxIntegerBW+1);
|
||||
};
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user