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;
|
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
|
/// Return a new range in the specified integer type, which must
|
||||||
/// be strictly larger than the current type. The returned range will
|
/// be strictly larger than the current type. The returned range will
|
||||||
/// correspond to the possible range of values if the source range had been
|
/// 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.
|
/// value is sign extended, truncated, or left alone to make it that width.
|
||||||
ConstantRange sextOrTrunc(uint32_t BitWidth) const;
|
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
|
/// Return a new range representing the possible values resulting
|
||||||
/// from an addition of a value in this range and a value in \p Other.
|
/// from an addition of a value in this range and a value in \p Other.
|
||||||
ConstantRange add(const ConstantRange &Other) const;
|
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
|
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||||
// more definitions.
|
// more definitions.
|
||||||
LVILatticeVal Result;
|
LVILatticeVal Result;
|
||||||
switch (BBI->getOpcode()) {
|
auto CastOp = (Instruction::CastOps) BBI->getOpcode();
|
||||||
case Instruction::Trunc:
|
Result.markConstantRange(LHSRange.castOp(CastOp, ResultBitWidth));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BBLV = Result;
|
BBLV = Result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1238,37 +1221,8 @@ bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
|
|||||||
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||||
// more definitions.
|
// more definitions.
|
||||||
LVILatticeVal Result;
|
LVILatticeVal Result;
|
||||||
switch (BBI->getOpcode()) {
|
auto BinOp = (Instruction::BinaryOps) BBI->getOpcode();
|
||||||
case Instruction::Add:
|
Result.markConstantRange(LHSRange.binaryOp(BinOp, RHSRange));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BBLV = Result;
|
BBLV = Result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -534,6 +534,49 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const {
|
|||||||
return ConstantRange(L, U);
|
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
|
/// zeroExtend - Return a new range in the specified integer type, which must
|
||||||
/// be strictly larger than the current type. The returned range will
|
/// 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
|
/// 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;
|
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
|
||||||
ConstantRange::add(const ConstantRange &Other) const {
|
ConstantRange::add(const ConstantRange &Other) const {
|
||||||
if (isEmptySet() || Other.isEmptySet())
|
if (isEmptySet() || Other.isEmptySet())
|
||||||
|
@ -190,21 +190,14 @@ void Float2IntPass::walkBackwards(const SmallPtrSetImpl<Instruction*> &Roots) {
|
|||||||
seen(I, badRange());
|
seen(I, badRange());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction::UIToFP: {
|
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::SIToFP: {
|
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();
|
unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
|
||||||
APInt SMin = APInt::getSignedMinValue(BW).sextOrSelf(MaxIntegerBW+1);
|
auto Input = ConstantRange(BW, true);
|
||||||
APInt SMax = APInt::getSignedMaxValue(BW).sextOrSelf(MaxIntegerBW+1);
|
auto CastOp = (Instruction::CastOps)I->getOpcode();
|
||||||
seen(I, validateRange(ConstantRange(SMin, SMax)));
|
seen(I, validateRange(Input.castOp(CastOp, MaxIntegerBW+1)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,23 +242,12 @@ void Float2IntPass::walkForwards() {
|
|||||||
llvm_unreachable("Should have been handled in walkForwards!");
|
llvm_unreachable("Should have been handled in walkForwards!");
|
||||||
|
|
||||||
case Instruction::FAdd:
|
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:
|
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:
|
case Instruction::FMul:
|
||||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
Op = [I](ArrayRef<ConstantRange> Ops) {
|
||||||
assert(Ops.size() == 2 && "FMul is a binary operator!");
|
assert(Ops.size() == 2 && "its a binary operator!");
|
||||||
return Ops[0].multiply(Ops[1]);
|
auto BinOp = (Instruction::BinaryOps) I->getOpcode();
|
||||||
|
return Ops[0].binaryOp(BinOp, Ops[1]);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -275,9 +257,12 @@ void Float2IntPass::walkForwards() {
|
|||||||
//
|
//
|
||||||
case Instruction::FPToUI:
|
case Instruction::FPToUI:
|
||||||
case Instruction::FPToSI:
|
case Instruction::FPToSI:
|
||||||
Op = [](ArrayRef<ConstantRange> Ops) {
|
Op = [I](ArrayRef<ConstantRange> Ops) {
|
||||||
assert(Ops.size() == 1 && "FPTo[US]I is a unary operator!");
|
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;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user