Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / inlinepolicy.h
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.
4
5 // Inlining Policies
6 //
7 // This file contains class definitions for various inlining
8 // policies used by the jit.
9 //
10 // -- CLASSES --
11 //
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
16 //
17 // These experimental policies are available only in
18 // DEBUG or release+INLINE_DATA builds of the jit.
19 //
20 // RandomPolicy         - randomized inlining
21 // FullPolicy           - inlines everything up to size and depth limits
22 // SizePolicy           - tries not to increase method sizes
23 //
24 // The default policy in use is the DefaultPolicy.
25
26 #ifndef _INLINE_POLICY_H_
27 #define _INLINE_POLICY_H_
28
29 #include "jit.h"
30 #include "inline.h"
31
32 // LegalPolicy is a partial policy that encapsulates the common
33 // legality and ability checks the inliner must make.
34 //
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.
45
46 class LegalPolicy : public InlinePolicy
47 {
48
49 public:
50     // Constructor
51     LegalPolicy(bool isPrejitRoot) : InlinePolicy(isPrejitRoot)
52     {
53         // empty
54     }
55
56     // Handle an observation that must cause inlining to fail.
57     void NoteFatal(InlineObservation obs) override;
58
59 #if defined(DEBUG) || defined(INLINE_DATA)
60
61     // Record observation for prior failure
62     void NotePriorFailure(InlineObservation obs) override;
63
64 #endif // defined(DEBUG) || defined(INLINE_DATA)
65
66 protected:
67     // Helper methods
68     void NoteInternal(InlineObservation obs);
69     void SetCandidate(InlineObservation obs);
70     void SetFailure(InlineObservation obs);
71     void SetNever(InlineObservation obs);
72 };
73
74 // Forward declaration for the state machine class used by the
75 // DefaultPolicy
76
77 class CodeSeqSM;
78
79 // DefaultPolicy implements the default inlining policy for the jit.
80
81 class DefaultPolicy : public LegalPolicy
82 {
83 public:
84     // Construct a DefaultPolicy
85     DefaultPolicy(Compiler* compiler, bool isPrejitRoot)
86         : LegalPolicy(isPrejitRoot)
87         , m_RootCompiler(compiler)
88         , m_StateMachine(nullptr)
89         , m_Multiplier(0.0)
90         , m_CodeSize(0)
91         , m_CallsiteFrequency(InlineCallsiteFrequency::UNUSED)
92         , m_InstructionCount(0)
93         , m_LoadStoreCount(0)
94         , m_ArgFeedsTest(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)
104         , m_HasSimd(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)
111     {
112         // empty
113     }
114
115     // Policy observations
116     void NoteSuccess() override;
117     void NoteBool(InlineObservation obs, bool value) override;
118     void NoteInt(InlineObservation obs, int value) override;
119
120     // Policy determinations
121     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
122
123     // Policy policies
124     bool PropagateNeverToRuntime() const override;
125
126     // Policy estimates
127     int CodeSizeEstimate() override;
128
129 #if defined(DEBUG) || defined(INLINE_DATA)
130
131     const char* GetName() const override
132     {
133         return "DefaultPolicy";
134     }
135
136 #endif // (DEBUG) || defined(INLINE_DATA)
137
138 protected:
139     // Constants
140     enum
141     {
142         MAX_BASIC_BLOCKS = 5,
143         SIZE_SCALE       = 10
144     };
145
146     // Helper methods
147     double DetermineMultiplier();
148     int    DetermineNativeSizeEstimate();
149     int DetermineCallsiteNativeSizeEstimate(CORINFO_METHOD_INFO* methodInfo);
150
151     // Data members
152     Compiler*               m_RootCompiler; // root compiler instance
153     CodeSeqSM*              m_StateMachine;
154     double                  m_Multiplier;
155     unsigned                m_CodeSize;
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;
169     bool                    m_HasSimd : 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;
176 };
177
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.
182 //
183 // It is useful for gathering data about inline costs.
184
185 class DiscretionaryPolicy : public DefaultPolicy
186 {
187 public:
188     // Construct a DiscretionaryPolicy
189     DiscretionaryPolicy(Compiler* compiler, bool isPrejitRoot);
190
191     // Policy observations
192     void NoteBool(InlineObservation obs, bool value) override;
193     void NoteInt(InlineObservation obs, int value) override;
194
195     // Policy policies
196     bool PropagateNeverToRuntime() const override;
197
198     // Policy determinations
199     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
200
201     // Policy estimates
202     int CodeSizeEstimate() override;
203
204 #if defined(DEBUG) || defined(INLINE_DATA)
205
206     // Externalize data
207     void DumpData(FILE* file) const override;
208     void DumpSchema(FILE* file) const override;
209
210     // Miscellaneous
211     const char* GetName() const override
212     {
213         return "DiscretionaryPolicy";
214     }
215
216 #endif // defined(DEBUG) || defined(INLINE_DATA)
217
218 protected:
219     void ComputeOpcodeBin(OPCODE opcode);
220     void EstimateCodeSize();
221     void EstimatePerformanceImpact();
222     void MethodInfoObservations(CORINFO_METHOD_INFO* methodInfo);
223     enum
224     {
225         MAX_ARGS = 6
226     };
227
228     unsigned    m_Depth;
229     unsigned    m_BlockCount;
230     unsigned    m_Maxstack;
231     unsigned    m_ArgCount;
232     CorInfoType m_ArgType[MAX_ARGS];
233     size_t      m_ArgSize[MAX_ARGS];
234     unsigned    m_LocalCount;
235     CorInfoType m_ReturnType;
236     size_t      m_ReturnSize;
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;
269     bool        m_IsClassCtor;
270     bool        m_IsSameThis;
271     bool        m_CallerHasNewArray;
272     bool        m_CallerHasNewObj;
273     bool        m_CalleeHasGCStruct;
274 };
275
276 // ModelPolicy is an experimental policy that uses the results
277 // of data modelling to make estimates.
278
279 class ModelPolicy : public DiscretionaryPolicy
280 {
281 public:
282     // Construct a ModelPolicy
283     ModelPolicy(Compiler* compiler, bool isPrejitRoot);
284
285     // Policy observations
286     void NoteInt(InlineObservation obs, int value) override;
287
288     // Policy determinations
289     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
290
291     // Policy policies
292     bool PropagateNeverToRuntime() const override
293     {
294         return true;
295     }
296
297 #if defined(DEBUG) || defined(INLINE_DATA)
298
299     // Miscellaneous
300     const char* GetName() const override
301     {
302         return "ModelPolicy";
303     }
304
305 #endif // defined(DEBUG) || defined(INLINE_DATA)
306 };
307
308 #if defined(DEBUG) || defined(INLINE_DATA)
309
310 // RandomPolicy implements a policy that inlines at random.
311 // It is mostly useful for stress testing.
312
313 class RandomPolicy : public DiscretionaryPolicy
314 {
315 public:
316     // Construct a RandomPolicy
317     RandomPolicy(Compiler* compiler, bool isPrejitRoot);
318
319     // Policy observations
320     void NoteInt(InlineObservation obs, int value) override;
321
322     // Policy determinations
323     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
324
325     const char* GetName() const override
326     {
327         return "RandomPolicy";
328     }
329
330 private:
331     // Data members
332     CLRRandom* m_Random;
333 };
334
335 #endif // defined(DEBUG) || defined(INLINE_DATA)
336
337 #if defined(DEBUG) || defined(INLINE_DATA)
338
339 // FullPolicy is an experimental policy that will always inline if
340 // possible, subject to externally settable depth and size limits.
341 //
342 // It's useful for unconvering the full set of possible inlines for
343 // methods.
344
345 class FullPolicy : public DiscretionaryPolicy
346 {
347 public:
348     // Construct a FullPolicy
349     FullPolicy(Compiler* compiler, bool isPrejitRoot);
350
351     // Policy determinations
352     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
353
354     // Miscellaneous
355     const char* GetName() const override
356     {
357         return "FullPolicy";
358     }
359 };
360
361 // SizePolicy is an experimental policy that will inline as much
362 // as possible without increasing the (estimated) method size.
363 //
364 // It may be useful down the road as a policy to use for methods
365 // that are rarely executed (eg class constructors).
366
367 class SizePolicy : public DiscretionaryPolicy
368 {
369 public:
370     // Construct a SizePolicy
371     SizePolicy(Compiler* compiler, bool isPrejitRoot);
372
373     // Policy determinations
374     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
375
376     // Miscellaneous
377     const char* GetName() const override
378     {
379         return "SizePolicy";
380     }
381 };
382
383 // The ReplayPolicy performs only inlines specified by an external
384 // inline replay log.
385
386 class ReplayPolicy : public DiscretionaryPolicy
387 {
388 public:
389     // Construct a ReplayPolicy
390     ReplayPolicy(Compiler* compiler, bool isPrejitRoot);
391
392     // Policy observations
393     void NoteBool(InlineObservation obs, bool value) override;
394
395     // Optional observations
396     void NoteContext(InlineContext* context) override
397     {
398         m_InlineContext = context;
399     }
400
401     void NoteOffset(IL_OFFSETX offset) override
402     {
403         m_Offset = offset;
404     }
405
406     // Policy determinations
407     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
408
409     // Miscellaneous
410     const char* GetName() const override
411     {
412         return "ReplayPolicy";
413     }
414
415     static void FinalizeXml();
416
417 private:
418     bool FindMethod();
419     bool FindContext(InlineContext* context);
420     bool FindInline(CORINFO_METHOD_HANDLE callee);
421     bool FindInline(unsigned token, unsigned hash, unsigned offset);
422
423     static bool          s_WroteReplayBanner;
424     static FILE*         s_ReplayFile;
425     static CritSecObject s_XmlReaderLock;
426     InlineContext*       m_InlineContext;
427     IL_OFFSETX           m_Offset;
428     bool                 m_WasForceInline;
429 };
430
431 #endif // defined(DEBUG) || defined(INLINE_DATA)
432
433 #endif // _INLINE_POLICY_H_