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