/// successful.
bool getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const;
+ /// Set up \p Pred, \p RHS and \p Offset such that (V + Offset) Pred RHS
+ /// is true iff V is in the range. Prefers using Offset == 0 if possible.
+ void
+ getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS, APInt &Offset) const;
+
/// Return the lower value for this range.
const APInt &getLower() const { return Lower; }
return CmpInst::Predicate::BAD_ICMP_PREDICATE;
}
-bool ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred,
- APInt &RHS) const {
- bool Success = false;
-
+void ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred,
+ APInt &RHS, APInt &Offset) const {
+ Offset = APInt(getBitWidth(), 0);
if (isFullSet() || isEmptySet()) {
Pred = isEmptySet() ? CmpInst::ICMP_ULT : CmpInst::ICMP_UGE;
RHS = APInt(getBitWidth(), 0);
- Success = true;
} else if (auto *OnlyElt = getSingleElement()) {
Pred = CmpInst::ICMP_EQ;
RHS = *OnlyElt;
- Success = true;
} else if (auto *OnlyMissingElt = getSingleMissingElement()) {
Pred = CmpInst::ICMP_NE;
RHS = *OnlyMissingElt;
- Success = true;
} else if (getLower().isMinSignedValue() || getLower().isMinValue()) {
Pred =
getLower().isMinSignedValue() ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT;
RHS = getUpper();
- Success = true;
} else if (getUpper().isMinSignedValue() || getUpper().isMinValue()) {
Pred =
getUpper().isMinSignedValue() ? CmpInst::ICMP_SGE : CmpInst::ICMP_UGE;
RHS = getLower();
- Success = true;
+ } else {
+ Pred = CmpInst::ICMP_ULT;
+ RHS = getUpper() - getLower();
+ Offset = -getLower();
}
- assert((!Success || ConstantRange::makeExactICmpRegion(Pred, RHS) == *this) &&
+ assert(ConstantRange::makeExactICmpRegion(Pred, RHS) == add(Offset) &&
"Bad result!");
+}
- return Success;
+bool ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred,
+ APInt &RHS) const {
+ APInt Offset;
+ getEquivalentICmp(Pred, RHS, Offset);
+ return Offset.isZero();
}
bool ConstantRange::icmp(CmpInst::Predicate Pred,
// checking for overflow.
const APInt *C;
if (match(WO->getRHS(), m_APInt(C))) {
- // Compute the no-wrap range [X,Y) for LHS given RHS=C, then
- // check for the inverted range using range offset trick (i.e.
- // use a subtract to shift the range to bottom of either the
- // signed or unsigned domain and then use a single compare to
- // check range membership).
+ // Compute the no-wrap range for LHS given RHS=C, then construct an
+ // equivalent icmp, potentially using an offset.
ConstantRange NWR =
ConstantRange::makeExactNoWrapRegion(WO->getBinaryOp(), *C,
WO->getNoWrapKind());
- APInt Min = WO->isSigned() ? NWR.getSignedMin() : NWR.getUnsignedMin();
- NWR = NWR.subtract(Min);
CmpInst::Predicate Pred;
- APInt NewRHSC;
- if (NWR.getEquivalentICmp(Pred, NewRHSC)) {
- auto *OpTy = WO->getRHS()->getType();
- auto *NewLHS = Builder.CreateSub(WO->getLHS(),
- ConstantInt::get(OpTy, Min));
- return new ICmpInst(ICmpInst::getInversePredicate(Pred), NewLHS,
- ConstantInt::get(OpTy, NewRHSC));
- }
+ APInt NewRHSC, Offset;
+ NWR.getEquivalentICmp(Pred, NewRHSC, Offset);
+ auto *OpTy = WO->getRHS()->getType();
+ auto *NewLHS = WO->getLHS();
+ if (Offset != 0)
+ NewLHS = Builder.CreateAdd(NewLHS, ConstantInt::get(OpTy, Offset));
+ return new ICmpInst(ICmpInst::getInversePredicate(Pred), NewLHS,
+ ConstantInt::get(OpTy, NewRHSC));
}
}
}
ConstantRange(APInt(32, -1)).inverse().getEquivalentICmp(Pred, RHS));
EXPECT_EQ(Pred, CmpInst::ICMP_NE);
EXPECT_EQ(RHS, APInt(32, -1));
+
+ EnumerateConstantRanges(4, [](const ConstantRange &CR) {
+ CmpInst::Predicate Pred;
+ APInt RHS, Offset;
+ CR.getEquivalentICmp(Pred, RHS, Offset);
+ ForeachNumInConstantRange(ConstantRange::getFull(4), [&](const APInt &N) {
+ bool Result = ICmpInst::compare(N + Offset, RHS, Pred);
+ EXPECT_EQ(CR.contains(N), Result);
+ });
+
+ if (CR.getEquivalentICmp(Pred, RHS)) {
+ ForeachNumInConstantRange(ConstantRange::getFull(4), [&](const APInt &N) {
+ bool Result = ICmpInst::compare(N, RHS, Pred);
+ EXPECT_EQ(CR.contains(N), Result);
+ });
+ }
+ });
}
#define EXPECT_MAY_OVERFLOW(op) \