@@ -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 )
@@ -757,10 +765,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
757765 }
758766
759767 int cnstLimit = (int )curAssertion->op2 .u1 .iconVal ;
760- assert (cnstLimit == m_pCompiler ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn ));
768+ assert (cnstLimit == comp ->vnStore ->CoercedConstantValue <int >(curAssertion->op2 .vn ));
761769
762770 if ((cnstLimit == 0 ) && (curAssertion->assertionKind == Compiler::OAK_NOT_EQUAL) &&
763- m_pCompiler ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
771+ comp ->vnStore ->IsVNCheckedBound (curAssertion->op1 .vn ))
764772 {
765773 // we have arr.Len != 0, so the length must be atleast one
766774 limit = Limit (Limit::keConstant, 1 );
@@ -805,31 +813,31 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
805813
806814 // Make sure the assertion is of the form != 0 or == 0 if it isn't a constant assertion.
807815 if (!isConstantAssertion && (curAssertion->assertionKind != Compiler::OAK_NO_THROW) &&
808- (curAssertion->op2 .vn != m_pCompiler ->vnStore ->VNZeroForType (TYP_INT)))
816+ (curAssertion->op2 .vn != comp ->vnStore ->VNZeroForType (TYP_INT)))
809817 {
810818 continue ;
811819 }
812820#ifdef DEBUG
813- if (m_pCompiler ->verbose )
821+ if (comp ->verbose )
814822 {
815- m_pCompiler ->optPrintAssertion (curAssertion, assertionIndex);
823+ comp ->optPrintAssertion (curAssertion, assertionIndex);
816824 }
817825#endif
818826
819827 // Limits are sometimes made with the form vn + constant, where vn is a known constant
820828 // see if we can simplify this to just a constant
821- if (limit.IsBinOpArray () && m_pCompiler ->vnStore ->IsVNInt32Constant (limit.vn ))
829+ if (limit.IsBinOpArray () && comp ->vnStore ->IsVNInt32Constant (limit.vn ))
822830 {
823- Limit tempLimit = Limit (Limit::keConstant, m_pCompiler ->vnStore ->ConstantValue <int >(limit.vn ));
831+ Limit tempLimit = Limit (Limit::keConstant, comp ->vnStore ->ConstantValue <int >(limit.vn ));
824832 if (tempLimit.AddConstant (limit.cns ))
825833 {
826834 limit = tempLimit;
827835 }
828836 }
829837
830- ValueNum arrLenVN = m_pCompiler-> vnStore -> VNConservativeNormalValue (m_pCurBndsChk-> GetArrayLength ()-> gtVNPair ) ;
838+ ValueNum arrLenVN = preferredBoundVN ;
831839
832- if (m_pCompiler ->vnStore ->IsVNConstant (arrLenVN))
840+ if (comp ->vnStore ->IsVNConstant (arrLenVN))
833841 {
834842 // Set arrLenVN to NoVN; this will make it match the "vn" recorded on
835843 // constant limits (where we explicitly track the constant and don't
@@ -918,7 +926,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
918926
919927 if (limit.vn != arrLenVN)
920928 {
921- JITDUMP (" Array length VN did not match arrLen=" FMT_VN " , limit=" FMT_VN " \n " , arrLenVN, limit.vn );
929+ if (log)
930+ {
931+ JITDUMP (" Array length VN did not match arrLen=" FMT_VN " , limit=" FMT_VN " \n " , arrLenVN, limit.vn );
932+ }
922933 continue ;
923934 }
924935
@@ -928,7 +939,10 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
928939 // Incoming limit doesn't tighten the existing upper limit.
929940 if (limCns >= curCns)
930941 {
931- JITDUMP (" Bound limit %d doesn't tighten current bound %d\n " , limCns, curCns);
942+ if (log)
943+ {
944+ JITDUMP (" Bound limit %d doesn't tighten current bound %d\n " , limCns, curCns);
945+ }
932946 continue ;
933947 }
934948 }
@@ -955,8 +969,12 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
955969
956970 case GT_GT:
957971 case GT_GE:
958- pRange->lLimit = limit;
959- // it doesn't matter if it's isUnsigned or not here - it's not negative anyway.
972+ // GT/GE being unsigned creates a non-contiguous range which we can't represent
973+ // using single Range object.
974+ if (!isUnsigned)
975+ {
976+ pRange->lLimit = limit;
977+ }
960978 break ;
961979
962980 case GT_EQ:
@@ -968,9 +986,13 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
968986 // All other 'cmpOper' kinds leave lLimit/uLimit unchanged
969987 break ;
970988 }
971- JITDUMP (" The range after edge merging:" );
972- JITDUMP (pRange->ToString (m_pCompiler));
973- JITDUMP (" \n " );
989+
990+ if (log)
991+ {
992+ JITDUMP (" The range after edge merging:" );
993+ JITDUMP (pRange->ToString (comp));
994+ JITDUMP (" \n " );
995+ }
974996 }
975997}
976998
0 commit comments