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:
Philip Reames 2016-12-01 20:08:47 +00:00
parent e126eb1e0d
commit c0d2319dda
4 changed files with 113 additions and 80 deletions

View File

@ -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;

View File

@ -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;
} }

View File

@ -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())

View File

@ -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;