diff options
Diffstat (limited to 'src/jit/inlinepolicy.cpp')
-rw-r--r-- | src/jit/inlinepolicy.cpp | 232 |
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) { |