@@ -251,7 +251,7 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree*
251251 {
252252 JITDUMP (" Looking for array size assertions for: " FMT_VN " \n " , arrLenVn);
253253 Range arrLength = Range (Limit (Limit::keDependent));
254- MergeEdgeAssertions (arrLenVn, block->bbAssertionIn , &arrLength);
254+ MergeEdgeAssertions (m_pCompiler, arrLenVn, arrLenVn, block->bbAssertionIn , &arrLength);
255255 if (arrLength.lLimit .IsConstant ())
256256 {
257257 arrSize = arrLength.lLimit .GetConstant ();
@@ -640,20 +640,28 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
640640
641641 LclSsaVarDsc* ssaData = m_pCompiler->lvaGetDesc (lcl)->GetPerSsaData (lcl->GetSsaNum ());
642642 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);
644645}
645646
646647// ------------------------------------------------------------------------
647648// MergeEdgeAssertions: Merge assertions on the edge flowing into the block about a variable
648649//
649650// 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
653656//
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)
655663{
656- if (BitVecOps::IsEmpty (m_pCompiler ->apTraits , assertions))
664+ if (BitVecOps::IsEmpty (comp ->apTraits , assertions))
657665 {
658666 return ;
659667 }
@@ -663,14 +671,14 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
663671 return ;
664672 }
665673
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);
668676 unsigned index = 0 ;
669677 while (iter.NextElem (&index))
670678 {
671679 AssertionIndex assertionIndex = GetAssertionIndex (index);
672680
673- Compiler::AssertionDsc* curAssertion = m_pCompiler ->optGetAssertion (assertionIndex);
681+ Compiler::AssertionDsc* curAssertion = comp ->optGetAssertion (assertionIndex);
674682
675683 Limit limit (Limit::keUndef);
676684 genTreeOps cmpOper = GT_NONE;
@@ -683,7 +691,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
683691 ValueNumStore::CompareCheckedBoundArithInfo info;
684692
685693 // Get i, len, cns and < as "info."
686- m_pCompiler ->vnStore ->GetCompareCheckedBoundArithInfo (curAssertion->op1 .vn , &info);
694+ comp ->vnStore ->GetCompareCheckedBoundArithInfo (curAssertion->op1 .vn , &info);
687695
688696 // If we don't have the same variable we are comparing against, bail.
689697 if (normalLclVN != info.cmpOp )
@@ -697,12 +705,12 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
697705 }
698706
699707 // 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 ))
701709 {
702710 continue ;
703711 }
704712
705- int cons = m_pCompiler ->vnStore ->ConstantValue <int >(info.arrOp );
713+ int cons = comp ->vnStore ->ConstantValue <int >(info.arrOp );
706714 limit = Limit (Limit::keBinOpArray, info.vnBound , info.arrOper == GT_SUB ? -cons : cons);
707715 cmpOper = (genTreeOps)info.cmpOper ;
708716 }
@@ -712,7 +720,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
712720 ValueNumStore::CompareCheckedBoundArithInfo info;
713721
714722 // Get the info as "i", "<" and "len"
715- m_pCompiler ->vnStore ->GetCompareCheckedBound (curAssertion->op1 .vn , &info);
723+ comp ->vnStore ->GetCompareCheckedBound (curAssertion->op1 .vn , &info);
716724
717725 // If we don't have the same variable we are comparing against, bail.
718726 if (normalLclVN == info.cmpOp )
@@ -736,7 +744,7 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
736744 ValueNumStore::ConstantBoundInfo info;
737745
738746 // Get the info as "i", "<" and "100"
739- m_pCompiler ->vnStore ->GetConstantBoundInfo (curAssertion->op1 .vn , &info);
747+ comp ->vnStore ->GetConstantBoundInfo (curAssertion->op1 .vn , &info);
740748
741749 // If we don't have the same variable we are comparing against, bail.
742750 if (normalLclVN != info.cmpOpVN )
@@ -756,10 +764,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
756764 continue ;
757765 }
758766
759- int cnstLimit = m_pCompiler ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn );
767+ int cnstLimit = comp ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn );
760768
761769 if ((cnstLimit == 0 ) && (curAssertion->assertionKind == Compiler::OAK_NOT_EQUAL) &&
762- m_pCompiler ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
770+ comp ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
763771 {
764772 // we have arr.Len != 0, so the length must be atleast one
765773 limit = Limit (Limit::keConstant, 1 );
@@ -804,31 +812,31 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
804812
805813 // Make sure the assertion is of the form != 0 or == 0 if it isn't a constant assertion.
806814 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)))
808816 {
809817 continue ;
810818 }
811819#ifdef DEBUG
812- if (m_pCompiler ->verbose )
820+ if (comp ->verbose )
813821 {
814- m_pCompiler ->optPrintAssertion (curAssertion, assertionIndex);
822+ comp ->optPrintAssertion (curAssertion, assertionIndex);
815823 }
816824#endif
817825
818826 // Limits are sometimes made with the form vn + constant, where vn is a known constant
819827 // 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 ))
821829 {
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 ));
823831 if (tempLimit.AddConstant (limit.cns ))
824832 {
825833 limit = tempLimit;
826834 }
827835 }
828836
829- ValueNum arrLenVN = m_pCompiler-> vnStore -> VNConservativeNormalValue (m_pCurBndsChk-> GetArrayLength ()-> gtVNPair ) ;
837+ ValueNum arrLenVN = preferredBoundVN ;
830838
831- if (m_pCompiler ->vnStore ->IsVNConstant (arrLenVN))
839+ if (comp ->vnStore ->IsVNConstant (arrLenVN))
832840 {
833841 // Set arrLenVN to NoVN; this will make it match the "vn" recorded on
834842 // constant limits (where we explicitly track the constant and don't
@@ -917,7 +925,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
917925
918926 if (limit.vn != arrLenVN)
919927 {
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+ }
921932 continue ;
922933 }
923934
@@ -927,7 +938,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
927938 // Incoming limit doesn't tighten the existing upper limit.
928939 if (limCns >= curCns)
929940 {
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+ }
931945 continue ;
932946 }
933947 }
@@ -954,8 +968,12 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
954968
955969 case GT_GT:
956970 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+ }
959977 break ;
960978
961979 case GT_EQ:
@@ -967,9 +985,13 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
967985 // All other 'cmpOper' kinds leave lLimit/uLimit unchanged
968986 break ;
969987 }
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+ }
973995 }
974996}
975997
0 commit comments