@@ -1738,27 +1738,6 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
1738
1738
if (IVType->getBitWidth () > RCType->getBitWidth ())
1739
1739
return std::nullopt;
1740
1740
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
-
1762
1741
// IndVar is of the form "A + B * I" (where "I" is the canonical induction
1763
1742
// variable, that may or may not exist as a real llvm::Value in the loop) and
1764
1743
// this inductive range check is a range check on the "C + D * I" ("C" is
@@ -1797,6 +1776,7 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
1797
1776
assert (!D->getValue ()->isZero () && " Recurrence with zero step?" );
1798
1777
unsigned BitWidth = RCType->getBitWidth ();
1799
1778
const SCEV *SIntMax = SE.getConstant (APInt::getSignedMaxValue (BitWidth));
1779
+ const SCEV *SIntMin = SE.getConstant (APInt::getSignedMinValue (BitWidth));
1800
1780
1801
1781
// Subtract Y from X so that it does not go through border of the IV
1802
1782
// iteration space. Mathematically, it is equivalent to:
@@ -1848,6 +1828,7 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
1848
1828
// This function returns SCEV equal to 1 if X is non-negative 0 otherwise.
1849
1829
auto SCEVCheckNonNegative = [&](const SCEV *X) {
1850
1830
const Loop *L = IndVar->getLoop ();
1831
+ const SCEV *Zero = SE.getZero (X->getType ());
1851
1832
const SCEV *One = SE.getOne (X->getType ());
1852
1833
// Can we trivially prove that X is a non-negative or negative value?
1853
1834
if (isKnownNonNegativeInLoop (X, L, SE))
@@ -1859,6 +1840,25 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
1859
1840
const SCEV *NegOne = SE.getNegativeSCEV (One);
1860
1841
return SE.getAddExpr (SE.getSMaxExpr (SE.getSMinExpr (X, Zero), NegOne), One);
1861
1842
};
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
+
1862
1862
// FIXME: Current implementation of ClampedSubtract implicitly assumes that
1863
1863
// X is non-negative (in sense of a signed value). We need to re-implement
1864
1864
// this function in a way that it will correctly handle negative X as well.
@@ -1868,10 +1868,35 @@ InductiveRangeCheck::computeSafeIterationSpace(ScalarEvolution &SE,
1868
1868
// Note that this may pessimize elimination of unsigned range checks against
1869
1869
// negative values.
1870
1870
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);
1872
1899
1873
- const SCEV *Begin = SE.getMulExpr (ClampedSubtract (Zero, M), EndIsNonNegative);
1874
- const SCEV *End = SE.getMulExpr (ClampedSubtract (REnd, M), EndIsNonNegative);
1875
1900
return InductiveRangeCheck::Range (Begin, End);
1876
1901
}
1877
1902
0 commit comments