Skip to content

Commit cdcefd2

Browse files
committed
[IRCE] Implement runtime overflow check for computed range's end
Here is activated check elimination which was parsed previously in https://reviews.llvm.org/D154069 * Added runtime check that computed range's boundary doesn't overflow in terms of range type. * From the statement INT_MIN <= END <= INT_MAX is inferred check: isNonNegative(INT_MAX - END) * isNonNegative(END - INT_MIN). * If overflow happens, check will return 0 and the safe interval will be empty. Reviewed By: skatkov Differential Revision: https://reviews.llvm.org/D154188
1 parent 367b1f2 commit cdcefd2

File tree

2 files changed

+230
-56
lines changed

2 files changed

+230
-56
lines changed

llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,27 +1738,6 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
17381738
if (IVType->getBitWidth() > RCType->getBitWidth())
17391739
return std::nullopt;
17401740

1741-
auto PrintRangeCheck = [&](raw_ostream &OS) {
1742-
auto L = IndVar->getLoop();
1743-
OS << "irce: in function ";
1744-
OS << L->getHeader()->getParent()->getName();
1745-
OS << ", in ";
1746-
L->print(OS);
1747-
OS << "there is range check with scaled boundary:\n";
1748-
print(OS);
1749-
};
1750-
1751-
if (EndType->getBitWidth() > RCType->getBitWidth()) {
1752-
assert(EndType->getBitWidth() == RCType->getBitWidth() * 2);
1753-
if (PrintScaledBoundaryRangeChecks)
1754-
PrintRangeCheck(errs());
1755-
// End is computed with extended type but will be truncated to a narrow one
1756-
// type of range check. Therefore we need a check that the result will not
1757-
// overflow in terms of narrow type.
1758-
// TODO: Support runtime overflow check for End
1759-
return std::nullopt;
1760-
}
1761-
17621741
// IndVar is of the form "A + B * I" (where "I" is the canonical induction
17631742
// variable, that may or may not exist as a real llvm::Value in the loop) and
17641743
// this inductive range check is a range check on the "C + D * I" ("C" is
@@ -1797,6 +1776,7 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
17971776
assert(!D->getValue()->isZero() && "Recurrence with zero step?");
17981777
unsigned BitWidth = RCType->getBitWidth();
17991778
const SCEV *SIntMax = SE.getConstant(APInt::getSignedMaxValue(BitWidth));
1779+
const SCEV *SIntMin = SE.getConstant(APInt::getSignedMinValue(BitWidth));
18001780

18011781
// Subtract Y from X so that it does not go through border of the IV
18021782
// iteration space. Mathematically, it is equivalent to:
@@ -1848,6 +1828,7 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
18481828
// This function returns SCEV equal to 1 if X is non-negative 0 otherwise.
18491829
auto SCEVCheckNonNegative = [&](const SCEV *X) {
18501830
const Loop *L = IndVar->getLoop();
1831+
const SCEV *Zero = SE.getZero(X->getType());
18511832
const SCEV *One = SE.getOne(X->getType());
18521833
// Can we trivially prove that X is a non-negative or negative value?
18531834
if (isKnownNonNegativeInLoop(X, L, SE))
@@ -1859,6 +1840,25 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
18591840
const SCEV *NegOne = SE.getNegativeSCEV(One);
18601841
return SE.getAddExpr(SE.getSMaxExpr(SE.getSMinExpr(X, Zero), NegOne), One);
18611842
};
1843+
1844+
// This function returns SCEV equal to 1 if X will not overflow in terms of
1845+
// range check type, 0 otherwise.
1846+
auto SCEVCheckWillNotOverflow = [&](const SCEV *X) {
1847+
// X doesn't overflow if SINT_MAX >= X.
1848+
// Then if (SINT_MAX - X) >= 0, X doesn't overflow
1849+
const SCEV *SIntMaxExt = SE.getSignExtendExpr(SIntMax, X->getType());
1850+
const SCEV *OverflowCheck =
1851+
SCEVCheckNonNegative(SE.getMinusSCEV(SIntMaxExt, X));
1852+
1853+
// X doesn't underflow if X >= SINT_MIN.
1854+
// Then if (X - SINT_MIN) >= 0, X doesn't underflow
1855+
const SCEV *SIntMinExt = SE.getSignExtendExpr(SIntMin, X->getType());
1856+
const SCEV *UnderflowCheck =
1857+
SCEVCheckNonNegative(SE.getMinusSCEV(X, SIntMinExt));
1858+
1859+
return SE.getMulExpr(OverflowCheck, UnderflowCheck);
1860+
};
1861+
18621862
// FIXME: Current implementation of ClampedSubtract implicitly assumes that
18631863
// X is non-negative (in sense of a signed value). We need to re-implement
18641864
// this function in a way that it will correctly handle negative X as well.
@@ -1868,10 +1868,35 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
18681868
// Note that this may pessimize elimination of unsigned range checks against
18691869
// negative values.
18701870
const SCEV *REnd = getEnd();
1871-
const SCEV *EndIsNonNegative = SCEVCheckNonNegative(REnd);
1871+
const SCEV *EndWillNotOverflow = SE.getOne(RCType);
1872+
1873+
auto PrintRangeCheck = [&](raw_ostream &OS) {
1874+
auto L = IndVar->getLoop();
1875+
OS << "irce: in function ";
1876+
OS << L->getHeader()->getParent()->getName();
1877+
OS << ", in ";
1878+
L->print(OS);
1879+
OS << "there is range check with scaled boundary:\n";
1880+
print(OS);
1881+
};
1882+
1883+
if (EndType->getBitWidth() > RCType->getBitWidth()) {
1884+
assert(EndType->getBitWidth() == RCType->getBitWidth() * 2);
1885+
if (PrintScaledBoundaryRangeChecks)
1886+
PrintRangeCheck(errs());
1887+
// End is computed with extended type but will be truncated to a narrow one
1888+
// type of range check. Therefore we need a check that the result will not
1889+
// overflow in terms of narrow type.
1890+
EndWillNotOverflow =
1891+
SE.getTruncateExpr(SCEVCheckWillNotOverflow(REnd), RCType);
1892+
REnd = SE.getTruncateExpr(REnd, RCType);
1893+
}
1894+
1895+
const SCEV *RuntimeChecks =
1896+
SE.getMulExpr(SCEVCheckNonNegative(REnd), EndWillNotOverflow);
1897+
const SCEV *Begin = SE.getMulExpr(ClampedSubtract(Zero, M), RuntimeChecks);
1898+
const SCEV *End = SE.getMulExpr(ClampedSubtract(REnd, M), RuntimeChecks);
18721899

1873-
const SCEV *Begin = SE.getMulExpr(ClampedSubtract(Zero, M), EndIsNonNegative);
1874-
const SCEV *End = SE.getMulExpr(ClampedSubtract(REnd, M), EndIsNonNegative);
18751900
return InductiveRangeCheck::Range(Begin, End);
18761901
}
18771902

0 commit comments

Comments
 (0)