1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
7 // This file contains class definitions for various inlining
8 // policies used by the jit.
12 // LegalPolicy - partial class providing common legality checks
13 // DefaultPolicy - default inliner policy
14 // DiscretionaryPolicy - default variant with uniform size policy
15 // ModelPolicy - policy based on statistical modelling
17 // These experimental policies are available only in
18 // DEBUG or release+INLINE_DATA builds of the jit.
20 // RandomPolicy - randomized inlining
21 // FullPolicy - inlines everything up to size and depth limits
22 // SizePolicy - tries not to increase method sizes
24 // The default policy in use is the DefaultPolicy.
26 #ifndef _INLINE_POLICY_H_
27 #define _INLINE_POLICY_H_
32 // LegalPolicy is a partial policy that encapsulates the common
33 // legality and ability checks the inliner must make.
35 // Generally speaking, the legal policy expects the inlining attempt
36 // to fail fast when a fatal or equivalent observation is made. So
37 // once an observation causes failure, no more observations are
38 // expected. However for the prejit scan case (where the jit is not
39 // actually inlining, but is assessing a method's general
40 // inlinability) the legal policy allows multiple failing
41 // observations provided they have the same impact. Only the first
42 // observation that puts the policy into a failing state is
43 // remembered. Transitions from failing states to candidate or success
44 // states are not allowed.
46 class LegalPolicy : public InlinePolicy
51 LegalPolicy(bool isPrejitRoot) : InlinePolicy(isPrejitRoot)
56 // Handle an observation that must cause inlining to fail.
57 void NoteFatal(InlineObservation obs) override;
59 #if defined(DEBUG) || defined(INLINE_DATA)
61 // Record observation for prior failure
62 void NotePriorFailure(InlineObservation obs) override;
64 #endif // defined(DEBUG) || defined(INLINE_DATA)
68 void NoteInternal(InlineObservation obs);
69 void SetCandidate(InlineObservation obs);
70 void SetFailure(InlineObservation obs);
71 void SetNever(InlineObservation obs);
74 // Forward declaration for the state machine class used by the
79 // DefaultPolicy implements the default inlining policy for the jit.
81 class DefaultPolicy : public LegalPolicy
84 // Construct a DefaultPolicy
85 DefaultPolicy(Compiler* compiler, bool isPrejitRoot)
86 : LegalPolicy(isPrejitRoot)
87 , m_RootCompiler(compiler)
88 , m_StateMachine(nullptr)
91 , m_CallsiteFrequency(InlineCallsiteFrequency::UNUSED)
92 , m_InstructionCount(0)
95 , m_ArgFeedsConstantTest(0)
96 , m_ArgFeedsRangeCheck(0)
97 , m_ConstantArgFeedsConstantTest(0)
98 , m_CalleeNativeSizeEstimate(0)
99 , m_CallsiteNativeSizeEstimate(0)
100 , m_IsForceInline(false)
101 , m_IsForceInlineKnown(false)
102 , m_IsInstanceCtor(false)
103 , m_IsFromPromotableValueClass(false)
105 , m_LooksLikeWrapperMethod(false)
106 , m_MethodIsMostlyLoadStore(false)
107 , m_CallsiteIsInTryRegion(false)
108 , m_CallsiteIsInLoop(false)
109 , m_IsNoReturn(false)
110 , m_IsNoReturnKnown(false)
115 // Policy observations
116 void NoteSuccess() override;
117 void NoteBool(InlineObservation obs, bool value) override;
118 void NoteInt(InlineObservation obs, int value) override;
120 // Policy determinations
121 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
124 bool PropagateNeverToRuntime() const override;
127 int CodeSizeEstimate() override;
129 #if defined(DEBUG) || defined(INLINE_DATA)
131 const char* GetName() const override
133 return "DefaultPolicy";
136 #endif // (DEBUG) || defined(INLINE_DATA)
142 MAX_BASIC_BLOCKS = 5,
147 double DetermineMultiplier();
148 int DetermineNativeSizeEstimate();
149 int DetermineCallsiteNativeSizeEstimate(CORINFO_METHOD_INFO* methodInfo);
152 Compiler* m_RootCompiler; // root compiler instance
153 CodeSeqSM* m_StateMachine;
156 InlineCallsiteFrequency m_CallsiteFrequency;
157 unsigned m_InstructionCount;
158 unsigned m_LoadStoreCount;
159 unsigned m_ArgFeedsTest;
160 unsigned m_ArgFeedsConstantTest;
161 unsigned m_ArgFeedsRangeCheck;
162 unsigned m_ConstantArgFeedsConstantTest;
163 int m_CalleeNativeSizeEstimate;
164 int m_CallsiteNativeSizeEstimate;
165 bool m_IsForceInline : 1;
166 bool m_IsForceInlineKnown : 1;
167 bool m_IsInstanceCtor : 1;
168 bool m_IsFromPromotableValueClass : 1;
170 bool m_LooksLikeWrapperMethod : 1;
171 bool m_MethodIsMostlyLoadStore : 1;
172 bool m_CallsiteIsInTryRegion : 1;
173 bool m_CallsiteIsInLoop : 1;
174 bool m_IsNoReturn : 1;
175 bool m_IsNoReturnKnown : 1;
178 // DiscretionaryPolicy is a variant of the default policy. It
179 // differs in that there is no ALWAYS_INLINE class, there is no IL
180 // size limit, and in prejit mode, discretionary failures do not
181 // propagate the "NEVER" inline bit to the runtime.
183 // It is useful for gathering data about inline costs.
185 class DiscretionaryPolicy : public DefaultPolicy
188 // Construct a DiscretionaryPolicy
189 DiscretionaryPolicy(Compiler* compiler, bool isPrejitRoot);
191 // Policy observations
192 void NoteBool(InlineObservation obs, bool value) override;
193 void NoteInt(InlineObservation obs, int value) override;
196 bool PropagateNeverToRuntime() const override;
198 // Policy determinations
199 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
202 int CodeSizeEstimate() override;
204 #if defined(DEBUG) || defined(INLINE_DATA)
207 void DumpData(FILE* file) const override;
208 void DumpSchema(FILE* file) const override;
211 const char* GetName() const override
213 return "DiscretionaryPolicy";
216 #endif // defined(DEBUG) || defined(INLINE_DATA)
219 void ComputeOpcodeBin(OPCODE opcode);
220 void EstimateCodeSize();
221 void EstimatePerformanceImpact();
222 void MethodInfoObservations(CORINFO_METHOD_INFO* methodInfo);
229 unsigned m_BlockCount;
232 CorInfoType m_ArgType[MAX_ARGS];
233 size_t m_ArgSize[MAX_ARGS];
234 unsigned m_LocalCount;
235 CorInfoType m_ReturnType;
237 unsigned m_ArgAccessCount;
238 unsigned m_LocalAccessCount;
239 unsigned m_IntConstantCount;
240 unsigned m_FloatConstantCount;
241 unsigned m_IntLoadCount;
242 unsigned m_FloatLoadCount;
243 unsigned m_IntStoreCount;
244 unsigned m_FloatStoreCount;
245 unsigned m_SimpleMathCount;
246 unsigned m_ComplexMathCount;
247 unsigned m_OverflowMathCount;
248 unsigned m_IntArrayLoadCount;
249 unsigned m_FloatArrayLoadCount;
250 unsigned m_RefArrayLoadCount;
251 unsigned m_StructArrayLoadCount;
252 unsigned m_IntArrayStoreCount;
253 unsigned m_FloatArrayStoreCount;
254 unsigned m_RefArrayStoreCount;
255 unsigned m_StructArrayStoreCount;
256 unsigned m_StructOperationCount;
257 unsigned m_ObjectModelCount;
258 unsigned m_FieldLoadCount;
259 unsigned m_FieldStoreCount;
260 unsigned m_StaticFieldLoadCount;
261 unsigned m_StaticFieldStoreCount;
262 unsigned m_LoadAddressCount;
263 unsigned m_ThrowCount;
264 unsigned m_ReturnCount;
265 unsigned m_CallCount;
266 unsigned m_CallSiteWeight;
267 int m_ModelCodeSizeEstimate;
268 int m_PerCallInstructionEstimate;
271 bool m_CallerHasNewArray;
272 bool m_CallerHasNewObj;
273 bool m_CalleeHasGCStruct;
276 // ModelPolicy is an experimental policy that uses the results
277 // of data modelling to make estimates.
279 class ModelPolicy : public DiscretionaryPolicy
282 // Construct a ModelPolicy
283 ModelPolicy(Compiler* compiler, bool isPrejitRoot);
285 // Policy observations
286 void NoteInt(InlineObservation obs, int value) override;
288 // Policy determinations
289 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
292 bool PropagateNeverToRuntime() const override
297 #if defined(DEBUG) || defined(INLINE_DATA)
300 const char* GetName() const override
302 return "ModelPolicy";
305 #endif // defined(DEBUG) || defined(INLINE_DATA)
308 #if defined(DEBUG) || defined(INLINE_DATA)
310 // RandomPolicy implements a policy that inlines at random.
311 // It is mostly useful for stress testing.
313 class RandomPolicy : public DiscretionaryPolicy
316 // Construct a RandomPolicy
317 RandomPolicy(Compiler* compiler, bool isPrejitRoot);
319 // Policy observations
320 void NoteInt(InlineObservation obs, int value) override;
322 // Policy determinations
323 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
325 const char* GetName() const override
327 return "RandomPolicy";
335 #endif // defined(DEBUG) || defined(INLINE_DATA)
337 #if defined(DEBUG) || defined(INLINE_DATA)
339 // FullPolicy is an experimental policy that will always inline if
340 // possible, subject to externally settable depth and size limits.
342 // It's useful for unconvering the full set of possible inlines for
345 class FullPolicy : public DiscretionaryPolicy
348 // Construct a FullPolicy
349 FullPolicy(Compiler* compiler, bool isPrejitRoot);
351 // Policy determinations
352 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
355 const char* GetName() const override
361 // SizePolicy is an experimental policy that will inline as much
362 // as possible without increasing the (estimated) method size.
364 // It may be useful down the road as a policy to use for methods
365 // that are rarely executed (eg class constructors).
367 class SizePolicy : public DiscretionaryPolicy
370 // Construct a SizePolicy
371 SizePolicy(Compiler* compiler, bool isPrejitRoot);
373 // Policy determinations
374 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
377 const char* GetName() const override
383 // The ReplayPolicy performs only inlines specified by an external
384 // inline replay log.
386 class ReplayPolicy : public DiscretionaryPolicy
389 // Construct a ReplayPolicy
390 ReplayPolicy(Compiler* compiler, bool isPrejitRoot);
392 // Policy observations
393 void NoteBool(InlineObservation obs, bool value) override;
395 // Optional observations
396 void NoteContext(InlineContext* context) override
398 m_InlineContext = context;
401 void NoteOffset(IL_OFFSETX offset) override
406 // Policy determinations
407 void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
410 const char* GetName() const override
412 return "ReplayPolicy";
415 static void FinalizeXml();
419 bool FindContext(InlineContext* context);
420 bool FindInline(CORINFO_METHOD_HANDLE callee);
421 bool FindInline(unsigned token, unsigned hash, unsigned offset);
423 static bool s_WroteReplayBanner;
424 static FILE* s_ReplayFile;
425 static CritSecObject s_XmlReaderLock;
426 InlineContext* m_InlineContext;
428 bool m_WasForceInline;
431 #endif // defined(DEBUG) || defined(INLINE_DATA)
433 #endif // _INLINE_POLICY_H_