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#include "treelifeupdater.h"
27
28// Forward reference types
29
30class CodeGenInterface;
31class emitter;
32
33// Small helper types
34
35//-------------------- Register selection ---------------------------------
36
37struct RegState
38{
39 regMaskTP rsCalleeRegArgMaskLiveIn; // mask of register arguments (live on entry to method)
40 unsigned rsCalleeRegArgCount; // total number of incoming register arguments of this kind (int or float)
41 bool rsIsFloat; // true for float argument registers, false for integer argument registers
42};
43
44//-------------------- CodeGenInterface ---------------------------------
45// interface to hide the full CodeGen implementation from rest of Compiler
46
47CodeGenInterface* getCodeGenerator(Compiler* comp);
48
49class CodeGenInterface
50{
51 friend class emitter;
52
53public:
54 CodeGenInterface(Compiler* theCompiler);
55 virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode) = 0;
56
57 // genSpillVar is called by compUpdateLifeVar.
58 // TODO-Cleanup: We should handle the spill directly in CodeGen, rather than
59 // calling it from compUpdateLifeVar. Then this can be non-virtual.
60
61 virtual void genSpillVar(GenTree* tree) = 0;
62
63 //-------------------------------------------------------------------------
64 // The following property indicates whether to align loops.
65 // (Used to avoid effects of loop alignment when diagnosing perf issues.)
66 __declspec(property(get = doAlignLoops, put = setAlignLoops)) bool genAlignLoops;
67 bool doAlignLoops()
68 {
69 return m_genAlignLoops;
70 }
71 void setAlignLoops(bool value)
72 {
73 m_genAlignLoops = value;
74 }
75
76 // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
77 // move it to Lower
78 virtual bool genCreateAddrMode(GenTree* addr,
79 bool fold,
80 bool* revPtr,
81 GenTree** rv1Ptr,
82 GenTree** rv2Ptr,
83#if SCALED_ADDR_MODES
84 unsigned* mulPtr,
85#endif // SCALED_ADDR_MODES
86 ssize_t* cnsPtr) = 0;
87
88 GCInfo gcInfo;
89
90 RegSet regSet;
91 RegState intRegState;
92 RegState floatRegState;
93
94protected:
95 Compiler* compiler;
96 bool m_genAlignLoops;
97
98private:
99#if defined(_TARGET_XARCH_)
100 static const insFlags instInfo[INS_count];
101#elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
102 static const BYTE instInfo[INS_count];
103#else
104#error Unsupported target architecture
105#endif
106
107#define INST_FP 0x01 // is it a FP instruction?
108public:
109 static bool instIsFP(instruction ins);
110
111 //-------------------------------------------------------------------------
112 // Liveness-related fields & methods
113public:
114 void genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bool isDying DEBUGARG(GenTree* tree));
115 void genUpdateVarReg(LclVarDsc* varDsc, GenTree* tree);
116
117protected:
118#ifdef DEBUG
119 VARSET_TP genTempOldLife;
120 bool genTempLiveChg;
121#endif
122
123 VARSET_TP genLastLiveSet; // A one element map (genLastLiveSet-> genLastLiveMask)
124 regMaskTP genLastLiveMask; // these two are used in genLiveMask
125
126 regMaskTP genGetRegMask(const LclVarDsc* varDsc);
127 regMaskTP genGetRegMask(GenTree* tree);
128
129 void genUpdateLife(GenTree* tree);
130 void genUpdateLife(VARSET_VALARG_TP newLife);
131
132 TreeLifeUpdater<true>* treeLifeUpdater;
133
134public:
135 bool genUseOptimizedWriteBarriers(GCInfo::WriteBarrierForm wbf);
136 bool genUseOptimizedWriteBarriers(GenTree* tgt, GenTree* assignVal);
137 CorInfoHelpFunc genWriteBarrierHelperForWriteBarrierForm(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
138
139 // The following property indicates whether the current method sets up
140 // an explicit stack frame or not.
141private:
142 PhasedVar<bool> m_cgFramePointerUsed;
143
144public:
145 bool isFramePointerUsed() const
146 {
147 return m_cgFramePointerUsed;
148 }
149 void setFramePointerUsed(bool value)
150 {
151 m_cgFramePointerUsed = value;
152 }
153 void resetFramePointerUsedWritePhase()
154 {
155 m_cgFramePointerUsed.ResetWritePhase();
156 }
157
158 // The following property indicates whether the current method requires
159 // an explicit frame. Does not prohibit double alignment of the stack.
160private:
161 PhasedVar<bool> m_cgFrameRequired;
162
163public:
164 bool isFrameRequired() const
165 {
166 return m_cgFrameRequired;
167 }
168 void setFrameRequired(bool value)
169 {
170 m_cgFrameRequired = value;
171 }
172
173public:
174 int genCallerSPtoFPdelta();
175 int genCallerSPtoInitialSPdelta();
176 int genSPtoFPdelta();
177 int genTotalFrameSize();
178
179 regNumber genGetThisArgReg(GenTreeCall* call) const;
180
181#ifdef _TARGET_XARCH_
182#ifdef _TARGET_AMD64_
183 // There are no reloc hints on x86
184 unsigned short genAddrRelocTypeHint(size_t addr);
185#endif
186 bool genDataIndirAddrCanBeEncodedAsPCRelOffset(size_t addr);
187 bool genCodeIndirAddrCanBeEncodedAsPCRelOffset(size_t addr);
188 bool genCodeIndirAddrCanBeEncodedAsZeroRelOffset(size_t addr);
189 bool genCodeIndirAddrNeedsReloc(size_t addr);
190 bool genCodeAddrNeedsReloc(size_t addr);
191#endif
192
193 // If both isFramePointerRequired() and isFrameRequired() are false, the method is eligible
194 // for Frame-Pointer-Omission (FPO).
195
196 // The following property indicates whether the current method requires
197 // an explicit stack frame, and all arguments and locals to be
198 // accessible relative to the Frame Pointer. Prohibits double alignment
199 // of the stack.
200private:
201 PhasedVar<bool> m_cgFramePointerRequired;
202
203public:
204 bool isFramePointerRequired() const
205 {
206 return m_cgFramePointerRequired;
207 }
208
209 void setFramePointerRequired(bool value)
210 {
211 m_cgFramePointerRequired = value;
212 }
213
214 //------------------------------------------------------------------------
215 // resetWritePhaseForFramePointerRequired: Return m_cgFramePointerRequired into the write phase.
216 // It is used only before the first phase, that locks this value, currently it is LSRA.
217 // Use it if you want to skip checks that set this value to true if the value is already true.
218 void resetWritePhaseForFramePointerRequired()
219 {
220 m_cgFramePointerRequired.ResetWritePhase();
221 }
222
223 void setFramePointerRequiredEH(bool value);
224
225 void setFramePointerRequiredGCInfo(bool value)
226 {
227#ifdef JIT32_GCENCODER
228 m_cgFramePointerRequired = value;
229#endif
230 }
231
232#if DOUBLE_ALIGN
233 // The following property indicates whether we going to double-align the frame.
234 // Arguments are accessed relative to the Frame Pointer (EBP), and
235 // locals are accessed relative to the Stack Pointer (ESP).
236public:
237 bool doDoubleAlign() const
238 {
239 return m_cgDoubleAlign;
240 }
241 void setDoubleAlign(bool value)
242 {
243 m_cgDoubleAlign = value;
244 }
245 bool doubleAlignOrFramePointerUsed() const
246 {
247 return isFramePointerUsed() || doDoubleAlign();
248 }
249
250private:
251 bool m_cgDoubleAlign;
252#else // !DOUBLE_ALIGN
253
254public:
255 bool doubleAlignOrFramePointerUsed() const
256 {
257 return isFramePointerUsed();
258 }
259
260#endif // !DOUBLE_ALIGN
261
262#ifdef DEBUG
263 // The following is used to make sure the value of 'genInterruptible' isn't
264 // changed after it's been used by any logic that depends on its value.
265public:
266 bool isGCTypeFixed()
267 {
268 return genInterruptibleUsed;
269 }
270
271protected:
272 bool genInterruptibleUsed;
273#endif
274
275public:
276 unsigned InferStructOpSizeAlign(GenTree* op, unsigned* alignmentWB);
277 unsigned InferOpSizeAlign(GenTree* op, unsigned* alignmentWB);
278
279 void genMarkTreeInReg(GenTree* tree, regNumber reg);
280
281 // Methods to abstract target information
282
283 bool validImmForInstr(instruction ins, target_ssize_t val, insFlags flags = INS_FLAGS_DONT_CARE);
284 bool validDispForLdSt(target_ssize_t disp, var_types type);
285 bool validImmForAdd(target_ssize_t imm, insFlags flags);
286 bool validImmForAlu(target_ssize_t imm);
287 bool validImmForMov(target_ssize_t imm);
288 bool validImmForBL(ssize_t addr);
289
290 instruction ins_Load(var_types srcType, bool aligned = false);
291 instruction ins_Store(var_types dstType, bool aligned = false);
292 static instruction ins_FloatLoad(var_types type = TYP_DOUBLE);
293
294 // Methods for spilling - used by RegSet
295 void spillReg(var_types type, TempDsc* tmp, regNumber reg);
296 void reloadReg(var_types type, TempDsc* tmp, regNumber reg);
297
298 // The following method is used by xarch emitter for handling contained tree temps.
299 TempDsc* getSpillTempDsc(GenTree* tree);
300
301public:
302 emitter* getEmitter()
303 {
304 return m_cgEmitter;
305 }
306
307protected:
308 emitter* m_cgEmitter;
309
310#ifdef LATE_DISASM
311public:
312 DisAssembler& getDisAssembler()
313 {
314 return m_cgDisAsm;
315 }
316
317protected:
318 DisAssembler m_cgDisAsm;
319#endif // LATE_DISASM
320
321public:
322#ifdef DEBUG
323 void setVerbose(bool value)
324 {
325 verbose = value;
326 }
327 bool verbose;
328#endif // DEBUG
329
330 // The following is set to true if we've determined that the current method
331 // is to be fully interruptible.
332 //
333public:
334 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
335 bool getInterruptible()
336 {
337 return m_cgInterruptible;
338 }
339 void setInterruptible(bool value)
340 {
341 m_cgInterruptible = value;
342 }
343
344#ifdef _TARGET_ARMARCH_
345 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
346 bool getHasTailCalls()
347 {
348 return m_cgHasTailCalls;
349 }
350 void setHasTailCalls(bool value)
351 {
352 m_cgHasTailCalls = value;
353 }
354#endif // _TARGET_ARMARCH_
355
356private:
357 bool m_cgInterruptible;
358#ifdef _TARGET_ARMARCH_
359 bool m_cgHasTailCalls;
360#endif // _TARGET_ARMARCH_
361
362 // The following will be set to true if we've determined that we need to
363 // generate a full-blown pointer register map for the current method.
364 // Currently it is equal to (genInterruptible || !isFramePointerUsed())
365 // (i.e. We generate the full-blown map for EBP-less methods and
366 // for fully interruptible methods)
367 //
368public:
369 __declspec(property(get = doFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
370 bool doFullPtrRegMap()
371 {
372 return m_cgFullPtrRegMap;
373 }
374 void setFullPtrRegMap(bool value)
375 {
376 m_cgFullPtrRegMap = value;
377 }
378
379private:
380 bool m_cgFullPtrRegMap;
381
382public:
383 virtual void siUpdate() = 0;
384
385#ifdef LATE_DISASM
386public:
387 virtual const char* siRegVarName(size_t offs, size_t size, unsigned reg) = 0;
388
389 virtual const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs) = 0;
390#endif // LATE_DISASM
391};
392
393#endif // _CODEGEN_INTERFACE_H_
394