@@ -6986,6 +6986,7 @@ void Compiler::pickGDV(GenTreeCall* call,
69866986 const int maxLikelyMethods = MAX_GDV_TYPE_CHECKS;
69876987 LikelyClassMethodRecord likelyMethods[maxLikelyMethods];
69886988 unsigned numberOfMethods = 0 ;
6989+ bool isInferredGDV = false ;
69896990
69906991 // TODO-GDV: R2R support requires additional work to reacquire the
69916992 // entrypoint, similar to what happens at the end of impDevirtualizeCall.
@@ -7000,6 +7001,39 @@ void Compiler::pickGDV(GenTreeCall* call,
70007001 pgoInfo.PgoData , ilOffset);
70017002 }
70027003
7004+ if ((numberOfClasses < 1 ) && (numberOfMethods < 1 ) && hasEnumeratorLikelyTypeMap ())
7005+ {
7006+ // See if we can infer a GDV here for enumerator var uses
7007+ //
7008+ CallArg* const thisArg = call->gtArgs .FindWellKnownArg (WellKnownArg::ThisPointer);
7009+
7010+ if (thisArg != nullptr )
7011+ {
7012+ GenTree* const thisNode = thisArg->GetEarlyNode ();
7013+ if (thisNode->OperIs (GT_LCL_VAR))
7014+ {
7015+ GenTreeLclVarCommon* thisLclNode = thisNode->AsLclVarCommon ();
7016+ LclVarDsc* const thisVarDsc = lvaGetDesc (thisLclNode);
7017+ unsigned const thisLclNum = thisLclNode->GetLclNum ();
7018+
7019+ if (thisVarDsc->lvIsEnumerator )
7020+ {
7021+ VarToLikelyClassMap* const map = getImpEnumeratorLikelyTypeMap ();
7022+ InferredGdvEntry e;
7023+ if (map->Lookup (thisLclNum, &e))
7024+ {
7025+ JITDUMP (" Recalling that V%02u has %u%% likely class %s\n " , thisLclNum, e.m_likelihood ,
7026+ eeGetClassName (e.m_classHandle ));
7027+ numberOfClasses = 1 ;
7028+ likelyClasses[0 ].handle = (INT_PTR)e.m_classHandle ;
7029+ likelyClasses[0 ].likelihood = e.m_likelihood ;
7030+ isInferredGDV = true ;
7031+ }
7032+ }
7033+ }
7034+ }
7035+ }
7036+
70037037 if ((numberOfClasses < 1 ) && (numberOfMethods < 1 ))
70047038 {
70057039 if (verboseLogging)
@@ -7186,6 +7220,58 @@ void Compiler::pickGDV(GenTreeCall* call,
71867220 JITDUMP (" Accepting type %s with likelihood %u as a candidate\n " ,
71877221 eeGetClassName (classGuesses[guessIdx]), likelihoods[guessIdx])
71887222 }
7223+
7224+ // If the 'this' arg to the call is an enumerator var, record any
7225+ // dominant likely class so we can possibly infer a GDV at places where we
7226+ // never observed the var's value. (eg an unreached Dispose call if
7227+ // control is hijacked out of Tier0+i by OSR).
7228+ //
7229+ // Note enumerator vars are special as they are generally not redefined
7230+ // and we want to ensure all methods called on them get inlined to enable
7231+ // escape analysis to kick in, if possible.
7232+ //
7233+ const unsigned dominantLikelihood = 50 ;
7234+
7235+ if (!isInferredGDV && (likelihoods[guessIdx] >= dominantLikelihood))
7236+ {
7237+ CallArg* const thisArg = call->gtArgs .FindWellKnownArg (WellKnownArg::ThisPointer);
7238+
7239+ if (thisArg != nullptr )
7240+ {
7241+ GenTree* const thisNode = thisArg->GetEarlyNode ();
7242+ if (thisNode->OperIs (GT_LCL_VAR))
7243+ {
7244+ GenTreeLclVarCommon* thisLclNode = thisNode->AsLclVarCommon ();
7245+ LclVarDsc* const thisVarDsc = lvaGetDesc (thisLclNode);
7246+ unsigned const thisLclNum = thisLclNode->GetLclNum ();
7247+
7248+ if (thisVarDsc->lvIsEnumerator )
7249+ {
7250+ VarToLikelyClassMap* const map = getImpEnumeratorLikelyTypeMap ();
7251+
7252+ // If we have multiple type observations, we just use the first.
7253+ //
7254+ // Note importation order is somewhat reverse-post-orderish;
7255+ // a block is only imported if one of its imported preds is imported.
7256+ //
7257+ // Enumerator vars tend to have a dominating MoveNext call that will
7258+ // be the one subsequent uses will see, if they lack their own
7259+ // type observations.
7260+ //
7261+ if (!map->Lookup (thisLclNum))
7262+ {
7263+ InferredGdvEntry e;
7264+ e.m_classHandle = classGuesses[guessIdx];
7265+ e.m_likelihood = likelihoods[guessIdx];
7266+
7267+ JITDUMP (" Remembering that V%02u has %u%% likely class %s\n " , thisLclNum,
7268+ e.m_likelihood , eeGetClassName (e.m_classHandle ));
7269+ map->Set (thisLclNum, e);
7270+ }
7271+ }
7272+ }
7273+ }
7274+ }
71897275 }
71907276 else
71917277 {
0 commit comments