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