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
llvm-svn: 288413
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index e188c80..a85ad46 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -534,6 +534,49 @@
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 @@
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())