summaryrefslogtreecommitdiff
path: root/src/jit/codegeninterface.h
blob: 672c51706dbc459425d68e78144a4e00abd6f449 (plain)
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
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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
{
    unsigned            rsCurRegArgNum;             // current argument register (for caller)
    unsigned            rsCalleeRegArgNum;          // total number of incoming register arguments
    regMaskTP           rsCalleeRegArgMaskLiveIn;   // mask of register arguments (live on entry to method)
    bool                rsIsFloat;
    unsigned            rsMaxRegArgNum;             // maximum register argument number + 1 (that is, exclusive of end of range)
};

//-------------------- 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);




    // 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:
    regNumber           getFramePointerReg()            { if (isFramePointerUsed())
                                                              return REG_FPBASE;
                                                          else
                                                              return REG_SPBASE; }

    int                 genCallerSPtoFPdelta();
    int                 genCallerSPtoInitialSPdelta();
    int                 genSPtoFPdelta();
    int                 genTotalFrameSize();

    regNumber           genGetThisArgReg    (GenTreePtr     call);

#ifdef _TARGET_XARCH_
    bool                genAddrShouldUsePCRel(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()                  { return m_cgDoubleAlign; }
    void                setDoubleAlign(bool value)       { m_cgDoubleAlign = value; }
    bool                doubleAlignOrFramePointerUsed()      { return isFramePointerUsed() || doDoubleAlign(); }
private:
    bool                m_cgDoubleAlign;
#else // !DOUBLE_ALIGN
public:
    bool                doubleAlignOrFramePointerUsed()      { 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);
    void                genMarkTreeInRegPair    (GenTreePtr tree, regPairNo regPair);

    // 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

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_