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.
6 // This file declares the types that constitute the interface between the
7 // code generator (CodeGen class) and the rest of the JIT.
11 // CodeGenInterface includes only the public methods that are called by
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.
21 #ifndef _CODEGEN_INTERFACE_H_
22 #define _CODEGEN_INTERFACE_H_
25 #include "jitgcinfo.h"
27 // Forward reference types
29 class CodeGenInterface;
34 //-------------------- Register selection ---------------------------------
38 regMaskTP rsCalleeRegArgMaskLiveIn; // mask of register arguments (live on entry to method)
40 unsigned rsCurRegArgNum; // current argument number (for caller)
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
46 //-------------------- CodeGenInterface ---------------------------------
47 // interface to hide the full CodeGen implementation from rest of Compiler
49 CodeGenInterface* getCodeGenerator(Compiler* comp);
51 class CodeGenInterface
56 CodeGenInterface(Compiler* theCompiler);
57 virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode) = 0;
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.
64 virtual void genSpillVar(GenTree* tree) = 0;
65 #endif // !LEGACY_BACKEND
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;
73 return m_genAlignLoops;
75 void setAlignLoops(bool value)
77 m_genAlignLoops = value;
80 // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
82 virtual bool genCreateAddrMode(GenTree* addr,
93 bool nogen = false) = 0;
95 void genCalcFrameSize();
100 RegState intRegState;
101 RegState floatRegState;
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;
108 #ifdef LEGACY_BACKEND
109 void trashReg(regNumber reg)
111 regTracker.rsTrackRegTrash(reg);
117 bool m_genAlignLoops;
120 static const BYTE instInfo[INS_count];
122 #define INST_FP 0x01 // is it a FP instruction?
124 static bool instIsFP(instruction ins);
126 //-------------------------------------------------------------------------
127 // Liveness-related fields & methods
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
136 VARSET_TP genTempOldLife;
140 VARSET_TP genLastLiveSet; // A one element map (genLastLiveSet-> genLastLiveMask)
141 regMaskTP genLastLiveMask; // these two are used in genLiveMask
143 regMaskTP genGetRegMask(const LclVarDsc* varDsc);
144 regMaskTP genGetRegMask(GenTree* tree);
146 void genUpdateLife(GenTree* tree);
147 void genUpdateLife(VARSET_VALARG_TP newLife);
149 #ifdef LEGACY_BACKEND
150 regMaskTP genLiveMask(GenTree* tree);
151 regMaskTP genLiveMask(VARSET_VALARG_TP liveSet);
155 bool genUseOptimizedWriteBarriers(GCInfo::WriteBarrierForm wbf);
156 bool genUseOptimizedWriteBarriers(GenTree* tgt, GenTree* assignVal);
157 CorInfoHelpFunc genWriteBarrierHelperForWriteBarrierForm(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
159 // The following property indicates whether the current method sets up
160 // an explicit stack frame or not.
162 PhasedVar<bool> m_cgFramePointerUsed;
165 bool isFramePointerUsed() const
167 return m_cgFramePointerUsed;
169 void setFramePointerUsed(bool value)
171 m_cgFramePointerUsed = value;
173 void resetFramePointerUsedWritePhase()
175 m_cgFramePointerUsed.ResetWritePhase();
178 // The following property indicates whether the current method requires
179 // an explicit frame. Does not prohibit double alignment of the stack.
181 PhasedVar<bool> m_cgFrameRequired;
184 bool isFrameRequired() const
186 return m_cgFrameRequired;
188 void setFrameRequired(bool value)
190 m_cgFrameRequired = value;
194 int genCallerSPtoFPdelta();
195 int genCallerSPtoInitialSPdelta();
196 int genSPtoFPdelta();
197 int genTotalFrameSize();
199 regNumber genGetThisArgReg(GenTreeCall* call) const;
201 #ifdef _TARGET_XARCH_
202 #ifdef _TARGET_AMD64_
203 // There are no reloc hints on x86
204 unsigned short genAddrRelocTypeHint(size_t addr);
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);
213 // If both isFramePointerRequired() and isFrameRequired() are false, the method is eligible
214 // for Frame-Pointer-Omission (FPO).
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
221 PhasedVar<bool> m_cgFramePointerRequired;
224 bool isFramePointerRequired() const
226 return m_cgFramePointerRequired;
229 void setFramePointerRequired(bool value)
231 m_cgFramePointerRequired = value;
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()
240 m_cgFramePointerRequired.ResetWritePhase();
243 void setFramePointerRequiredEH(bool value);
245 void setFramePointerRequiredGCInfo(bool value)
247 #ifdef JIT32_GCENCODER
248 m_cgFramePointerRequired = value;
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).
257 bool doDoubleAlign() const
259 return m_cgDoubleAlign;
261 void setDoubleAlign(bool value)
263 m_cgDoubleAlign = value;
265 bool doubleAlignOrFramePointerUsed() const
267 return isFramePointerUsed() || doDoubleAlign();
271 bool m_cgDoubleAlign;
272 #else // !DOUBLE_ALIGN
275 bool doubleAlignOrFramePointerUsed() const
277 return isFramePointerUsed();
280 #endif // !DOUBLE_ALIGN
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.
288 return genInterruptibleUsed;
292 bool genInterruptibleUsed;
296 #if FEATURE_STACK_FP_X87
297 FlatFPStateX87 compCurFPState;
298 unsigned genFPregCnt; // count of current FP reg. vars (including dead but unpopped ones)
300 void SetRegVarFloat(regNumber reg, var_types type, LclVarDsc* varDsc);
302 void inst_FN(instruction ins, unsigned stk);
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
309 unsigned genFPstkLevel;
311 void genResetFPstkLevel(unsigned newValue = 0);
312 unsigned genGetFPstkLevel();
313 FlatFPStateX87* FlatFPAllocFPState(FlatFPStateX87* pInitFrom = 0);
315 void genIncrementFPstkLevel(unsigned inc = 1);
316 void genDecrementFPstkLevel(unsigned dec = 1);
318 static const char* regVarNameStackFP(regNumber reg);
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
325 void FlatFPX87_MoveToTOS(FlatFPStateX87* pState, unsigned iVirtual, bool bEmitCode = true);
326 void FlatFPX87_SwapStack(FlatFPStateX87* pState, unsigned i, unsigned j, bool bEmitCode = true);
328 #endif // FEATURE_STACK_FP_X87
330 #ifndef LEGACY_BACKEND
331 regNumber genGetAssignedReg(GenTree* tree);
332 #endif // !LEGACY_BACKEND
334 #ifdef LEGACY_BACKEND
335 // Changes GT_LCL_VAR nodes to GT_REG_VAR nodes if possible.
336 bool genMarkLclVar(GenTree* tree);
338 void genBashLclVar(GenTree* tree, unsigned varNum, LclVarDsc* varDsc);
339 #endif // LEGACY_BACKEND
342 unsigned InferStructOpSizeAlign(GenTree* op, unsigned* alignmentWB);
343 unsigned InferOpSizeAlign(GenTree* op, unsigned* alignmentWB);
345 void genMarkTreeInReg(GenTree* tree, regNumber reg);
346 #if CPU_LONG_USES_REGPAIR
347 void genMarkTreeInRegPair(GenTree* tree, regPairNo regPair);
349 // Methods to abstract target information
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);
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);
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);
367 #ifdef LEGACY_BACKEND
368 void SpillFloat(regNumber reg, bool bIsCall = false);
369 #endif // LEGACY_BACKEND
371 // The following method is used by xarch emitter for handling contained tree temps.
372 TempDsc* getSpillTempDsc(GenTree* tree);
375 emitter* getEmitter()
381 emitter* m_cgEmitter;
385 DisAssembler& getDisAssembler()
391 DisAssembler m_cgDisAsm;
392 #endif // LATE_DISASM
396 void setVerbose(bool value)
401 #ifdef LEGACY_BACKEND
403 int genStressFloat();
404 regMaskTP genStressLockedMaskFloat();
405 #endif // LEGACY_BACKEND
408 // The following is set to true if we've determined that the current method
409 // is to be fully interruptible.
412 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
413 bool getInterruptible()
415 return m_cgInterruptible;
417 void setInterruptible(bool value)
419 m_cgInterruptible = value;
422 #ifdef _TARGET_ARMARCH_
423 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
424 bool getHasTailCalls()
426 return m_cgHasTailCalls;
428 void setHasTailCalls(bool value)
430 m_cgHasTailCalls = value;
432 #endif // _TARGET_ARMARCH_
435 bool m_cgInterruptible;
436 #ifdef _TARGET_ARMARCH_
437 bool m_cgHasTailCalls;
438 #endif // _TARGET_ARMARCH_
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)
447 __declspec(property(get = doFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
448 bool doFullPtrRegMap()
450 return m_cgFullPtrRegMap;
452 void setFullPtrRegMap(bool value)
454 m_cgFullPtrRegMap = value;
458 bool m_cgFullPtrRegMap;
461 virtual void siUpdate() = 0;
465 virtual const char* siRegVarName(size_t offs, size_t size, unsigned reg) = 0;
467 virtual const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs) = 0;
468 #endif // LATE_DISASM
471 #endif // _CODEGEN_INTERFACE_H_