Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / codegeninterface.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 //
6 // This file declares the types that constitute the interface between the
7 // code generator (CodeGen class) and the rest of the JIT.
8 //
9 // RegState
10 //
11 // CodeGenInterface includes only the public methods that are called by
12 // the Compiler.
13 //
14 // CodeGenContext contains the shared context between the code generator
15 // and other phases of the JIT, especially the register allocator and
16 // GC encoder.  It is distinct from CodeGenInterface so that it can be
17 // included in the Compiler object, and avoid an extra indirection when
18 // accessed from members of Compiler.
19 //
20
21 #ifndef _CODEGEN_INTERFACE_H_
22 #define _CODEGEN_INTERFACE_H_
23
24 #include "regset.h"
25 #include "jitgcinfo.h"
26
27 // Forward reference types
28
29 class CodeGenInterface;
30 class emitter;
31
32 // Small helper types
33
34 //-------------------- Register selection ---------------------------------
35
36 struct RegState
37 {
38     regMaskTP rsCalleeRegArgMaskLiveIn; // mask of register arguments (live on entry to method)
39 #ifdef LEGACY_BACKEND
40     unsigned rsCurRegArgNum; // current argument number (for caller)
41 #endif
42     unsigned rsCalleeRegArgCount; // total number of incoming register arguments of this kind (int or float)
43     bool     rsIsFloat;           // true for float argument registers, false for integer argument registers
44 };
45
46 //-------------------- CodeGenInterface ---------------------------------
47 // interface to hide the full CodeGen implementation from rest of Compiler
48
49 CodeGenInterface* getCodeGenerator(Compiler* comp);
50
51 class CodeGenInterface
52 {
53     friend class emitter;
54
55 public:
56     CodeGenInterface(Compiler* theCompiler);
57     virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode) = 0;
58
59 #ifndef LEGACY_BACKEND
60     // genSpillVar is called by compUpdateLifeVar in the RyuJIT backend case.
61     // TODO-Cleanup: We should handle the spill directly in CodeGen, rather than
62     // calling it from compUpdateLifeVar.  Then this can be non-virtual.
63
64     virtual void genSpillVar(GenTree* tree) = 0;
65 #endif // !LEGACY_BACKEND
66
67     //-------------------------------------------------------------------------
68     //  The following property indicates whether to align loops.
69     //  (Used to avoid effects of loop alignment when diagnosing perf issues.)
70     __declspec(property(get = doAlignLoops, put = setAlignLoops)) bool genAlignLoops;
71     bool doAlignLoops()
72     {
73         return m_genAlignLoops;
74     }
75     void setAlignLoops(bool value)
76     {
77         m_genAlignLoops = value;
78     }
79
80     // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
81     // move it to Lower
82     virtual bool genCreateAddrMode(GenTree*  addr,
83                                    int       mode,
84                                    bool      fold,
85                                    regMaskTP regMask,
86                                    bool*     revPtr,
87                                    GenTree** rv1Ptr,
88                                    GenTree** rv2Ptr,
89 #if SCALED_ADDR_MODES
90                                    unsigned* mulPtr,
91 #endif
92                                    unsigned* cnsPtr,
93                                    bool      nogen = false) = 0;
94
95     void genCalcFrameSize();
96
97     GCInfo gcInfo;
98
99     RegSet   regSet;
100     RegState intRegState;
101     RegState floatRegState;
102
103     // TODO-Cleanup: The only reason that regTracker needs to live in CodeGenInterface is that
104     // in RegSet::rsUnspillOneReg, it needs to mark the new register as "trash"
105     RegTracker regTracker;
106
107 public:
108 #ifdef LEGACY_BACKEND
109     void trashReg(regNumber reg)
110     {
111         regTracker.rsTrackRegTrash(reg);
112     }
113 #endif
114
115 protected:
116     Compiler* compiler;
117     bool      m_genAlignLoops;
118
119 private:
120     static const BYTE instInfo[INS_count];
121
122 #define INST_FP 0x01 // is it a FP instruction?
123 public:
124     static bool instIsFP(instruction ins);
125
126     //-------------------------------------------------------------------------
127     // Liveness-related fields & methods
128 public:
129     void genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bool isDying DEBUGARG(GenTree* tree));
130 #ifndef LEGACY_BACKEND
131     void genUpdateVarReg(LclVarDsc* varDsc, GenTree* tree);
132 #endif // !LEGACY_BACKEND
133
134 protected:
135 #ifdef DEBUG
136     VARSET_TP genTempOldLife;
137     bool      genTempLiveChg;
138 #endif
139
140     VARSET_TP genLastLiveSet;  // A one element map (genLastLiveSet-> genLastLiveMask)
141     regMaskTP genLastLiveMask; // these two are used in genLiveMask
142
143     regMaskTP genGetRegMask(const LclVarDsc* varDsc);
144     regMaskTP genGetRegMask(GenTree* tree);
145
146     void genUpdateLife(GenTree* tree);
147     void genUpdateLife(VARSET_VALARG_TP newLife);
148
149 #ifdef LEGACY_BACKEND
150     regMaskTP genLiveMask(GenTree* tree);
151     regMaskTP genLiveMask(VARSET_VALARG_TP liveSet);
152 #endif
153
154 public:
155     bool genUseOptimizedWriteBarriers(GCInfo::WriteBarrierForm wbf);
156     bool genUseOptimizedWriteBarriers(GenTree* tgt, GenTree* assignVal);
157     CorInfoHelpFunc genWriteBarrierHelperForWriteBarrierForm(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
158
159     // The following property indicates whether the current method sets up
160     // an explicit stack frame or not.
161 private:
162     PhasedVar<bool> m_cgFramePointerUsed;
163
164 public:
165     bool isFramePointerUsed() const
166     {
167         return m_cgFramePointerUsed;
168     }
169     void setFramePointerUsed(bool value)
170     {
171         m_cgFramePointerUsed = value;
172     }
173     void resetFramePointerUsedWritePhase()
174     {
175         m_cgFramePointerUsed.ResetWritePhase();
176     }
177
178     // The following property indicates whether the current method requires
179     // an explicit frame. Does not prohibit double alignment of the stack.
180 private:
181     PhasedVar<bool> m_cgFrameRequired;
182
183 public:
184     bool isFrameRequired() const
185     {
186         return m_cgFrameRequired;
187     }
188     void setFrameRequired(bool value)
189     {
190         m_cgFrameRequired = value;
191     }
192
193 public:
194     int genCallerSPtoFPdelta();
195     int genCallerSPtoInitialSPdelta();
196     int genSPtoFPdelta();
197     int genTotalFrameSize();
198
199     regNumber genGetThisArgReg(GenTreeCall* call) const;
200
201 #ifdef _TARGET_XARCH_
202 #ifdef _TARGET_AMD64_
203     // There are no reloc hints on x86
204     unsigned short genAddrRelocTypeHint(size_t addr);
205 #endif
206     bool genDataIndirAddrCanBeEncodedAsPCRelOffset(size_t addr);
207     bool genCodeIndirAddrCanBeEncodedAsPCRelOffset(size_t addr);
208     bool genCodeIndirAddrCanBeEncodedAsZeroRelOffset(size_t addr);
209     bool genCodeIndirAddrNeedsReloc(size_t addr);
210     bool genCodeAddrNeedsReloc(size_t addr);
211 #endif
212
213     // If both isFramePointerRequired() and isFrameRequired() are false, the method is eligible
214     // for Frame-Pointer-Omission (FPO).
215
216     // The following property indicates whether the current method requires
217     // an explicit stack frame, and all arguments and locals to be
218     // accessible relative to the Frame Pointer. Prohibits double alignment
219     // of the stack.
220 private:
221     PhasedVar<bool> m_cgFramePointerRequired;
222
223 public:
224     bool isFramePointerRequired() const
225     {
226         return m_cgFramePointerRequired;
227     }
228
229     void setFramePointerRequired(bool value)
230     {
231         m_cgFramePointerRequired = value;
232     }
233
234     //------------------------------------------------------------------------
235     // resetWritePhaseForFramePointerRequired: Return m_cgFramePointerRequired into the write phase.
236     // It is used only before the first phase, that locks this value, currently it is LSRA.
237     // Use it if you want to skip checks that set this value to true if the value is already true.
238     void resetWritePhaseForFramePointerRequired()
239     {
240         m_cgFramePointerRequired.ResetWritePhase();
241     }
242
243     void setFramePointerRequiredEH(bool value);
244
245     void setFramePointerRequiredGCInfo(bool value)
246     {
247 #ifdef JIT32_GCENCODER
248         m_cgFramePointerRequired = value;
249 #endif
250     }
251
252 #if DOUBLE_ALIGN
253     // The following property indicates whether we going to double-align the frame.
254     // Arguments are accessed relative to the Frame Pointer (EBP), and
255     // locals are accessed relative to the Stack Pointer (ESP).
256 public:
257     bool doDoubleAlign() const
258     {
259         return m_cgDoubleAlign;
260     }
261     void setDoubleAlign(bool value)
262     {
263         m_cgDoubleAlign = value;
264     }
265     bool doubleAlignOrFramePointerUsed() const
266     {
267         return isFramePointerUsed() || doDoubleAlign();
268     }
269
270 private:
271     bool m_cgDoubleAlign;
272 #else // !DOUBLE_ALIGN
273
274 public:
275     bool doubleAlignOrFramePointerUsed() const
276     {
277         return isFramePointerUsed();
278     }
279
280 #endif // !DOUBLE_ALIGN
281
282 #ifdef DEBUG
283     // The following is used to make sure the value of 'genInterruptible' isn't
284     // changed after it's been used by any logic that depends on its value.
285 public:
286     bool isGCTypeFixed()
287     {
288         return genInterruptibleUsed;
289     }
290
291 protected:
292     bool genInterruptibleUsed;
293 #endif
294
295 public:
296 #if FEATURE_STACK_FP_X87
297     FlatFPStateX87 compCurFPState;
298     unsigned       genFPregCnt; // count of current FP reg. vars (including dead but unpopped ones)
299
300     void SetRegVarFloat(regNumber reg, var_types type, LclVarDsc* varDsc);
301
302     void inst_FN(instruction ins, unsigned stk);
303
304     //  Keeps track of the current level of the FP coprocessor stack
305     //  (excluding FP reg. vars).
306     //  Do not use directly, instead use the processor agnostic accessor
307     //  methods below
308     //
309     unsigned genFPstkLevel;
310
311     void genResetFPstkLevel(unsigned newValue = 0);
312     unsigned        genGetFPstkLevel();
313     FlatFPStateX87* FlatFPAllocFPState(FlatFPStateX87* pInitFrom = 0);
314
315     void genIncrementFPstkLevel(unsigned inc = 1);
316     void genDecrementFPstkLevel(unsigned dec = 1);
317
318     static const char* regVarNameStackFP(regNumber reg);
319
320     // FlatFPStateX87_ functions are the actual verbs to do stuff
321     // like doing a transition, loading   register, etc. It's also
322     // responsible for emitting the x87 code to do so. We keep
323     // them in Compiler because we don't want to store a pointer to the
324     // emitter.
325     void FlatFPX87_MoveToTOS(FlatFPStateX87* pState, unsigned iVirtual, bool bEmitCode = true);
326     void FlatFPX87_SwapStack(FlatFPStateX87* pState, unsigned i, unsigned j, bool bEmitCode = true);
327
328 #endif // FEATURE_STACK_FP_X87
329
330 #ifndef LEGACY_BACKEND
331     regNumber genGetAssignedReg(GenTree* tree);
332 #endif // !LEGACY_BACKEND
333
334 #ifdef LEGACY_BACKEND
335     // Changes GT_LCL_VAR nodes to GT_REG_VAR nodes if possible.
336     bool genMarkLclVar(GenTree* tree);
337
338     void genBashLclVar(GenTree* tree, unsigned varNum, LclVarDsc* varDsc);
339 #endif // LEGACY_BACKEND
340
341 public:
342     unsigned InferStructOpSizeAlign(GenTree* op, unsigned* alignmentWB);
343     unsigned InferOpSizeAlign(GenTree* op, unsigned* alignmentWB);
344
345     void genMarkTreeInReg(GenTree* tree, regNumber reg);
346 #if CPU_LONG_USES_REGPAIR
347     void genMarkTreeInRegPair(GenTree* tree, regPairNo regPair);
348 #endif
349     // Methods to abstract target information
350
351     bool validImmForInstr(instruction ins, ssize_t val, insFlags flags = INS_FLAGS_DONT_CARE);
352     bool validDispForLdSt(ssize_t disp, var_types type);
353     bool validImmForAdd(ssize_t imm, insFlags flags);
354     bool validImmForAlu(ssize_t imm);
355     bool validImmForMov(ssize_t imm);
356     bool validImmForBL(ssize_t addr);
357
358     instruction ins_Load(var_types srcType, bool aligned = false);
359     instruction ins_Store(var_types dstType, bool aligned = false);
360     static instruction ins_FloatLoad(var_types type = TYP_DOUBLE);
361
362     // Methods for spilling - used by RegSet
363     void spillReg(var_types type, TempDsc* tmp, regNumber reg);
364     void reloadReg(var_types type, TempDsc* tmp, regNumber reg);
365     void reloadFloatReg(var_types type, TempDsc* tmp, regNumber reg);
366
367 #ifdef LEGACY_BACKEND
368     void SpillFloat(regNumber reg, bool bIsCall = false);
369 #endif // LEGACY_BACKEND
370
371     // The following method is used by xarch emitter for handling contained tree temps.
372     TempDsc* getSpillTempDsc(GenTree* tree);
373
374 public:
375     emitter* getEmitter()
376     {
377         return m_cgEmitter;
378     }
379
380 protected:
381     emitter* m_cgEmitter;
382
383 #ifdef LATE_DISASM
384 public:
385     DisAssembler& getDisAssembler()
386     {
387         return m_cgDisAsm;
388     }
389
390 protected:
391     DisAssembler m_cgDisAsm;
392 #endif // LATE_DISASM
393
394 public:
395 #ifdef DEBUG
396     void setVerbose(bool value)
397     {
398         verbose = value;
399     }
400     bool verbose;
401 #ifdef LEGACY_BACKEND
402     // Stress mode
403     int       genStressFloat();
404     regMaskTP genStressLockedMaskFloat();
405 #endif // LEGACY_BACKEND
406 #endif // DEBUG
407
408     // The following is set to true if we've determined that the current method
409     // is to be fully interruptible.
410     //
411 public:
412     __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
413     bool getInterruptible()
414     {
415         return m_cgInterruptible;
416     }
417     void setInterruptible(bool value)
418     {
419         m_cgInterruptible = value;
420     }
421
422 #ifdef _TARGET_ARMARCH_
423     __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
424     bool getHasTailCalls()
425     {
426         return m_cgHasTailCalls;
427     }
428     void setHasTailCalls(bool value)
429     {
430         m_cgHasTailCalls = value;
431     }
432 #endif // _TARGET_ARMARCH_
433
434 private:
435     bool m_cgInterruptible;
436 #ifdef _TARGET_ARMARCH_
437     bool m_cgHasTailCalls;
438 #endif // _TARGET_ARMARCH_
439
440     //  The following will be set to true if we've determined that we need to
441     //  generate a full-blown pointer register map for the current method.
442     //  Currently it is equal to (genInterruptible || !isFramePointerUsed())
443     //  (i.e. We generate the full-blown map for EBP-less methods and
444     //        for fully interruptible methods)
445     //
446 public:
447     __declspec(property(get = doFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
448     bool doFullPtrRegMap()
449     {
450         return m_cgFullPtrRegMap;
451     }
452     void setFullPtrRegMap(bool value)
453     {
454         m_cgFullPtrRegMap = value;
455     }
456
457 private:
458     bool m_cgFullPtrRegMap;
459
460 public:
461     virtual void siUpdate() = 0;
462
463 #ifdef LATE_DISASM
464 public:
465     virtual const char* siRegVarName(size_t offs, size_t size, unsigned reg) = 0;
466
467     virtual const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs) = 0;
468 #endif // LATE_DISASM
469 };
470
471 #endif // _CODEGEN_INTERFACE_H_