Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rely on PGO for isinst/castclass #65922

Merged
merged 9 commits into from
Apr 1, 2022
Merged
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4597,7 +4597,7 @@ class Compiler
CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);

bool impIsCastHelperEligibleForClassProbe(GenTree* tree);
bool impIsCastHelperMayHaveProfileData(GenTree* tree);
bool impIsCastHelperMayHaveProfileData(CorInfoHelpFunc helper);

GenTree* impCastClassOrIsInstToTree(
GenTree* op1, GenTree* op2, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass, IL_OFFSET ilOffset);
Expand Down
56 changes: 44 additions & 12 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2141,21 +2141,17 @@ bool Compiler::impIsCastHelperEligibleForClassProbe(GenTree* tree)
// Returns:
// true if the tree is a cast helper with potential profile data
//
bool Compiler::impIsCastHelperMayHaveProfileData(GenTree* tree)
bool Compiler::impIsCastHelperMayHaveProfileData(CorInfoHelpFunc helper)
{
if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) || (JitConfig.JitCastProfiling() != 1))
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT))
{
return false;
}

if (tree->IsCall() && tree->AsCall()->gtCallType == CT_HELPER)
if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS) ||
(helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTINTERFACE))
{
const CorInfoHelpFunc helper = eeGetHelperNum(tree->AsCall()->gtCallMethHnd);
if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS) ||
(helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTINTERFACE))
{
return true;
}
return true;
}
return false;
}
Expand Down Expand Up @@ -11561,8 +11557,11 @@ GenTree* Compiler::impCastClassOrIsInstToTree(

// Pessimistically assume the jit cannot expand this as an inline test
bool canExpandInline = false;
bool partialExpand = false;
const CorInfoHelpFunc helper = info.compCompHnd->getCastingHelper(pResolvedToken, isCastClass);

GenTree* exactCls = nullptr;

// Legality check.
//
// Not all classclass/isinst operations can be inline expanded.
Expand All @@ -11582,6 +11581,34 @@ GenTree* Compiler::impCastClassOrIsInstToTree(
canExpandInline = impIsClassExact(pResolvedToken->hClass);
}
}

// Check if this cast helper have some profile data
if (impIsCastHelperMayHaveProfileData(helper))
{
LikelyClassRecord likelyClass[1]; // multiple guesses aren't yet supported
if (getLikelyClasses(likelyClass, 1, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset) > 0)
{
assert(likelyClass != nullptr);
CORINFO_CLASS_HANDLE likelyCls = likelyClass->clsHandle;

if ((likelyCls != NO_CLASS_HANDLE) &&
(likelyClass->likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood()))
{
if ((info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass) ==
TypeCompareState::Must))
{
assert((info.compCompHnd->getClassAttribs(likelyCls) &
(CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) == 0);
JITDUMP("Adding \"is %s (%X)\" check as a fast path for %s using PGO data.\n",
eeGetClassName(likelyCls), likelyCls, isCastClass ? "castclass" : "isinst");

canExpandInline = true;
partialExpand = true;
exactCls = gtNewIconEmbClsHndNode(likelyCls);
}
}
}
}
}

const bool expandInline = canExpandInline && shouldExpandInline;
Expand Down Expand Up @@ -11633,13 +11660,13 @@ GenTree* Compiler::impCastClassOrIsInstToTree(
//

GenTree* op2Var = op2;
if (isCastClass)
if (isCastClass && !partialExpand)
{
op2Var = fgInsertCommaFormTemp(&op2);
lvaTable[op2Var->AsLclVarCommon()->GetLclNum()].lvIsCSE = true;
}
temp = gtNewMethodTableLookup(temp);
condMT = gtNewOperNode(GT_NE, TYP_INT, temp, op2);
condMT = gtNewOperNode(GT_NE, TYP_INT, temp, exactCls != nullptr ? exactCls : op2);

GenTree* condNull;
//
Expand All @@ -11664,7 +11691,12 @@ GenTree* Compiler::impCastClassOrIsInstToTree(
//
const CorInfoHelpFunc specialHelper = CORINFO_HELP_CHKCASTCLASS_SPECIAL;

condTrue = gtNewHelperCallNode(specialHelper, TYP_REF, gtNewCallArgs(op2Var, gtClone(op1)));
condTrue =
gtNewHelperCallNode(specialHelper, TYP_REF, gtNewCallArgs(partialExpand ? op2 : op2Var, gtClone(op1)));
}
else if (partialExpand)
{
condTrue = gtNewHelperCallNode(helper, TYP_REF, gtNewCallArgs(op2, gtClone(op1)));
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ CONFIG_STRING(JitEnablePatchpointRange, W("JitEnablePatchpointRange"))
// Profile instrumentation options
CONFIG_INTEGER(JitMinimalJitProfiling, W("JitMinimalJitProfiling"), 1)
CONFIG_INTEGER(JitMinimalPrejitProfiling, W("JitMinimalPrejitProfiling"), 0)
CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 0) // Profile castclass and isinst
CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 1) // CI test, will disable it back
CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1) // Profile virtual and interface calls
CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1) // Profile edges instead of blocks
CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect counts as 64-bit values.
Expand Down