diff options
-rw-r--r-- | src/jit/inline.h | 22 | ||||
-rw-r--r-- | src/jit/inlinepolicy.cpp | 77 | ||||
-rw-r--r-- | src/jit/inlinepolicy.h | 24 | ||||
-rw-r--r-- | src/jit/jitconfigvalues.h | 1 | ||||
-rw-r--r-- | tests/src/JIT/jit64/regress/ddb/87766/ddb87766.cs | 8 |
5 files changed, 124 insertions, 8 deletions
diff --git a/src/jit/inline.h b/src/jit/inline.h index d0eaf42735..19c3e2d09a 100644 --- a/src/jit/inline.h +++ b/src/jit/inline.h @@ -656,7 +656,7 @@ public: InlineResult* inlineResult); // Compiler associated with this strategy - Compiler* GetCompiler() + Compiler* GetCompiler() const { return m_Compiler; } @@ -665,23 +665,35 @@ public: InlineContext* GetRootContext(); // Get IL size for maximum allowable inline - unsigned GetMaxInlineILSize() + unsigned GetMaxInlineILSize() const { return m_MaxInlineSize; } // Get depth of maximum allowable inline - unsigned GetMaxInlineDepth() + unsigned GetMaxInlineDepth() const { return m_MaxInlineDepth; } - // Number of successful inlines into the root. - unsigned GetInlineCount() + // Number of successful inlines into the root + unsigned GetInlineCount() const { return m_InlineCount; } + // Return the current code size estimate for this method + int GetCurrentSizeEstimate() const + { + return m_CurrentSizeEstimate; + } + + // Return the initial code size estimate for this method + int GetInitialSizeEstimate() const + { + return m_InitialSizeEstimate; + } + // Inform strategy that there's a new inline candidate. void NoteCandidate(); diff --git a/src/jit/inlinepolicy.cpp b/src/jit/inlinepolicy.cpp index 9615bdcfb5..73e22d4530 100644 --- a/src/jit/inlinepolicy.cpp +++ b/src/jit/inlinepolicy.cpp @@ -43,6 +43,14 @@ InlinePolicy* InlinePolicy::GetPolicy(Compiler* compiler, bool isPrejitRoot) #if defined(DEBUG) || defined(INLINE_DATA) + // Optionally install the SizePolicy. + bool useSizePolicy = JitConfig.JitInlinePolicySize() != 0; + + if (useSizePolicy) + { + return new (compiler, CMK_Inlining) SizePolicy(compiler, isPrejitRoot); + } + // Optionally install the FullPolicy. bool useFullPolicy = JitConfig.JitInlinePolicyFull() != 0; @@ -1948,4 +1956,73 @@ void FullPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) return; } +//------------------------------------------------------------------------/ +// SizePolicy: construct a new SizePolicy +// +// Arguments: +// compiler -- compiler instance doing the inlining (root compiler) +// isPrejitRoot -- true if this compiler is prejitting the root method + +SizePolicy::SizePolicy(Compiler* compiler, bool isPrejitRoot) + : DiscretionaryPolicy(compiler, isPrejitRoot) +{ + // Empty +} + +//------------------------------------------------------------------------ +// DetermineProfitability: determine if this inline is profitable +// +// Arguments: +// methodInfo -- method info for the callee + +void SizePolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) +{ + // Do some homework + MethodInfoObservations(methodInfo); + EstimateCodeSize(); + + // Does this inline increase the estimated size beyond + // the original size estimate? + const InlineStrategy* strategy = m_RootCompiler->m_inlineStrategy; + const int initialSize = strategy->GetInitialSizeEstimate(); + const int currentSize = strategy->GetCurrentSizeEstimate(); + const int newSize = currentSize + m_ModelCodeSizeEstimate; + + if (newSize <= initialSize) + { + // Estimated size impact is acceptable, so inline here. + JITLOG_THIS(m_RootCompiler, + (LL_INFO100000, + "Inline profitable, root size estimate %d is less than initial size %d\n", + newSize / SIZE_SCALE, initialSize / SIZE_SCALE)); + + if (m_IsPrejitRoot) + { + SetCandidate(InlineObservation::CALLEE_IS_SIZE_DECREASING_INLINE); + } + else + { + SetCandidate(InlineObservation::CALLSITE_IS_SIZE_DECREASING_INLINE); + } + } + else + { + // Estimated size increase is too large, so no inline here. + // + // Note that we ought to reconsider this inline if we make + // room in the budget by inlining a bunch of size decreasing + // inlines after this one. But for now, we won't do this. + if (m_IsPrejitRoot) + { + SetNever(InlineObservation::CALLEE_NOT_PROFITABLE_INLINE); + } + else + { + SetFailure(InlineObservation::CALLSITE_NOT_PROFITABLE_INLINE); + } + } + + return; +} + #endif // defined(DEBUG) || defined(INLINE_DATA) diff --git a/src/jit/inlinepolicy.h b/src/jit/inlinepolicy.h index eb019d446b..31a686e52f 100644 --- a/src/jit/inlinepolicy.h +++ b/src/jit/inlinepolicy.h @@ -19,6 +19,7 @@ // DiscretionaryPolicy - legacy variant with uniform size policy // ModelPolicy - policy based on statistical modelling // FullPolicy - inlines everything up to size and depth limits +// SizePolicy - tries not to increase method sizes #ifndef _INLINE_POLICY_H_ #define _INLINE_POLICY_H_ @@ -307,7 +308,7 @@ class FullPolicy : public DiscretionaryPolicy { public: - // Construct a ModelPolicy + // Construct a FullPolicy FullPolicy(Compiler* compiler, bool isPrejitRoot); // Policy determinations @@ -317,6 +318,27 @@ public: const char* GetName() const override { return "FullPolicy"; } }; +// SizePolicy is an experimental policy that will inline as much +// as possible without increasing the (estimated) method size. +// +// It may be useful down the road as a policy to use for methods +// that are rarely executed (eg class constructors). + +class SizePolicy : public DiscretionaryPolicy +{ +public: + + // Construct a SizePolicy + SizePolicy(Compiler* compiler, bool isPrejitRoot); + + // Policy determinations + void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override; + + // Miscellaneous + const char* GetName() const override { return "SizePolicy"; } +}; + + #endif // defined(DEBUG) || defined(INLINE_DATA) #endif // _INLINE_POLICY_H_ diff --git a/src/jit/jitconfigvalues.h b/src/jit/jitconfigvalues.h index cbf676d413..cb4724dee0 100644 --- a/src/jit/jitconfigvalues.h +++ b/src/jit/jitconfigvalues.h @@ -197,6 +197,7 @@ CONFIG_INTEGER(JitInlineLimit, W("JitInlineLimit"), -1) CONFIG_INTEGER(JitInlinePolicyDiscretionary, W("JitInlinePolicyDiscretionary"), 0) CONFIG_INTEGER(JitInlinePolicyModel, W("JitInlinePolicyModel"), 0) CONFIG_INTEGER(JitInlinePolicyFull, W("JitInlinePolicyFull"), 0) +CONFIG_INTEGER(JitInlinePolicySize, W("JitInlinePolicySize"), 0) CONFIG_STRING(JitNoInlineRange, W("JitNoInlineRange")) #endif // defined(DEBUG) || defined(INLINE_DATA) diff --git a/tests/src/JIT/jit64/regress/ddb/87766/ddb87766.cs b/tests/src/JIT/jit64/regress/ddb/87766/ddb87766.cs index 445026c5e0..a33bf86b92 100644 --- a/tests/src/JIT/jit64/regress/ddb/87766/ddb87766.cs +++ b/tests/src/JIT/jit64/regress/ddb/87766/ddb87766.cs @@ -2,23 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System; +using System.Runtime.CompilerServices; public class VInline { private int _fi1; private int _fi2; + public VInline(int ival) { _fi1 = ival; _fi2 = 0; } - [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + + [MethodImpl(MethodImplOptions.NoInlining)] private void GetI1(ref int i) { i = _fi1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Accumulate(int a) { int i = 0; |