@@ -590,12 +590,19 @@ void Compiler::optAssertionInit(bool isLocalProp)
590
590
//
591
591
optAssertionDep =
592
592
new (this , CMK_AssertionProp) JitExpandArray<ASSERT_TP>(getAllocator (CMK_AssertionProp), max (1 , lvaCount));
593
+
594
+ if (optCrossBlockLocalAssertionProp)
595
+ {
596
+ optComplementaryAssertionMap = new (this , CMK_AssertionProp)
597
+ AssertionIndex[optMaxAssertionCount + 1 ](); // zero-inited (NO_ASSERTION_INDEX)
598
+ }
593
599
}
594
600
else
595
601
{
596
602
// General assertion prop.
597
603
//
598
- optLocalAssertionProp = false ;
604
+ optLocalAssertionProp = false ;
605
+ optCrossBlockLocalAssertionProp = false ;
599
606
600
607
// Use a function countFunc to determine a proper maximum assertion count for the
601
608
// method being compiled. The function is linear to the IL size for small and
@@ -615,7 +622,6 @@ void Compiler::optAssertionInit(bool isLocalProp)
615
622
}
616
623
617
624
optAssertionTabPrivate = new (this , CMK_AssertionProp) AssertionDsc[optMaxAssertionCount];
618
-
619
625
optAssertionTraitsInit (optMaxAssertionCount);
620
626
621
627
optAssertionCount = 0 ;
@@ -1641,7 +1647,8 @@ AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
1641
1647
//
1642
1648
if (optLocalAssertionProp)
1643
1649
{
1644
- assert (newAssertion->op1 .kind == O1K_LCLVAR);
1650
+ assert ((newAssertion->op1 .kind == O1K_LCLVAR) || (newAssertion->op1 .kind == O1K_SUBTYPE) ||
1651
+ (newAssertion->op1 .kind == O1K_EXACT_TYPE));
1645
1652
1646
1653
unsigned lclNum = newAssertion->op1 .lcl .lclNum ;
1647
1654
BitVecOps::Iter iter (apTraits, GetAssertionDep (lclNum));
@@ -1702,7 +1709,8 @@ AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
1702
1709
// Assertion mask bits are [index + 1].
1703
1710
if (optLocalAssertionProp)
1704
1711
{
1705
- assert (newAssertion->op1 .kind == O1K_LCLVAR);
1712
+ assert ((newAssertion->op1 .kind == O1K_LCLVAR) || (newAssertion->op1 .kind == O1K_SUBTYPE) ||
1713
+ (newAssertion->op1 .kind == O1K_EXACT_TYPE));
1706
1714
1707
1715
// Mark the variables this index depends on
1708
1716
unsigned lclNum = newAssertion->op1 .lcl .lclNum ;
@@ -1971,6 +1979,13 @@ AssertionIndex Compiler::optCreateJtrueAssertions(GenTree* op1
1971
1979
1972
1980
AssertionInfo Compiler::optCreateJTrueBoundsAssertion (GenTree* tree)
1973
1981
{
1982
+ // These assertions are VN based, so not relevant for local prop
1983
+ //
1984
+ if (optLocalAssertionProp)
1985
+ {
1986
+ return NO_ASSERTION_INDEX;
1987
+ }
1988
+
1974
1989
GenTree* relop = tree->gtGetOp1 ();
1975
1990
if (!relop->OperIsCompare ())
1976
1991
{
@@ -2138,13 +2153,7 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
2138
2153
*/
2139
2154
AssertionInfo Compiler::optAssertionGenJtrue (GenTree* tree)
2140
2155
{
2141
- // Only create assertions for JTRUE when we are in the global phase
2142
- if (optLocalAssertionProp)
2143
- {
2144
- return NO_ASSERTION_INDEX;
2145
- }
2146
-
2147
- GenTree* relop = tree->AsOp ()->gtOp1 ;
2156
+ GenTree* const relop = tree->AsOp ()->gtOp1 ;
2148
2157
if (!relop->OperIsCompare ())
2149
2158
{
2150
2159
return NO_ASSERTION_INDEX;
@@ -2158,6 +2167,11 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
2158
2167
return info;
2159
2168
}
2160
2169
2170
+ if (optLocalAssertionProp && !optCrossBlockLocalAssertionProp)
2171
+ {
2172
+ return NO_ASSERTION_INDEX;
2173
+ }
2174
+
2161
2175
// Find assertion kind.
2162
2176
switch (relop->gtOper )
2163
2177
{
@@ -2185,53 +2199,57 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
2185
2199
std::swap (op1, op2);
2186
2200
}
2187
2201
2188
- ValueNum op1VN = vnStore->VNConservativeNormalValue (op1->gtVNPair );
2189
- ValueNum op2VN = vnStore->VNConservativeNormalValue (op2->gtVNPair );
2190
2202
// If op1 is lcl and op2 is const or lcl, create assertion.
2191
2203
if ((op1->gtOper == GT_LCL_VAR) && (op2->OperIsConst () || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483
2192
2204
{
2193
2205
return optCreateJtrueAssertions (op1, op2, assertionKind);
2194
2206
}
2195
- else if (vnStore-> IsVNCheckedBound (op1VN) && vnStore-> IsVNInt32Constant (op2VN) )
2207
+ else if (!optLocalAssertionProp )
2196
2208
{
2197
- assert (relop->OperIs (GT_EQ, GT_NE));
2209
+ ValueNum op1VN = vnStore->VNConservativeNormalValue (op1->gtVNPair );
2210
+ ValueNum op2VN = vnStore->VNConservativeNormalValue (op2->gtVNPair );
2198
2211
2199
- int con = vnStore->ConstantValue <int >(op2VN);
2200
- if (con >= 0 )
2212
+ if (vnStore->IsVNCheckedBound (op1VN) && vnStore->IsVNInt32Constant (op2VN))
2201
2213
{
2202
- AssertionDsc dsc ;
2214
+ assert (relop-> OperIs (GT_EQ, GT_NE)) ;
2203
2215
2204
- // For arr.Length != 0, we know that 0 is a valid index
2205
- // For arr.Length == con, we know that con - 1 is the greatest valid index
2206
- if (con == 0 )
2216
+ int con = vnStore->ConstantValue <int >(op2VN);
2217
+ if (con >= 0 )
2207
2218
{
2208
- dsc.assertionKind = OAK_NOT_EQUAL;
2209
- dsc.op1 .bnd .vnIdx = vnStore->VNForIntCon (0 );
2210
- }
2211
- else
2212
- {
2213
- dsc.assertionKind = OAK_EQUAL;
2214
- dsc.op1 .bnd .vnIdx = vnStore->VNForIntCon (con - 1 );
2215
- }
2219
+ AssertionDsc dsc;
2216
2220
2217
- dsc.op1 .vn = op1VN;
2218
- dsc.op1 .kind = O1K_ARR_BND;
2219
- dsc.op1 .bnd .vnLen = op1VN;
2220
- dsc.op2 .vn = vnStore->VNConservativeNormalValue (op2->gtVNPair );
2221
- dsc.op2 .kind = O2K_CONST_INT;
2222
- dsc.op2 .u1 .iconVal = 0 ;
2223
- dsc.op2 .SetIconFlag (GTF_EMPTY);
2224
-
2225
- // when con is not zero, create an assertion on the arr.Length == con edge
2226
- // when con is zero, create an assertion on the arr.Length != 0 edge
2227
- AssertionIndex index = optAddAssertion (&dsc);
2228
- if (relop->OperIs (GT_NE) != (con == 0 ))
2229
- {
2230
- return AssertionInfo::ForNextEdge (index );
2231
- }
2232
- else
2233
- {
2234
- return index ;
2221
+ // For arr.Length != 0, we know that 0 is a valid index
2222
+ // For arr.Length == con, we know that con - 1 is the greatest valid index
2223
+ if (con == 0 )
2224
+ {
2225
+ dsc.assertionKind = OAK_NOT_EQUAL;
2226
+ dsc.op1 .bnd .vnIdx = vnStore->VNForIntCon (0 );
2227
+ }
2228
+ else
2229
+ {
2230
+ dsc.assertionKind = OAK_EQUAL;
2231
+ dsc.op1 .bnd .vnIdx = vnStore->VNForIntCon (con - 1 );
2232
+ }
2233
+
2234
+ dsc.op1 .vn = op1VN;
2235
+ dsc.op1 .kind = O1K_ARR_BND;
2236
+ dsc.op1 .bnd .vnLen = op1VN;
2237
+ dsc.op2 .vn = vnStore->VNConservativeNormalValue (op2->gtVNPair );
2238
+ dsc.op2 .kind = O2K_CONST_INT;
2239
+ dsc.op2 .u1 .iconVal = 0 ;
2240
+ dsc.op2 .SetIconFlag (GTF_EMPTY);
2241
+
2242
+ // when con is not zero, create an assertion on the arr.Length == con edge
2243
+ // when con is zero, create an assertion on the arr.Length != 0 edge
2244
+ AssertionIndex index = optAddAssertion (&dsc);
2245
+ if (relop->OperIs (GT_NE) != (con == 0 ))
2246
+ {
2247
+ return AssertionInfo::ForNextEdge (index );
2248
+ }
2249
+ else
2250
+ {
2251
+ return index ;
2252
+ }
2235
2253
}
2236
2254
}
2237
2255
}
@@ -2260,7 +2278,7 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
2260
2278
return NO_ASSERTION_INDEX;
2261
2279
}
2262
2280
2263
- GenTreeCall* call = op1->AsCall ();
2281
+ GenTreeCall* const call = op1->AsCall ();
2264
2282
2265
2283
// Note CORINFO_HELP_READYTORUN_ISINSTANCEOF does not have the same argument pattern.
2266
2284
// In particular, it is not possible to deduce what class is being tested from its args.
0 commit comments