5
5
6
6
#include " jitpch.h"
7
7
#include " rangecheck.h"
8
+ #include " compiler.h"
8
9
9
10
// Max stack depth (path length) in walking the UD chain.
10
11
static const int MAX_SEARCH_DEPTH = 100 ;
@@ -60,7 +61,7 @@ int RangeCheck::GetArrLength(ValueNum vn)
60
61
}
61
62
62
63
// Check if the computed range is within bounds.
63
- bool RangeCheck::BetweenBounds (Range& range, int lower, GenTree* upper)
64
+ bool RangeCheck::BetweenBounds (Range& range, int lower, ValueNum uLimitVN, int arrSize DEBUGARG ( GenTree* upper) )
64
65
{
65
66
#ifdef DEBUG
66
67
if (m_pCompiler->verbose )
@@ -73,10 +74,8 @@ bool RangeCheck::BetweenBounds(Range& range, int lower, GenTree* upper)
73
74
74
75
ValueNumStore* vnStore = m_pCompiler->vnStore ;
75
76
76
- // Get the VN for the upper limit.
77
- ValueNum uLimitVN = vnStore->VNConservativeNormalValue (upper->gtVNPair );
78
-
79
77
#ifdef DEBUG
78
+ assert (vnStore->VNConservativeNormalValue (upper->gtVNPair ));
80
79
JITDUMP (FMT_VN " upper bound is: " , uLimitVN);
81
80
if (m_pCompiler->verbose )
82
81
{
@@ -85,26 +84,7 @@ bool RangeCheck::BetweenBounds(Range& range, int lower, GenTree* upper)
85
84
JITDUMP (" \n " );
86
85
#endif
87
86
88
- int arrSize = 0 ;
89
-
90
- if (vnStore->IsVNConstant (uLimitVN))
91
- {
92
- ssize_t constVal = -1 ;
93
- unsigned iconFlags = 0 ;
94
-
95
- if (m_pCompiler->optIsTreeKnownIntValue (true , upper, &constVal, &iconFlags))
96
- {
97
- arrSize = (int )constVal;
98
- }
99
- }
100
- else if (vnStore->IsVNArrLen (uLimitVN))
101
- {
102
- // Get the array reference from the length.
103
- ValueNum arrRefVN = vnStore->GetArrForLenVn (uLimitVN);
104
- // Check if array size can be obtained.
105
- arrSize = vnStore->GetNewArrSize (arrRefVN);
106
- }
107
- else if (!vnStore->IsVNCheckedBound (uLimitVN))
87
+ if ((arrSize <= 0 ) && !vnStore->IsVNCheckedBound (uLimitVN))
108
88
{
109
89
// If the upper limit is not length, then bail.
110
90
return false ;
@@ -231,6 +211,16 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree*
231
211
#endif // FEATURE_SIMD
232
212
{
233
213
arrSize = GetArrLength (arrLenVn);
214
+ if (arrSize <= 0 )
215
+ {
216
+ // see if there are any assertions about the array size we can use
217
+ Range arrLength = Range (Limit (Limit::keDependent));
218
+ MergeEdgeAssertions (arrLenVn, block->bbAssertionIn , &arrLength);
219
+ if (arrLength.lLimit .IsConstant ())
220
+ {
221
+ arrSize = arrLength.lLimit .GetConstant ();
222
+ }
223
+ }
234
224
}
235
225
236
226
JITDUMP (" ArrSize for lengthVN:%03X = %d\n " , arrLenVn, arrSize);
@@ -286,7 +276,7 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree*
286
276
}
287
277
288
278
// Is the range between the lower and upper bound values.
289
- if (BetweenBounds (range, 0 , bndsChk->gtArrLen ))
279
+ if (BetweenBounds (range, 0 , arrLenVn, arrSize DEBUGARG ( bndsChk->gtArrLen ) ))
290
280
{
291
281
JITDUMP (" [RangeCheck::OptimizeRangeCheck] Between bounds\n " );
292
282
m_pCompiler->optRemoveRangeCheck (treeParent, stmt);
@@ -532,7 +522,6 @@ void RangeCheck::SetDef(UINT64 hash, Location* loc)
532
522
}
533
523
#endif
534
524
535
- // Merge assertions on the edge flowing into the block about a variable.
536
525
void RangeCheck::MergeEdgeAssertions (GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP assertions, Range* pRange)
537
526
{
538
527
if (BitVecOps::IsEmpty (m_pCompiler->apTraits , assertions))
@@ -544,6 +533,20 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
544
533
{
545
534
return ;
546
535
}
536
+
537
+ LclVarDsc* varDsc = m_pCompiler->lvaGetDesc (lcl);
538
+ if (varDsc->CanBeReplacedWithItsField (m_pCompiler))
539
+ {
540
+ varDsc = m_pCompiler->lvaGetDesc (varDsc->lvFieldLclStart );
541
+ }
542
+ LclSsaVarDsc* ssaData = varDsc->GetPerSsaData (lcl->GetSsaNum ());
543
+ ValueNum normalLclVN = m_pCompiler->vnStore ->VNConservativeNormalValue (ssaData->m_vnPair );
544
+ MergeEdgeAssertions (normalLclVN, assertions, pRange);
545
+ }
546
+
547
+ // Merge assertions on the edge flowing into the block about a variable.
548
+ void RangeCheck::MergeEdgeAssertions (ValueNum normalLclVN, ASSERT_VALARG_TP assertions, Range* pRange)
549
+ {
547
550
// Walk through the "assertions" to check if the apply.
548
551
BitVecOps::Iter iter (m_pCompiler->apTraits , assertions);
549
552
unsigned index = 0 ;
@@ -556,14 +559,6 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
556
559
Limit limit (Limit::keUndef);
557
560
genTreeOps cmpOper = GT_NONE;
558
561
559
- LclVarDsc* varDsc = m_pCompiler->lvaGetDesc (lcl);
560
- if (varDsc->CanBeReplacedWithItsField (m_pCompiler))
561
- {
562
- varDsc = m_pCompiler->lvaGetDesc (varDsc->lvFieldLclStart );
563
- }
564
- LclSsaVarDsc* ssaData = varDsc->GetPerSsaData (lcl->GetSsaNum ());
565
- ValueNum normalLclVN = m_pCompiler->vnStore ->VNConservativeNormalValue (ssaData->m_vnPair );
566
-
567
562
// Current assertion is of the form (i < len - cns) != 0
568
563
if (curAssertion->IsCheckedBoundArithBound ())
569
564
{
@@ -602,13 +597,20 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
602
597
m_pCompiler->vnStore ->GetCompareCheckedBound (curAssertion->op1 .vn , &info);
603
598
604
599
// If we don't have the same variable we are comparing against, bail.
605
- if (normalLclVN != info.cmpOp )
600
+ if (normalLclVN == info.cmpOp )
601
+ {
602
+ cmpOper = (genTreeOps)info.cmpOper ;
603
+ limit = Limit (Limit::keBinOpArray, info.vnBound , 0 );
604
+ }
605
+ else if (info.vnBound == info.vnBound )
606
+ {
607
+ cmpOper = GenTree::SwapRelop ((genTreeOps)info.cmpOper );
608
+ limit = Limit (Limit::keBinOpArray, info.cmpOp , 0 );
609
+ }
610
+ else
606
611
{
607
612
continue ;
608
613
}
609
-
610
- limit = Limit (Limit::keBinOpArray, info.vnBound , 0 );
611
- cmpOper = (genTreeOps)info.cmpOper ;
612
614
}
613
615
// Current assertion is of the form (i < 100) != 0
614
616
else if (curAssertion->IsConstantBound ())
@@ -627,6 +629,11 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
627
629
limit = Limit (Limit::keConstant, info.constVal );
628
630
cmpOper = (genTreeOps)info.cmpOper ;
629
631
}
632
+ else if (IsConstantAssertion (curAssertion, normalLclVN))
633
+ {
634
+ limit = Limit (Limit::keConstant, m_pCompiler->vnStore ->ConstantValue <int >(curAssertion->op2 .vn ));
635
+ cmpOper = GT_EQ;
636
+ }
630
637
// Current assertion is not supported, ignore it
631
638
else
632
639
{
@@ -636,7 +643,8 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
636
643
assert (limit.IsBinOpArray () || limit.IsConstant ());
637
644
638
645
// Make sure the assertion is of the form != 0 or == 0.
639
- if (curAssertion->op2 .vn != m_pCompiler->vnStore ->VNZeroForType (TYP_INT))
646
+ if ((curAssertion->op2 .vn != m_pCompiler->vnStore ->VNZeroForType (TYP_INT)) &&
647
+ (cmpOper != GT_EQ))
640
648
{
641
649
continue ;
642
650
}
@@ -647,6 +655,13 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
647
655
}
648
656
#endif
649
657
658
+ // Limits are sometimes made with the form vn + constant, where vn is a known constant
659
+ // see if we can simplify this to just a constant
660
+ if (limit.IsBinOpArray () && m_pCompiler->vnStore ->IsVNInt32Constant (limit.vn ))
661
+ {
662
+ limit = Limit (Limit::keConstant, m_pCompiler->vnStore ->ConstantValue <int >(limit.vn ) + limit.cns );
663
+ }
664
+
650
665
ValueNum arrLenVN = m_pCompiler->vnStore ->VNConservativeNormalValue (m_pCurBndsChk->gtArrLen ->gtVNPair );
651
666
652
667
if (m_pCompiler->vnStore ->IsVNConstant (arrLenVN))
@@ -663,6 +678,7 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
663
678
// (i < length) != 0
664
679
// (i < 100) == 0
665
680
// (i < 100) != 0
681
+ // i == 100
666
682
//
667
683
// At this point, we have detected that op1.vn is (i < length) or (i < length + cns) or
668
684
// (i < 100) and the op2.vn is 0.
@@ -673,12 +689,12 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
673
689
// If we have an assertion of the form == 0 (i.e., equals false), then reverse relop.
674
690
// The relop has to be reversed because we have: (i < length) is false which is the same
675
691
// as (i >= length).
676
- if (curAssertion->assertionKind == Compiler::OAK_EQUAL)
692
+ if (( curAssertion->assertionKind == Compiler::OAK_EQUAL) && (cmpOper != GT_EQ) )
677
693
{
678
694
cmpOper = GenTree::ReverseRelop (cmpOper);
679
695
}
680
696
681
- // Bounds are inclusive, so add -1 for upper bound when "<". But make sure we won't overflow .
697
+ // Bounds are inclusive, so add -1 for upper bound when "<". But make sure we won't underflow .
682
698
if (cmpOper == GT_LT && !limit.AddConstant (-1 ))
683
699
{
684
700
continue ;
@@ -744,6 +760,10 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
744
760
pRange->lLimit = limit;
745
761
break ;
746
762
763
+ case GT_EQ:
764
+ pRange->uLimit = limit;
765
+ pRange->lLimit = limit;
766
+
747
767
default :
748
768
// All other 'cmpOper' kinds leave lLimit/uLimit unchanged
749
769
break ;
0 commit comments