@@ -251,7 +251,7 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree*
251
251
{
252
252
JITDUMP (" Looking for array size assertions for: " FMT_VN " \n " , arrLenVn);
253
253
Range arrLength = Range (Limit (Limit::keDependent));
254
- MergeEdgeAssertions (arrLenVn, block->bbAssertionIn , &arrLength);
254
+ MergeEdgeAssertions (m_pCompiler, arrLenVn, arrLenVn, block->bbAssertionIn , &arrLength);
255
255
if (arrLength.lLimit .IsConstant ())
256
256
{
257
257
arrSize = arrLength.lLimit .GetConstant ();
@@ -640,20 +640,28 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
640
640
641
641
LclSsaVarDsc* ssaData = m_pCompiler->lvaGetDesc (lcl)->GetPerSsaData (lcl->GetSsaNum ());
642
642
ValueNum normalLclVN = m_pCompiler->vnStore ->VNConservativeNormalValue (ssaData->m_vnPair );
643
- MergeEdgeAssertions (normalLclVN, assertions, pRange);
643
+ ValueNum arrLenVN = m_pCompiler->vnStore ->VNConservativeNormalValue (m_pCurBndsChk->GetArrayLength ()->gtVNPair );
644
+ MergeEdgeAssertions (m_pCompiler, normalLclVN, arrLenVN, assertions, pRange);
644
645
}
645
646
646
647
// ------------------------------------------------------------------------
647
648
// MergeEdgeAssertions: Merge assertions on the edge flowing into the block about a variable
648
649
//
649
650
// Arguments:
650
- // normalLclVN - the value number to look for assertions for
651
- // assertions - the assertions to use
652
- // pRange - the range to tighten with assertions
651
+ // comp - the compiler instance
652
+ // normalLclVN - the value number to look for assertions for
653
+ // preferredBoundVN - when this VN is set, it will be given preference over constant limits
654
+ // assertions - the assertions to use
655
+ // pRange - the range to tighten with assertions
653
656
//
654
- void RangeCheck::MergeEdgeAssertions (ValueNum normalLclVN, ASSERT_VALARG_TP assertions, Range* pRange)
657
+ void RangeCheck::MergeEdgeAssertions (Compiler* comp,
658
+ ValueNum normalLclVN,
659
+ ValueNum preferredBoundVN,
660
+ ASSERT_VALARG_TP assertions,
661
+ Range* pRange,
662
+ bool log)
655
663
{
656
- if (BitVecOps::IsEmpty (m_pCompiler ->apTraits , assertions))
664
+ if (BitVecOps::IsEmpty (comp ->apTraits , assertions))
657
665
{
658
666
return ;
659
667
}
@@ -663,14 +671,14 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
663
671
return ;
664
672
}
665
673
666
- // Walk through the "assertions" to check if the apply.
667
- BitVecOps::Iter iter (m_pCompiler ->apTraits , assertions);
674
+ // Walk through the "assertions" to check if they apply.
675
+ BitVecOps::Iter iter (comp ->apTraits , assertions);
668
676
unsigned index = 0 ;
669
677
while (iter.NextElem (&index ))
670
678
{
671
679
AssertionIndex assertionIndex = GetAssertionIndex (index );
672
680
673
- Compiler::AssertionDsc* curAssertion = m_pCompiler ->optGetAssertion (assertionIndex);
681
+ Compiler::AssertionDsc* curAssertion = comp ->optGetAssertion (assertionIndex);
674
682
675
683
Limit limit (Limit::keUndef);
676
684
genTreeOps cmpOper = GT_NONE;
@@ -683,7 +691,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
683
691
ValueNumStore::CompareCheckedBoundArithInfo info;
684
692
685
693
// Get i, len, cns and < as "info."
686
- m_pCompiler ->vnStore ->GetCompareCheckedBoundArithInfo (curAssertion->op1 .vn , &info);
694
+ comp ->vnStore ->GetCompareCheckedBoundArithInfo (curAssertion->op1 .vn , &info);
687
695
688
696
// If we don't have the same variable we are comparing against, bail.
689
697
if (normalLclVN != info.cmpOp )
@@ -697,12 +705,12 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
697
705
}
698
706
699
707
// If the operand that operates on the bound is not constant, then done.
700
- if (!m_pCompiler ->vnStore ->IsVNInt32Constant (info.arrOp ))
708
+ if (!comp ->vnStore ->IsVNInt32Constant (info.arrOp ))
701
709
{
702
710
continue ;
703
711
}
704
712
705
- int cons = m_pCompiler ->vnStore ->ConstantValue <int >(info.arrOp );
713
+ int cons = comp ->vnStore ->ConstantValue <int >(info.arrOp );
706
714
limit = Limit (Limit::keBinOpArray, info.vnBound , info.arrOper == GT_SUB ? -cons : cons);
707
715
cmpOper = (genTreeOps)info.cmpOper ;
708
716
}
@@ -712,7 +720,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
712
720
ValueNumStore::CompareCheckedBoundArithInfo info;
713
721
714
722
// Get the info as "i", "<" and "len"
715
- m_pCompiler ->vnStore ->GetCompareCheckedBound (curAssertion->op1 .vn , &info);
723
+ comp ->vnStore ->GetCompareCheckedBound (curAssertion->op1 .vn , &info);
716
724
717
725
// If we don't have the same variable we are comparing against, bail.
718
726
if (normalLclVN == info.cmpOp )
@@ -736,7 +744,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
736
744
ValueNumStore::ConstantBoundInfo info;
737
745
738
746
// Get the info as "i", "<" and "100"
739
- m_pCompiler ->vnStore ->GetConstantBoundInfo (curAssertion->op1 .vn , &info);
747
+ comp ->vnStore ->GetConstantBoundInfo (curAssertion->op1 .vn , &info);
740
748
741
749
// If we don't have the same variable we are comparing against, bail.
742
750
if (normalLclVN != info.cmpOpVN )
@@ -756,10 +764,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
756
764
continue ;
757
765
}
758
766
759
- int cnstLimit = m_pCompiler ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn );
767
+ int cnstLimit = comp ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn );
760
768
761
769
if ((cnstLimit == 0 ) && (curAssertion->assertionKind == Compiler::OAK_NOT_EQUAL) &&
762
- m_pCompiler ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
770
+ comp ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
763
771
{
764
772
// we have arr.Len != 0, so the length must be atleast one
765
773
limit = Limit (Limit::keConstant, 1 );
@@ -804,31 +812,31 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
804
812
805
813
// Make sure the assertion is of the form != 0 or == 0 if it isn't a constant assertion.
806
814
if (!isConstantAssertion && (curAssertion->assertionKind != Compiler::OAK_NO_THROW) &&
807
- (curAssertion->op2 .vn != m_pCompiler ->vnStore ->VNZeroForType (TYP_INT)))
815
+ (curAssertion->op2 .vn != comp ->vnStore ->VNZeroForType (TYP_INT)))
808
816
{
809
817
continue ;
810
818
}
811
819
#ifdef DEBUG
812
- if (m_pCompiler ->verbose )
820
+ if (comp ->verbose )
813
821
{
814
- m_pCompiler ->optPrintAssertion (curAssertion, assertionIndex);
822
+ comp ->optPrintAssertion (curAssertion, assertionIndex);
815
823
}
816
824
#endif
817
825
818
826
// Limits are sometimes made with the form vn + constant, where vn is a known constant
819
827
// see if we can simplify this to just a constant
820
- if (limit.IsBinOpArray () && m_pCompiler ->vnStore ->IsVNInt32Constant (limit.vn ))
828
+ if (limit.IsBinOpArray () && comp ->vnStore ->IsVNInt32Constant (limit.vn ))
821
829
{
822
- Limit tempLimit = Limit (Limit::keConstant, m_pCompiler ->vnStore ->ConstantValue <int >(limit.vn ));
830
+ Limit tempLimit = Limit (Limit::keConstant, comp ->vnStore ->ConstantValue <int >(limit.vn ));
823
831
if (tempLimit.AddConstant (limit.cns ))
824
832
{
825
833
limit = tempLimit;
826
834
}
827
835
}
828
836
829
- ValueNum arrLenVN = m_pCompiler-> vnStore -> VNConservativeNormalValue (m_pCurBndsChk-> GetArrayLength ()-> gtVNPair ) ;
837
+ ValueNum arrLenVN = preferredBoundVN ;
830
838
831
- if (m_pCompiler ->vnStore ->IsVNConstant (arrLenVN))
839
+ if (comp ->vnStore ->IsVNConstant (arrLenVN))
832
840
{
833
841
// Set arrLenVN to NoVN; this will make it match the "vn" recorded on
834
842
// constant limits (where we explicitly track the constant and don't
@@ -917,7 +925,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
917
925
918
926
if (limit.vn != arrLenVN)
919
927
{
920
- JITDUMP (" Array length VN did not match arrLen=" FMT_VN " , limit=" FMT_VN " \n " , arrLenVN, limit.vn );
928
+ if (log )
929
+ {
930
+ JITDUMP (" Array length VN did not match arrLen=" FMT_VN " , limit=" FMT_VN " \n " , arrLenVN, limit.vn );
931
+ }
921
932
continue ;
922
933
}
923
934
@@ -927,7 +938,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
927
938
// Incoming limit doesn't tighten the existing upper limit.
928
939
if (limCns >= curCns)
929
940
{
930
- JITDUMP (" Bound limit %d doesn't tighten current bound %d\n " , limCns, curCns);
941
+ if (log )
942
+ {
943
+ JITDUMP (" Bound limit %d doesn't tighten current bound %d\n " , limCns, curCns);
944
+ }
931
945
continue ;
932
946
}
933
947
}
@@ -954,8 +968,12 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
954
968
955
969
case GT_GT:
956
970
case GT_GE:
957
- pRange->lLimit = limit;
958
- // it doesn't matter if it's isUnsigned or not here - it's not negative anyway.
971
+ // GT/GE being unsigned creates a non-contiguous range which we can't represent
972
+ // using single Range object.
973
+ if (!isUnsigned)
974
+ {
975
+ pRange->lLimit = limit;
976
+ }
959
977
break ;
960
978
961
979
case GT_EQ:
@@ -967,9 +985,13 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
967
985
// All other 'cmpOper' kinds leave lLimit/uLimit unchanged
968
986
break ;
969
987
}
970
- JITDUMP (" The range after edge merging:" );
971
- JITDUMP (pRange->ToString (m_pCompiler));
972
- JITDUMP (" \n " );
988
+
989
+ if (log )
990
+ {
991
+ JITDUMP (" The range after edge merging:" );
992
+ JITDUMP (pRange->ToString (comp));
993
+ JITDUMP (" \n " );
994
+ }
973
995
}
974
996
}
975
997
0 commit comments