Remove JIT LEGACY_BACKEND code (#18064)
[platform/upstream/coreclr.git] / src / jit / codegen.h
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 class contains all the data & functionality for code generation
7 // of a method, except for the target-specific elements, which are
8 // primarily in the Target class.
9 //
10
11 #ifndef _CODEGEN_H_
12 #define _CODEGEN_H_
13 #include "compiler.h" // temporary??
14 #include "codegeninterface.h"
15 #include "regset.h"
16 #include "jitgcinfo.h"
17
18 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
19 #define FOREACH_REGISTER_FILE(file)                                                                                    \
20     for ((file) = &(this->intRegState); (file) != NULL;                                                                \
21          (file) = ((file) == &(this->intRegState)) ? &(this->floatRegState) : NULL)
22 #else
23 #define FOREACH_REGISTER_FILE(file) (file) = &(this->intRegState);
24 #endif
25
26 class CodeGen : public CodeGenInterface
27 {
28     friend class emitter;
29     friend class DisAssembler;
30
31 public:
32     // This could use further abstraction
33     CodeGen(Compiler* theCompiler);
34
35     virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode);
36     // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
37     // move it to Lower
38     virtual bool genCreateAddrMode(GenTree*  addr,
39                                    int       mode,
40                                    bool      fold,
41                                    regMaskTP regMask,
42                                    bool*     revPtr,
43                                    GenTree** rv1Ptr,
44                                    GenTree** rv2Ptr,
45 #if SCALED_ADDR_MODES
46                                    unsigned* mulPtr,
47 #endif
48                                    unsigned* cnsPtr,
49                                    bool      nogen = false);
50
51 private:
52 #if defined(_TARGET_XARCH_)
53     // Bit masks used in negating a float or double number.
54     // This is to avoid creating more than one data constant for these bitmasks when a
55     // method has more than one GT_NEG operation on floating point values.
56     CORINFO_FIELD_HANDLE negBitmaskFlt;
57     CORINFO_FIELD_HANDLE negBitmaskDbl;
58
59     // Bit masks used in computing Math.Abs() of a float or double number.
60     CORINFO_FIELD_HANDLE absBitmaskFlt;
61     CORINFO_FIELD_HANDLE absBitmaskDbl;
62
63     // Bit mask used in U8 -> double conversion to adjust the result.
64     CORINFO_FIELD_HANDLE u8ToDblBitmask;
65
66     // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
67     void genSSE2BitwiseOp(GenTree* treeNode);
68
69     // Generates SSE41 code for the given tree as a round operation
70     void genSSE41RoundOp(GenTreeOp* treeNode);
71 #endif // defined(_TARGET_XARCH_)
72
73     void genPrepForCompiler();
74
75     void genPrepForEHCodegen();
76
77     inline RegState* regStateForType(var_types t)
78     {
79         return varTypeIsFloating(t) ? &floatRegState : &intRegState;
80     }
81     inline RegState* regStateForReg(regNumber reg)
82     {
83         return genIsValidFloatReg(reg) ? &floatRegState : &intRegState;
84     }
85
86     regNumber genFramePointerReg()
87     {
88         if (isFramePointerUsed())
89         {
90             return REG_FPBASE;
91         }
92         else
93         {
94             return REG_SPBASE;
95         }
96     }
97
98     enum CompareKind
99     {
100         CK_SIGNED,
101         CK_UNSIGNED,
102         CK_LOGICAL
103     };
104     static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);
105
106     // For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
107     // The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
108     // 'true' label or a 'false' label.
109     //
110     // 'true' label corresponds to jump target of the current basic block i.e. the target to
111     // branch to on compare condition being true.  'false' label corresponds to the target to
112     // branch to on condition being false.
113     static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
114
115     static bool genShouldRoundFP();
116
117     GenTreeIndir indirForm(var_types type, GenTree* base);
118
119     GenTreeIntCon intForm(var_types type, ssize_t value);
120
121     void genRangeCheck(GenTree* node);
122
123     void genLockedInstructions(GenTreeOp* node);
124
125     //-------------------------------------------------------------------------
126     // Register-related methods
127
128     void rsInit();
129
130 #ifdef REG_OPT_RSVD
131     // On some targets such as the ARM we may need to have an extra reserved register
132     //  that is used when addressing stack based locals and stack based temps.
133     //  This method returns the regNumber that should be used when an extra register
134     //  is needed to access the stack based locals and stack based temps.
135     //
136     regNumber rsGetRsvdReg()
137     {
138         // We should have already added this register to the mask
139         //  of reserved registers in regSet.rdMaskResvd
140         noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
141
142         return REG_OPT_RSVD;
143     }
144 #endif // REG_OPT_RSVD
145
146     //-------------------------------------------------------------------------
147
148     bool     genUseBlockInit;  // true if we plan to block-initialize the local stack frame
149     unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
150
151     //  Keeps track of how many bytes we've pushed on the processor's stack.
152     //
153     unsigned genStackLevel;
154
155     void SubtractStackLevel(unsigned adjustment)
156     {
157         assert(genStackLevel >= adjustment);
158         unsigned newStackLevel = genStackLevel - adjustment;
159         if (genStackLevel != newStackLevel)
160         {
161             JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
162         }
163         genStackLevel = newStackLevel;
164     }
165
166     void AddStackLevel(unsigned adjustment)
167     {
168         unsigned newStackLevel = genStackLevel + adjustment;
169         if (genStackLevel != newStackLevel)
170         {
171             JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
172         }
173         genStackLevel = newStackLevel;
174     }
175
176     void SetStackLevel(unsigned newStackLevel)
177     {
178         if (genStackLevel != newStackLevel)
179         {
180             JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
181         }
182         genStackLevel = newStackLevel;
183     }
184
185 #if STACK_PROBES
186     // Stack Probes
187     bool genNeedPrologStackProbe;
188
189     void genGenerateStackProbe();
190 #endif
191
192     //-------------------------------------------------------------------------
193
194     void genReportEH();
195
196     // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
197     // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
198     // the GC info.  Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
199     // to be the sizes of the prolog and epilog, respectively.  In DEBUG, makes a check involving the
200     // "codePtr", assumed to be a pointer to the start of the generated code.
201     CLANG_FORMAT_COMMENT_ANCHOR;
202
203 #ifdef JIT32_GCENCODER
204     void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
205     void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
206                                        unsigned prologSize,
207                                        unsigned epilogSize DEBUGARG(void* codePtr));
208 #else  // !JIT32_GCENCODER
209     void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
210     void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
211 #endif // !JIT32_GCENCODER
212
213     /**************************************************************************
214      *                          PROTECTED
215      *************************************************************************/
216
217 protected:
218     // the current (pending) label ref, a label which has been referenced but not yet seen
219     BasicBlock* genPendingCallLabel;
220
221 #ifdef DEBUG
222     // Last instr we have displayed for dspInstrs
223     unsigned genCurDispOffset;
224
225     static const char* genInsName(instruction ins);
226 #endif // DEBUG
227
228     //-------------------------------------------------------------------------
229
230     // JIT-time constants for use in multi-dimensional array code generation.
231     unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
232     unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
233
234 #ifdef DEBUG
235     static const char* genSizeStr(emitAttr size);
236
237     void genStressRegs(GenTree* tree);
238 #endif // DEBUG
239
240     void genCodeForBBlist();
241
242 public:
243     void genSpillVar(GenTree* tree);
244
245 protected:
246     void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
247
248     void genGCWriteBarrier(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
249
250     BasicBlock* genCreateTempLabel();
251
252     void genDefineTempLabel(BasicBlock* label);
253
254     void genAdjustSP(ssize_t delta);
255
256     void genAdjustStackLevel(BasicBlock* block);
257
258     void genExitCode(BasicBlock* block);
259
260     void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTree* failBlk = nullptr);
261
262     void genCheckOverflow(GenTree* tree);
263
264     //-------------------------------------------------------------------------
265     //
266     // Prolog/epilog generation
267     //
268     //-------------------------------------------------------------------------
269
270     //
271     // Prolog functions and data (there are a few exceptions for more generally used things)
272     //
273
274     void genEstablishFramePointer(int delta, bool reportUnwindData);
275     void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
276     void genEnregisterIncomingStackArgs();
277     void genCheckUseBlockInit();
278 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
279     void genClearStackVec3ArgUpperBits();
280 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
281
282 #if defined(_TARGET_ARM64_)
283     bool genInstrWithConstant(instruction ins,
284                               emitAttr    attr,
285                               regNumber   reg1,
286                               regNumber   reg2,
287                               ssize_t     imm,
288                               regNumber   tmpReg,
289                               bool        inUnwindRegion = false);
290
291     void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
292
293     void genPrologSaveRegPair(regNumber reg1,
294                               regNumber reg2,
295                               int       spOffset,
296                               int       spDelta,
297                               bool      lastSavedWasPreviousPair,
298                               regNumber tmpReg,
299                               bool*     pTmpRegIsZero);
300
301     void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
302
303     void genEpilogRestoreRegPair(
304         regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
305
306     void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
307
308     void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
309
310     void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
311
312     void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
313 #else
314     void genPushCalleeSavedRegisters();
315 #endif
316
317     void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
318
319 #if defined(_TARGET_ARM_)
320
321     void genPushFltRegs(regMaskTP regMask);
322     void genPopFltRegs(regMaskTP regMask);
323     regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
324
325     regMaskTP genJmpCallArgMask();
326
327     void genFreeLclFrame(unsigned           frameSize,
328                          /* IN OUT */ bool* pUnwindStarted,
329                          bool               jmpEpilog);
330
331     void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
332     void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
333     void genMov32RelocatableImmediate(emitAttr size, size_t value, regNumber reg);
334
335     bool genUsedPopToReturn; // True if we use the pop into PC to return,
336                              // False if we didn't and must branch to LR to return.
337
338     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
339     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
340     // same.
341     struct FuncletFrameInfoDsc
342     {
343         regMaskTP fiSaveRegs;                  // Set of registers saved in the funclet prolog (includes LR)
344         unsigned  fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
345         unsigned  fiSpDelta;                   // Stack pointer delta
346         unsigned  fiPSP_slot_SP_offset;        // PSP slot offset from SP
347         int       fiPSP_slot_CallerSP_offset;  // PSP slot offset from Caller SP
348     };
349
350     FuncletFrameInfoDsc genFuncletInfo;
351
352 #elif defined(_TARGET_ARM64_)
353
354     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
355     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
356     // same.
357     struct FuncletFrameInfoDsc
358     {
359         regMaskTP fiSaveRegs;                // Set of callee-saved registers saved in the funclet prolog (includes LR)
360         int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
361                                              // (negative)
362         int fiSP_to_FPLR_save_delta;         // FP/LR register save offset from SP (positive)
363         int fiSP_to_PSP_slot_delta;          // PSP slot offset from SP (positive)
364         int fiSP_to_CalleeSave_delta;        // First callee-saved register slot offset from SP (positive)
365         int fiCallerSP_to_PSP_slot_delta;    // PSP slot offset from Caller SP (negative)
366         int fiFrameType;                     // Funclet frame types are numbered. See genFuncletProlog() for details.
367         int fiSpDelta1;                      // Stack pointer delta 1 (negative)
368         int fiSpDelta2;                      // Stack pointer delta 2 (negative)
369     };
370
371     FuncletFrameInfoDsc genFuncletInfo;
372
373 #elif defined(_TARGET_AMD64_)
374
375     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
376     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
377     // same.
378     struct FuncletFrameInfoDsc
379     {
380         unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
381         unsigned fiSpDelta;                        // Stack pointer delta
382         int      fiPSP_slot_InitialSP_offset;      // PSP slot offset from Initial-SP
383     };
384
385     FuncletFrameInfoDsc genFuncletInfo;
386
387 #endif // _TARGET_AMD64_
388
389 #if defined(_TARGET_XARCH_)
390
391     // Save/Restore callee saved float regs to stack
392     void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
393     void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
394     // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
395     void genVzeroupperIfNeeded(bool check256bitOnly = true);
396
397 #endif // _TARGET_XARCH_
398
399     void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
400
401     regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
402
403     void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
404
405     void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
406
407     void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
408
409     void genFinalizeFrame();
410
411 #ifdef PROFILING_SUPPORTED
412     void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
413     void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
414 #endif // PROFILING_SUPPORTED
415
416     void genPrologPadForReJit();
417
418     // clang-format off
419     void genEmitCall(int                   callType,
420                      CORINFO_METHOD_HANDLE methHnd,
421                      INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
422                      void*                 addr
423                      X86_ARG(ssize_t argSize),
424                      emitAttr              retSize
425                      MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
426                      IL_OFFSETX            ilOffset,
427                      regNumber             base   = REG_NA,
428                      bool                  isJump = false,
429                      bool                  isNoGC = false);
430     // clang-format on
431
432     // clang-format off
433     void genEmitCall(int                   callType,
434                      CORINFO_METHOD_HANDLE methHnd,
435                      INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
436                      GenTreeIndir*         indir
437                      X86_ARG(ssize_t argSize),
438                      emitAttr              retSize
439                      MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
440                      IL_OFFSETX            ilOffset);
441     // clang-format on
442
443     //
444     // Epilog functions
445     //
446     CLANG_FORMAT_COMMENT_ANCHOR;
447
448 #if defined(_TARGET_ARM_)
449     bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
450 #endif
451
452 #if defined(_TARGET_ARM64_)
453
454     void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
455
456 #else // !defined(_TARGET_ARM64_)
457
458     void genPopCalleeSavedRegisters(bool jmpEpilog = false);
459
460 #endif // !defined(_TARGET_ARM64_)
461
462     //
463     // Common or driving functions
464     //
465
466     void genReserveProlog(BasicBlock* block); // currently unused
467     void genReserveEpilog(BasicBlock* block);
468     void genFnProlog();
469     void genFnEpilog(BasicBlock* block);
470
471 #if FEATURE_EH_FUNCLETS
472
473     void genReserveFuncletProlog(BasicBlock* block);
474     void genReserveFuncletEpilog(BasicBlock* block);
475     void genFuncletProlog(BasicBlock* block);
476     void genFuncletEpilog();
477     void genCaptureFuncletPrologEpilogInfo();
478
479     void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
480
481     void genUpdateCurrentFunclet(BasicBlock* block);
482 #if defined(_TARGET_ARM_)
483     void genInsertNopForUnwinder(BasicBlock* block);
484 #endif
485
486 #else // FEATURE_EH_FUNCLETS
487
488     // This is a no-op when there are no funclets!
489     void genUpdateCurrentFunclet(BasicBlock* block)
490     {
491         return;
492     }
493
494 #if defined(_TARGET_ARM_)
495     void genInsertNopForUnwinder(BasicBlock* block)
496     {
497         return;
498     }
499 #endif
500
501 #endif // FEATURE_EH_FUNCLETS
502
503     void genGeneratePrologsAndEpilogs();
504
505 #if defined(DEBUG) && defined(_TARGET_ARM64_)
506     void genArm64EmitterUnitTests();
507 #endif
508
509 #if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
510     void genAmd64EmitterUnitTests();
511 #endif
512
513     //-------------------------------------------------------------------------
514     //
515     // End prolog/epilog generation
516     //
517     //-------------------------------------------------------------------------
518
519     void      genSinglePush();
520     void      genSinglePop();
521     regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
522     void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
523
524 /*
525 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
526 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
527 XX                                                                           XX
528 XX                           Debugging Support                               XX
529 XX                                                                           XX
530 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
531 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
532 */
533
534 #ifdef DEBUG
535     void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
536     void genIPmappingListDisp();
537 #endif // DEBUG
538
539     void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
540     void genIPmappingAddToFront(IL_OFFSETX offset);
541     void genIPmappingGen();
542
543     void genEnsureCodeEmitted(IL_OFFSETX offsx);
544
545     //-------------------------------------------------------------------------
546     // scope info for the variables
547
548     void genSetScopeInfo(unsigned            which,
549                          UNATIVE_OFFSET      startOffs,
550                          UNATIVE_OFFSET      length,
551                          unsigned            varNum,
552                          unsigned            LVnum,
553                          bool                avail,
554                          Compiler::siVarLoc& loc);
555
556     void genSetScopeInfo();
557
558     void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
559
560 protected:
561     /*
562     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
563     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
564     XX                                                                           XX
565     XX                           ScopeInfo                                       XX
566     XX                                                                           XX
567     XX  Keeps track of the scopes during code-generation.                        XX
568     XX  This is used to translate the local-variable debugging information       XX
569     XX  from IL offsets to native code offsets.                                  XX
570     XX                                                                           XX
571     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
572     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
573     */
574
575     /*****************************************************************************/
576     /*****************************************************************************
577      *                              ScopeInfo
578      *
579      * This class is called during code gen at block-boundaries, and when the
580      * set of live variables changes. It keeps track of the scope of the variables
581      * in terms of the native code PC.
582      */
583
584 public:
585     void siInit();
586
587     void siBeginBlock(BasicBlock* block);
588
589     void siEndBlock(BasicBlock* block);
590
591     virtual void siUpdate();
592
593     void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
594
595     void siCloseAllOpenScopes();
596
597 #ifdef DEBUG
598     void siDispOpenScopes();
599 #endif
600
601     /**************************************************************************
602      *                          PROTECTED
603      *************************************************************************/
604
605 protected:
606     struct siScope
607     {
608         emitLocation scStartLoc; // emitter location of start of scope
609         emitLocation scEndLoc;   // emitter location of end of scope
610
611         unsigned scVarNum; // index into lvaTable
612         unsigned scLVnum;  // 'which' in eeGetLVinfo()
613
614         unsigned scStackLevel; // Only for stk-vars
615         bool scAvailable : 1;  // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
616
617         siScope* scPrev;
618         siScope* scNext;
619     };
620
621     siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
622
623     unsigned siScopeCnt;
624
625     VARSET_TP siLastLife; // Life at last call to siUpdate()
626
627     // Tracks the last entry for each tracked register variable
628
629     siScope* siLatestTrackedScopes[lclMAX_TRACKED];
630
631     IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
632
633 #if FEATURE_EH_FUNCLETS
634     bool siInFuncletRegion; // Have we seen the start of the funclet region?
635 #endif                      // FEATURE_EH_FUNCLETS
636
637     // Functions
638
639     siScope* siNewScope(unsigned LVnum, unsigned varNum);
640
641     void siRemoveFromOpenScopeList(siScope* scope);
642
643     void siEndTrackedScope(unsigned varIndex);
644
645     void siEndScope(unsigned varNum);
646
647     void siEndScope(siScope* scope);
648
649 #ifdef DEBUG
650     bool siVerifyLocalVarTab();
651 #endif
652
653 #ifdef LATE_DISASM
654 public:
655     /* virtual */
656     const char* siRegVarName(size_t offs, size_t size, unsigned reg);
657
658     /* virtual */
659     const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
660 #endif // LATE_DISASM
661
662 public:
663     /*
664     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
665     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
666     XX                                                                           XX
667     XX                          PrologScopeInfo                                  XX
668     XX                                                                           XX
669     XX We need special handling in the prolog block, as the parameter variables  XX
670     XX may not be in the same position described by genLclVarTable - they all    XX
671     XX start out on the stack                                                    XX
672     XX                                                                           XX
673     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
674     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
675     */
676
677 public:
678     void psiBegProlog();
679
680     void psiAdjustStackLevel(unsigned size);
681
682     void psiMoveESPtoEBP();
683
684     void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
685
686     void psiMoveToStack(unsigned varNum);
687
688     void psiEndProlog();
689
690     /**************************************************************************
691      *                          PROTECTED
692      *************************************************************************/
693
694 protected:
695     struct psiScope
696     {
697         emitLocation scStartLoc; // emitter location of start of scope
698         emitLocation scEndLoc;   // emitter location of end of scope
699
700         unsigned scSlotNum; // index into lclVarTab
701         unsigned scLVnum;   // 'which' in eeGetLVinfo()
702
703         bool scRegister;
704
705         union {
706             struct
707             {
708                 regNumberSmall scRegNum;
709
710                 // Used for:
711                 //  - "other half" of long var on architectures with 32 bit size registers - x86.
712                 //  - for System V structs it stores the second register
713                 //    used to pass a register passed struct.
714                 regNumberSmall scOtherReg;
715             } u1;
716
717             struct
718             {
719                 regNumberSmall scBaseReg;
720                 NATIVE_OFFSET  scOffset;
721             } u2;
722         };
723
724         psiScope* scPrev;
725         psiScope* scNext;
726     };
727
728     psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
729
730     unsigned psiScopeCnt;
731
732     // Implementation Functions
733
734     psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
735
736     void psiEndPrologScope(psiScope* scope);
737
738     void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
739
740 /*****************************************************************************
741  *                        TrnslLocalVarInfo
742  *
743  * This struct holds the LocalVarInfo in terms of the generated native code
744  * after a call to genSetScopeInfo()
745  */
746
747 #ifdef DEBUG
748
749     struct TrnslLocalVarInfo
750     {
751         unsigned           tlviVarNum;
752         unsigned           tlviLVnum;
753         VarName            tlviName;
754         UNATIVE_OFFSET     tlviStartPC;
755         size_t             tlviLength;
756         bool               tlviAvailable;
757         Compiler::siVarLoc tlviVarLoc;
758     };
759
760     // Array of scopes of LocalVars in terms of native code
761
762     TrnslLocalVarInfo* genTrnslLocalVarInfo;
763     unsigned           genTrnslLocalVarCount;
764 #endif
765
766 #include "codegenlinear.h"
767
768     /*
769     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
770     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
771     XX                                                                           XX
772     XX                           Instruction                                     XX
773     XX                                                                           XX
774     XX  The interface to generate a machine-instruction.                         XX
775     XX  Currently specific to x86                                                XX
776     XX  TODO-Cleanup: Consider factoring this out of CodeGen                     XX
777     XX                                                                           XX
778     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
779     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
780     */
781
782 public:
783     void instInit();
784
785     void instGen(instruction ins);
786 #ifdef _TARGET_XARCH_
787     void instNop(unsigned size);
788 #endif
789
790     void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
791
792     void inst_SET(emitJumpKind condition, regNumber reg);
793
794     void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
795
796     void inst_RV_RV(instruction ins,
797                     regNumber   reg1,
798                     regNumber   reg2,
799                     var_types   type  = TYP_I_IMPL,
800                     emitAttr    size  = EA_UNKNOWN,
801                     insFlags    flags = INS_FLAGS_DONT_CARE);
802
803     void inst_RV_RV_RV(instruction ins,
804                        regNumber   reg1,
805                        regNumber   reg2,
806                        regNumber   reg3,
807                        emitAttr    size,
808                        insFlags    flags = INS_FLAGS_DONT_CARE);
809
810     void inst_IV(instruction ins, int val);
811     void inst_IV_handle(instruction ins, int val);
812     void inst_FS(instruction ins, unsigned stk = 0);
813
814     void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
815
816     void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
817     void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
818
819     void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
820     void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
821
822     void inst_RV_ST(
823         instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
824     void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
825
826     void instEmit_indCall(GenTreeCall* call,
827                           size_t       argSize,
828                           emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
829
830     void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
831
832     void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
833
834     void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
835
836     void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
837
838     void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
839
840     void inst_TT_RV(instruction ins,
841                     GenTree*    tree,
842                     regNumber   reg,
843                     unsigned    offs  = 0,
844                     emitAttr    size  = EA_UNKNOWN,
845                     insFlags    flags = INS_FLAGS_DONT_CARE);
846
847     void inst_TT_IV(instruction ins,
848                     GenTree*    tree,
849                     ssize_t     val,
850                     unsigned    offs  = 0,
851                     emitAttr    size  = EA_UNKNOWN,
852                     insFlags    flags = INS_FLAGS_DONT_CARE);
853
854     void inst_RV_AT(instruction ins,
855                     emitAttr    size,
856                     var_types   type,
857                     regNumber   reg,
858                     GenTree*    tree,
859                     unsigned    offs  = 0,
860                     insFlags    flags = INS_FLAGS_DONT_CARE);
861
862     void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
863
864     void inst_RV_TT(instruction ins,
865                     regNumber   reg,
866                     GenTree*    tree,
867                     unsigned    offs  = 0,
868                     emitAttr    size  = EA_UNKNOWN,
869                     insFlags    flags = INS_FLAGS_DONT_CARE);
870
871     void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
872
873     void inst_FS_TT(instruction ins, GenTree* tree);
874
875     void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
876
877     void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
878
879     void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
880
881     void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
882
883 #if defined(_TARGET_XARCH_)
884     void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
885 #endif
886
887     void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
888
889     void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
890
891     void inst_mov_RV_ST(regNumber reg, GenTree* tree);
892
893     void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
894
895     void inst_set_SV_var(GenTree* tree);
896
897 #ifdef _TARGET_ARM_
898     bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
899     bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
900     bool arm_Valid_Imm_For_Alu(ssize_t imm);
901     bool arm_Valid_Imm_For_Mov(ssize_t imm);
902     bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
903     bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
904     bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
905     bool arm_Valid_Imm_For_BL(ssize_t addr);
906
907     bool ins_Writes_Dest(instruction ins);
908 #endif
909
910     bool isMoveIns(instruction ins);
911     instruction ins_Move_Extend(var_types srcType, bool srcInReg);
912
913     instruction ins_Copy(var_types dstType);
914     instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
915     instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
916     static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
917     static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
918     instruction ins_FloatConv(var_types to, var_types from);
919     instruction ins_FloatCompare(var_types type);
920     instruction ins_MathOp(genTreeOps oper, var_types type);
921     instruction ins_FloatSqrt(var_types type);
922
923     void instGen_Return(unsigned stkArgSize);
924
925 #ifdef _TARGET_ARM64_
926     void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
927 #else
928     void instGen_MemoryBarrier();
929 #endif
930
931     void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
932
933     void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
934
935     void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
936
937     void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
938
939     void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
940
941     void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
942
943     void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
944
945     void instGen_Store_Imm_Into_Lcl(
946         var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
947
948 #ifdef DEBUG
949     void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
950 #endif
951
952 #ifdef _TARGET_XARCH_
953     instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
954 #endif // _TARGET_XARCH_
955 };
956
957 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
958 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
959 XX                                                                           XX
960 XX                       Instruction                                         XX
961 XX                      Inline functions                                     XX
962 XX                                                                           XX
963 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
964 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
965 */
966
967 #ifdef _TARGET_XARCH_
968 /*****************************************************************************
969  *
970  *  Generate a floating-point instruction that has one operand given by
971  *  a tree (which has been made addressable).
972  */
973
974 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
975 {
976     assert(instIsFP(ins));
977
978     assert(varTypeIsFloating(tree->gtType));
979
980     inst_TT(ins, tree, 0);
981 }
982 #endif
983
984 /*****************************************************************************
985  *
986  *  Generate a "shift reg, cl" instruction.
987  */
988
989 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
990 {
991     inst_RV(ins, reg, type);
992 }
993
994 #endif // _CODEGEN_H_