summaryrefslogtreecommitdiff
path: root/src/jit/inlinepolicy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/inlinepolicy.cpp')
-rw-r--r--src/jit/inlinepolicy.cpp232
1 files changed, 111 insertions, 121 deletions
diff --git a/src/jit/inlinepolicy.cpp b/src/jit/inlinepolicy.cpp
index f80f3a5ec0..61e70c3ed4 100644
--- a/src/jit/inlinepolicy.cpp
+++ b/src/jit/inlinepolicy.cpp
@@ -27,22 +27,22 @@
InlinePolicy* InlinePolicy::GetPolicy(Compiler* compiler, bool isPrejitRoot)
{
-#ifdef DEBUG
+#if defined(DEBUG) || defined(INLINE_DATA)
- // Optionally install the RandomPolicy.
- bool useRandomPolicy = compiler->compRandomInlineStress();
+#if defined(DEBUG)
+ const bool useRandomPolicyForStress = compiler->compRandomInlineStress();
+#else
+ const bool useRandomPolicyForStress = false;
+#endif // defined(DEBUG)
+
+ const bool useRandomPolicy = (JitConfig.JitInlinePolicyRandom() != 0);
- if (useRandomPolicy)
+ // Optionally install the RandomPolicy.
+ if (useRandomPolicyForStress || useRandomPolicy)
{
- unsigned seed = getJitStressLevel();
- assert(seed != 0);
- return new (compiler, CMK_Inlining) RandomPolicy(compiler, isPrejitRoot, seed);
+ return new (compiler, CMK_Inlining) RandomPolicy(compiler, isPrejitRoot);
}
-#endif // DEBUG
-
-#if defined(DEBUG) || defined(INLINE_DATA)
-
// Optionally install the ReplayPolicy.
bool useReplayPolicy = JitConfig.JitInlinePolicyReplay() != 0;
@@ -106,7 +106,7 @@ InlinePolicy* InlinePolicy::GetPolicy(Compiler* compiler, bool isPrejitRoot)
void LegalPolicy::NoteFatal(InlineObservation obs)
{
// As a safeguard, all fatal impact must be
- // reported via noteFatal.
+ // reported via NoteFatal.
assert(InlGetImpact(obs) == InlineImpact::FATAL);
NoteInternal(obs);
assert(InlDecisionIsFailure(m_Decision));
@@ -243,7 +243,7 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
InlineImpact impact = InlGetImpact(obs);
// As a safeguard, all fatal impact must be
- // reported via noteFatal.
+ // reported via NoteFatal.
assert(impact != InlineImpact::FATAL);
// Handle most information here
@@ -383,6 +383,12 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
break;
}
+ case InlineObservation::CALLEE_HAS_PINNED_LOCALS:
+ // The legacy policy is to never inline methods with
+ // pinned locals.
+ SetNever(obs);
+ break;
+
default:
// Ignore the remainder for now
break;
@@ -443,16 +449,16 @@ void LegacyPolicy::NoteInt(InlineObservation obs, int value)
// Now that we know size and forceinline state,
// update candidacy.
- if (m_CodeSize <= InlineStrategy::ALWAYS_INLINE_SIZE)
- {
- // Candidate based on small size
- SetCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE);
- }
- else if (m_IsForceInline)
+ if (m_IsForceInline)
{
// Candidate based on force inline
SetCandidate(InlineObservation::CALLEE_IS_FORCE_INLINE);
}
+ else if (m_CodeSize <= InlineStrategy::ALWAYS_INLINE_SIZE)
+ {
+ // Candidate based on small size
+ SetCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE);
+ }
else if (m_CodeSize <= m_RootCompiler->m_inlineStrategy->GetMaxInlineILSize())
{
// Candidate, pending profitability evaluation
@@ -842,11 +848,21 @@ int LegacyPolicy::CodeSizeEstimate()
// NoteBool: handle a boolean observation with non-fatal impact
//
// Arguments:
-// obs - the current obsevation
+// obs - the current observation
// value - the value of the observation
void EnhancedLegacyPolicy::NoteBool(InlineObservation obs, bool value)
{
+
+#ifdef DEBUG
+ // Check the impact
+ InlineImpact impact = InlGetImpact(obs);
+
+ // As a safeguard, all fatal impact must be
+ // reported via NoteFatal.
+ assert(impact != InlineImpact::FATAL);
+#endif // DEBUG
+
switch (obs)
{
case InlineObservation::CALLEE_DOES_NOT_RETURN:
@@ -854,6 +870,36 @@ void EnhancedLegacyPolicy::NoteBool(InlineObservation obs, bool value)
m_IsNoReturnKnown = true;
break;
+ case InlineObservation::CALLSITE_RARE_GC_STRUCT:
+ // If this is a discretionary or always inline candidate
+ // with a gc struct, we may change our mind about inlining
+ // if the call site is rare, to avoid costs associated with
+ // zeroing the GC struct up in the root prolog.
+ if (m_Observation == InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE)
+ {
+ assert(m_CallsiteFrequency == InlineCallsiteFrequency::UNUSED);
+ SetFailure(obs);
+ return;
+ }
+ else if (m_Observation == InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE)
+ {
+ assert(m_CallsiteFrequency == InlineCallsiteFrequency::RARE);
+ SetFailure(obs);
+ return;
+ }
+ break;
+
+ case InlineObservation::CALLEE_HAS_PINNED_LOCALS:
+ if (m_CallsiteIsInTryRegion)
+ {
+ // Inlining a method with pinned locals in a try
+ // region requires wrapping the inline body in a
+ // try/finally to ensure unpinning. Bail instead.
+ SetFailure(InlineObservation::CALLSITE_PIN_IN_TRY_REGION);
+ return;
+ }
+ break;
+
default:
// Pass all other information to the legacy policy
LegacyPolicy::NoteBool(obs, value);
@@ -928,7 +974,7 @@ bool EnhancedLegacyPolicy::PropagateNeverToRuntime() const
return propagate;
}
-#ifdef DEBUG
+#if defined(DEBUG) || defined(INLINE_DATA)
//------------------------------------------------------------------------
// RandomPolicy: construct a new RandomPolicy
@@ -936,89 +982,10 @@ bool EnhancedLegacyPolicy::PropagateNeverToRuntime() const
// Arguments:
// compiler -- compiler instance doing the inlining (root compiler)
// isPrejitRoot -- true if this compiler is prejitting the root method
-// seed -- seed value for the random number generator
-
-RandomPolicy::RandomPolicy(Compiler* compiler, bool isPrejitRoot, unsigned seed)
- : LegalPolicy(isPrejitRoot)
- , m_RootCompiler(compiler)
- , m_Random(nullptr)
- , m_CodeSize(0)
- , m_IsForceInline(false)
- , m_IsForceInlineKnown(false)
-{
- // If necessary, setup and seed the random state.
- if (compiler->inlRNG == nullptr)
- {
- compiler->inlRNG = new (compiler, CMK_Inlining) CLRRandom();
- unsigned hash = m_RootCompiler->info.compMethodHash();
- assert(hash != 0);
- assert(seed != 0);
- int hashSeed = static_cast<int>(hash ^ seed);
- compiler->inlRNG->Init(hashSeed);
- }
-
- m_Random = compiler->inlRNG;
-}
-
-//------------------------------------------------------------------------
-// NoteSuccess: handle finishing all the inlining checks successfully
-
-void RandomPolicy::NoteSuccess()
+RandomPolicy::RandomPolicy(Compiler* compiler, bool isPrejitRoot) : DiscretionaryPolicy(compiler, isPrejitRoot)
{
- assert(InlDecisionIsCandidate(m_Decision));
- m_Decision = InlineDecision::SUCCESS;
-}
-
-//------------------------------------------------------------------------
-// NoteBool: handle a boolean observation with non-fatal impact
-//
-// Arguments:
-// obs - the current obsevation
-// value - the value of the observation
-void RandomPolicy::NoteBool(InlineObservation obs, bool value)
-{
- // Check the impact
- InlineImpact impact = InlGetImpact(obs);
-
- // As a safeguard, all fatal impact must be
- // reported via noteFatal.
- assert(impact != InlineImpact::FATAL);
-
- // Handle most information here
- bool isInformation = (impact == InlineImpact::INFORMATION);
- bool propagate = !isInformation;
-
- if (isInformation)
- {
- switch (obs)
- {
- case InlineObservation::CALLEE_IS_FORCE_INLINE:
- // The RandomPolicy still honors force inlines.
- //
- // We may make the force-inline observation more than
- // once. All observations should agree.
- assert(!m_IsForceInlineKnown || (m_IsForceInline == value));
- m_IsForceInline = value;
- m_IsForceInlineKnown = true;
- break;
-
- case InlineObservation::CALLEE_HAS_SWITCH:
- case InlineObservation::CALLEE_UNSUPPORTED_OPCODE:
- // Pass these on, they should cause inlining to fail.
- propagate = true;
- break;
-
- default:
- // Ignore the remainder for now
- break;
- }
- }
-
- if (propagate)
- {
- NoteInternal(obs);
- }
+ m_Random = compiler->m_inlineStrategy->GetRandom();
}
//------------------------------------------------------------------------
@@ -1032,7 +999,6 @@ void RandomPolicy::NoteInt(InlineObservation obs, int value)
{
switch (obs)
{
-
case InlineObservation::CALLEE_IL_CODE_SIZE:
{
assert(m_IsForceInlineKnown);
@@ -1054,7 +1020,8 @@ void RandomPolicy::NoteInt(InlineObservation obs, int value)
}
default:
- // Ignore all other information
+ // Defer to superclass for all other information
+ DiscretionaryPolicy::NoteInt(obs, value);
break;
}
}
@@ -1087,6 +1054,16 @@ void RandomPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
}
}
+ // If we're also dumping inline data, make additional observations
+ // based on the method info, and estimate code size and perf
+ // impact, so that the reports have the necessary data.
+ if (JitConfig.JitInlineDumpData() != 0)
+ {
+ MethodInfoObservations(methodInfo);
+ EstimateCodeSize();
+ EstimatePerformanceImpact();
+ }
+
// Use a probability curve that roughly matches the observed
// behavior of the LegacyPolicy. That way we're inlining
// differently but not creating enormous methods.
@@ -1165,7 +1142,7 @@ void RandomPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
}
}
-#endif // DEBUG
+#endif // defined(DEBUG) || defined(INLINE_DATA)
#ifdef _MSC_VER
// Disable warning about new array member initialization behavior
@@ -1181,7 +1158,7 @@ void RandomPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
// clang-format off
DiscretionaryPolicy::DiscretionaryPolicy(Compiler* compiler, bool isPrejitRoot)
- : LegacyPolicy(compiler, isPrejitRoot)
+ : EnhancedLegacyPolicy(compiler, isPrejitRoot)
, m_Depth(0)
, m_BlockCount(0)
, m_Maxstack(0)
@@ -1227,6 +1204,7 @@ DiscretionaryPolicy::DiscretionaryPolicy(Compiler* compiler, bool isPrejitRoot)
, m_IsSameThis(false)
, m_CallerHasNewArray(false)
, m_CallerHasNewObj(false)
+ , m_CalleeHasGCStruct(false)
{
// Empty
}
@@ -1278,8 +1256,17 @@ void DiscretionaryPolicy::NoteBool(InlineObservation obs, bool value)
m_CallerHasNewObj = value;
break;
+ case InlineObservation::CALLEE_HAS_GC_STRUCT:
+ m_CalleeHasGCStruct = value;
+ break;
+
+ case InlineObservation::CALLSITE_RARE_GC_STRUCT:
+ // This is redundant since this policy tracks call site
+ // hotness for all candidates. So ignore.
+ break;
+
default:
- LegacyPolicy::NoteBool(obs, value);
+ EnhancedLegacyPolicy::NoteBool(obs, value);
break;
}
}
@@ -1295,7 +1282,6 @@ void DiscretionaryPolicy::NoteInt(InlineObservation obs, int value)
{
switch (obs)
{
-
case InlineObservation::CALLEE_IL_CODE_SIZE:
// Override how code size is handled
{
@@ -1323,7 +1309,7 @@ void DiscretionaryPolicy::NoteInt(InlineObservation obs, int value)
// on similarity of impact on codegen.
OPCODE opcode = static_cast<OPCODE>(value);
ComputeOpcodeBin(opcode);
- LegacyPolicy::NoteInt(obs, value);
+ EnhancedLegacyPolicy::NoteInt(obs, value);
break;
}
@@ -1344,8 +1330,8 @@ void DiscretionaryPolicy::NoteInt(InlineObservation obs, int value)
break;
default:
- // Delegate remainder to the LegacyPolicy.
- LegacyPolicy::NoteInt(obs, value);
+ // Delegate remainder to the super class.
+ EnhancedLegacyPolicy::NoteInt(obs, value);
break;
}
}
@@ -1660,8 +1646,8 @@ void DiscretionaryPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo
// model for actual inlining.
EstimatePerformanceImpact();
- // Delegate to LegacyPolicy for the rest
- LegacyPolicy::DetermineProfitability(methodInfo);
+ // Delegate to super class for the rest
+ EnhancedLegacyPolicy::DetermineProfitability(methodInfo);
}
//------------------------------------------------------------------------
@@ -1869,7 +1855,7 @@ int DiscretionaryPolicy::CodeSizeEstimate()
void DiscretionaryPolicy::DumpSchema(FILE* file) const
{
- fprintf(file, ",ILSize");
+ fprintf(file, "ILSize");
fprintf(file, ",CallsiteFrequency");
fprintf(file, ",InstructionCount");
fprintf(file, ",LoadStoreCount");
@@ -1938,6 +1924,8 @@ void DiscretionaryPolicy::DumpSchema(FILE* file) const
fprintf(file, ",IsSameThis");
fprintf(file, ",CallerHasNewArray");
fprintf(file, ",CallerHasNewObj");
+ fprintf(file, ",CalleeDoesNotReturn");
+ fprintf(file, ",CalleeHasGCStruct");
}
//------------------------------------------------------------------------
@@ -1949,7 +1937,7 @@ void DiscretionaryPolicy::DumpSchema(FILE* file) const
void DiscretionaryPolicy::DumpData(FILE* file) const
{
- fprintf(file, ",%u", m_CodeSize);
+ fprintf(file, "%u", m_CodeSize);
fprintf(file, ",%u", m_CallsiteFrequency);
fprintf(file, ",%u", m_InstructionCount);
fprintf(file, ",%u", m_LoadStoreCount);
@@ -2018,6 +2006,8 @@ void DiscretionaryPolicy::DumpData(FILE* file) const
fprintf(file, ",%u", m_IsSameThis ? 1 : 0);
fprintf(file, ",%u", m_CallerHasNewArray ? 1 : 0);
fprintf(file, ",%u", m_CallerHasNewObj ? 1 : 0);
+ fprintf(file, ",%u", m_IsNoReturn ? 1 : 0);
+ fprintf(file, ",%u", m_CalleeHasGCStruct ? 1 : 0);
}
#endif // defined(DEBUG) || defined(INLINE_DATA)
@@ -2473,7 +2463,7 @@ bool ReplayPolicy::FindMethod()
// See if token matches
unsigned token = 0;
- int count = sscanf(buffer, " <Token>%u</Token> ", &token);
+ int count = sscanf_s(buffer, " <Token>%u</Token> ", &token);
if ((count != 1) || (token != methodToken))
{
continue;
@@ -2487,7 +2477,7 @@ bool ReplayPolicy::FindMethod()
// See if hash matches
unsigned hash = 0;
- count = sscanf(buffer, " <Hash>%u</Hash> ", &hash);
+ count = sscanf_s(buffer, " <Hash>%u</Hash> ", &hash);
if ((count != 1) || (hash != methodHash))
{
continue;
@@ -2646,7 +2636,7 @@ bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
// Match token
unsigned inlineToken = 0;
- int count = sscanf(buffer, " <Token>%u</Token> ", &inlineToken);
+ int count = sscanf_s(buffer, " <Token>%u</Token> ", &inlineToken);
if ((count != 1) || (inlineToken != token))
{
@@ -2661,7 +2651,7 @@ bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
// Match hash
unsigned inlineHash = 0;
- count = sscanf(buffer, " <Hash>%u</Hash> ", &inlineHash);
+ count = sscanf_s(buffer, " <Hash>%u</Hash> ", &inlineHash);
if ((count != 1) || (inlineHash != hash))
{
@@ -2676,7 +2666,7 @@ bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
// Match offset
unsigned inlineOffset = 0;
- count = sscanf(buffer, " <Offset>%u</Offset> ", &inlineOffset);
+ count = sscanf_s(buffer, " <Offset>%u</Offset> ", &inlineOffset);
if ((count != 1) || (inlineOffset != offset))
{
continue;
@@ -2695,7 +2685,7 @@ bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
if (fgets(buffer, sizeof(buffer), s_ReplayFile) != nullptr)
{
unsigned collectData = 0;
- count = sscanf(buffer, " <CollectData>%u</CollectData> ", &collectData);
+ count = sscanf_s(buffer, " <CollectData>%u</CollectData> ", &collectData);
if (count == 1)
{