@@ -118,6 +118,59 @@ bool IntegralRange::Contains(int64_t value) const
118118 }
119119}
120120
121+ // ------------------------------------------------------------------------
122+ // ForNode: Compute the integral range for a node.
123+ //
124+ // Arguments:
125+ // node - the node, of an integral type, in question
126+ // compiler - the Compiler, used to retrieve additional info
127+ //
128+ // Return Value:
129+ // The integral range this node produces.
130+ //
131+ /* static */ IntegralRange IntegralRange::ForNode (GenTree* node, Compiler* compiler)
132+ {
133+ assert (varTypeIsIntegral (node));
134+
135+ var_types rangeType = node->TypeGet ();
136+
137+ switch (node->OperGet ())
138+ {
139+ case GT_EQ:
140+ case GT_NE:
141+ case GT_LT:
142+ case GT_LE:
143+ case GT_GE:
144+ case GT_GT:
145+ return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
146+
147+ case GT_ARR_LENGTH:
148+ return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::IntMax};
149+
150+ case GT_CALL:
151+ if (node->AsCall ()->NormalizesSmallTypesOnReturn ())
152+ {
153+ rangeType = static_cast <var_types>(node->AsCall ()->gtReturnType );
154+ }
155+ break ;
156+
157+ case GT_LCL_VAR:
158+ if (compiler->lvaGetDesc (node->AsLclVar ())->lvNormalizeOnStore ())
159+ {
160+ rangeType = compiler->lvaGetDesc (node->AsLclVar ())->TypeGet ();
161+ }
162+ break ;
163+
164+ case GT_CAST:
165+ return ForCastOutput (node->AsCast ());
166+
167+ default :
168+ break ;
169+ }
170+
171+ return ForType (rangeType);
172+ }
173+
121174// ------------------------------------------------------------------------
122175// ForCastInput: Get the non-overflowing input range for a cast.
123176//
@@ -214,7 +267,14 @@ bool IntegralRange::Contains(int64_t value) const
214267 // CAST_OVF(long <- ulong) - [0..LONG_MAX]
215268 // CAST_OVF(long <- long) - [LONG_MIN..LONG_MAX]
216269 case TYP_LONG:
217- lowerBound = fromUnsigned ? SymbolicIntegerValue::Zero : LowerBoundForType (fromType);
270+ if (fromUnsigned && (fromType == TYP_LONG))
271+ {
272+ lowerBound = SymbolicIntegerValue::Zero;
273+ }
274+ else
275+ {
276+ lowerBound = LowerBoundForType (fromType);
277+ }
218278 upperBound = UpperBoundForType (fromType);
219279 break ;
220280
@@ -1545,12 +1605,17 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
15451605 }
15461606
15471607 // Try and see if we can make a subrange assertion.
1548- if (((assertionKind == OAK_SUBRANGE) || (assertionKind == OAK_EQUAL)))
1608+ if (((assertionKind == OAK_SUBRANGE) || (assertionKind == OAK_EQUAL)) && varTypeIsIntegral (op2) )
15491609 {
1550- if (optTryExtractSubrangeAssertion (op2, &assertion.op2 .u2 ))
1610+ IntegralRange nodeRange = IntegralRange::ForNode (op2, this );
1611+ IntegralRange typeRange = IntegralRange::ForType (genActualType (op2));
1612+ assert (typeRange.Contains (nodeRange));
1613+
1614+ if (!typeRange.Equals (nodeRange))
15511615 {
15521616 assertion.op2 .kind = O2K_SUBRANGE;
15531617 assertion.assertionKind = OAK_SUBRANGE;
1618+ assertion.op2 .u2 = nodeRange;
15541619 }
15551620 }
15561621 }
@@ -1689,73 +1754,6 @@ AssertionIndex Compiler::optFinalizeCreatingAssertion(AssertionDsc* assertion)
16891754 return optAddAssertion (assertion);
16901755}
16911756
1692- // ------------------------------------------------------------------------
1693- // optTryExtractSubrangeAssertion: Extract the bounds of the value a tree produces.
1694- //
1695- // Generates [0..1] ranges for relops, [T_MIN..T_MAX] for small-typed indirections
1696- // and casts to small types. Generates various ranges for casts to and from "large"
1697- // types - see "IntegralRange::ForCastOutput".
1698- //
1699- // Arguments:
1700- // source - tree producing the value
1701- // pRange - [out] parameter for the range
1702- //
1703- // Return Value:
1704- // "true" if the "source" computes a value that could be used for a subrange
1705- // assertion, i. e. narrower than the range of the node's type.
1706- //
1707- // Notes:
1708- // The "pRange" parameter is only written to if the function returns "true".
1709- //
1710- bool Compiler::optTryExtractSubrangeAssertion (GenTree* source, IntegralRange* pRange)
1711- {
1712- var_types sourceType = TYP_UNDEF;
1713-
1714- switch (source->OperGet ())
1715- {
1716- case GT_EQ:
1717- case GT_NE:
1718- case GT_LT:
1719- case GT_LE:
1720- case GT_GT:
1721- case GT_GE:
1722- *pRange = {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
1723- return true ;
1724-
1725- case GT_CLS_VAR:
1726- case GT_LCL_FLD:
1727- case GT_IND:
1728- sourceType = source->TypeGet ();
1729- break ;
1730-
1731- case GT_CAST:
1732- if (varTypeIsIntegral (source))
1733- {
1734- IntegralRange castRange = IntegralRange::ForCastOutput (source->AsCast ());
1735- IntegralRange nodeRange = IntegralRange::ForType (source->TypeGet ());
1736- assert (nodeRange.Contains (castRange));
1737-
1738- if (!castRange.Equals (nodeRange))
1739- {
1740- *pRange = castRange;
1741- return true ;
1742- }
1743- }
1744- return false ;
1745-
1746- default :
1747- return false ;
1748- }
1749-
1750- if (varTypeIsSmall (sourceType))
1751- {
1752- *pRange = IntegralRange::ForType (sourceType);
1753- return true ;
1754- }
1755-
1756- return false ;
1757- }
1758-
17591757/* ****************************************************************************
17601758 *
17611759 * If tree is a constant node holding an integral value, retrieve the value in
0 commit comments