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
|
// 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"
#include "treelifeupdater.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)
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;
// genSpillVar is called by compUpdateLifeVar.
// 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(GenTree* tree) = 0;
//-------------------------------------------------------------------------
// 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(GenTree* addr,
bool fold,
bool* revPtr,
GenTree** rv1Ptr,
GenTree** rv2Ptr,
#if SCALED_ADDR_MODES
unsigned* mulPtr,
#endif // SCALED_ADDR_MODES
ssize_t* cnsPtr) = 0;
void genCalcFrameSize();
GCInfo gcInfo;
RegSet regSet;
RegState intRegState;
RegState floatRegState;
protected:
Compiler* compiler;
bool m_genAlignLoops;
private:
#if defined(_TARGET_XARCH_)
static const insFlags instInfo[INS_count];
#elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
static const BYTE instInfo[INS_count];
#else
#error Unsupported target architecture
#endif
#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(GenTree* tree));
void genUpdateVarReg(LclVarDsc* varDsc, GenTree* tree);
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(GenTree* tree);
void genUpdateLife(GenTree* tree);
void genUpdateLife(VARSET_VALARG_TP newLife);
TreeLifeUpdater<true>* treeLifeUpdater;
public:
bool genUseOptimizedWriteBarriers(GCInfo::WriteBarrierForm wbf);
bool genUseOptimizedWriteBarriers(GenTree* tgt, GenTree* assignVal);
CorInfoHelpFunc genWriteBarrierHelperForWriteBarrierForm(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
// 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(GenTreeCall* call) const;
#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;
}
//------------------------------------------------------------------------
// resetWritePhaseForFramePointerRequired: Return m_cgFramePointerRequired into the write phase.
// It is used only before the first phase, that locks this value, currently it is LSRA.
// Use it if you want to skip checks that set this value to true if the value is already true.
void resetWritePhaseForFramePointerRequired()
{
m_cgFramePointerRequired.ResetWritePhase();
}
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:
unsigned InferStructOpSizeAlign(GenTree* op, unsigned* alignmentWB);
unsigned InferOpSizeAlign(GenTree* op, unsigned* alignmentWB);
void genMarkTreeInReg(GenTree* tree, regNumber reg);
// Methods to abstract target information
bool validImmForInstr(instruction ins, target_ssize_t val, insFlags flags = INS_FLAGS_DONT_CARE);
bool validDispForLdSt(target_ssize_t disp, var_types type);
bool validImmForAdd(target_ssize_t imm, insFlags flags);
bool validImmForAlu(target_ssize_t imm);
bool validImmForMov(target_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);
// 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;
#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;
}
#ifdef _TARGET_ARMARCH_
__declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
bool getHasTailCalls()
{
return m_cgHasTailCalls;
}
void setHasTailCalls(bool value)
{
m_cgHasTailCalls = value;
}
#endif // _TARGET_ARMARCH_
private:
bool m_cgInterruptible;
#ifdef _TARGET_ARMARCH_
bool m_cgHasTailCalls;
#endif // _TARGET_ARMARCH_
// 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;
public:
virtual void siUpdate() = 0;
#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_
|