Handle MovRelocatableImmediate on ARM32 as a special case (IF_T2_N3) (#19013)
[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                                    bool      fold,
40                                    bool*     revPtr,
41                                    GenTree** rv1Ptr,
42                                    GenTree** rv2Ptr,
43 #if SCALED_ADDR_MODES
44                                    unsigned* mulPtr,
45 #endif // SCALED_ADDR_MODES
46                                    ssize_t* cnsPtr);
47
48 private:
49 #if defined(_TARGET_XARCH_)
50     // Bit masks used in negating a float or double number.
51     // This is to avoid creating more than one data constant for these bitmasks when a
52     // method has more than one GT_NEG operation on floating point values.
53     CORINFO_FIELD_HANDLE negBitmaskFlt;
54     CORINFO_FIELD_HANDLE negBitmaskDbl;
55
56     // Bit masks used in computing Math.Abs() of a float or double number.
57     CORINFO_FIELD_HANDLE absBitmaskFlt;
58     CORINFO_FIELD_HANDLE absBitmaskDbl;
59
60     // Bit mask used in U8 -> double conversion to adjust the result.
61     CORINFO_FIELD_HANDLE u8ToDblBitmask;
62
63     // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
64     void genSSE2BitwiseOp(GenTree* treeNode);
65
66     // Generates SSE41 code for the given tree as a round operation
67     void genSSE41RoundOp(GenTreeOp* treeNode);
68 #endif // defined(_TARGET_XARCH_)
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(GenTree* 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 #ifdef _TARGET_XARCH_
122     void genCodeForLockAdd(GenTreeOp* node);
123 #endif
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, BYTE* addr, 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;
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     void genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree);
767     void genCodeForTreeNode(GenTree* treeNode);
768     void genCodeForBinary(GenTree* treeNode);
769
770 #if defined(_TARGET_X86_)
771     void genCodeForLongUMod(GenTreeOp* node);
772 #endif // _TARGET_X86_
773
774     void genCodeForDivMod(GenTreeOp* treeNode);
775     void genCodeForMul(GenTreeOp* treeNode);
776     void genCodeForMulHi(GenTreeOp* treeNode);
777     void genLeaInstruction(GenTreeAddrMode* lea);
778     void genSetRegToCond(regNumber dstReg, GenTree* tree);
779
780 #if defined(_TARGET_ARMARCH_)
781     void genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale);
782 #endif // _TARGET_ARMARCH_
783
784 #if defined(_TARGET_ARM_)
785     void genCodeForMulLong(GenTreeMultiRegOp* treeNode);
786 #endif // _TARGET_ARM_
787
788 #if !defined(_TARGET_64BIT_)
789     void genLongToIntCast(GenTree* treeNode);
790 #endif
791
792     void genIntToIntCast(GenTree* treeNode);
793     void genFloatToFloatCast(GenTree* treeNode);
794     void genFloatToIntCast(GenTree* treeNode);
795     void genIntToFloatCast(GenTree* treeNode);
796     void genCkfinite(GenTree* treeNode);
797     void genCodeForCompare(GenTreeOp* tree);
798     void genIntrinsic(GenTree* treeNode);
799     void genPutArgStk(GenTreePutArgStk* treeNode);
800     void genPutArgReg(GenTreeOp* tree);
801 #if FEATURE_ARG_SPLIT
802     void genPutArgSplit(GenTreePutArgSplit* treeNode);
803 #endif // FEATURE_ARG_SPLIT
804
805 #if defined(_TARGET_XARCH_)
806     unsigned getBaseVarForPutArgStk(GenTree* treeNode);
807 #endif // _TARGET_XARCH_
808
809     unsigned getFirstArgWithStackSlot();
810
811     void genCompareFloat(GenTree* treeNode);
812     void genCompareInt(GenTree* treeNode);
813
814 #ifdef FEATURE_SIMD
815     enum SIMDScalarMoveType{
816         SMT_ZeroInitUpper,                  // zero initlaize target upper bits
817         SMT_ZeroInitUpper_SrcHasUpperZeros, // zero initialize target upper bits; source upper bits are known to be zero
818         SMT_PreserveUpper                   // preserve target upper bits
819     };
820
821 #ifdef _TARGET_ARM64_
822     insOpts genGetSimdInsOpt(emitAttr size, var_types elementType);
823 #endif
824     instruction getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival = nullptr);
825     void genSIMDScalarMove(
826         var_types targetType, var_types type, regNumber target, regNumber src, SIMDScalarMoveType moveType);
827     void genSIMDZero(var_types targetType, var_types baseType, regNumber targetReg);
828     void genSIMDIntrinsicInit(GenTreeSIMD* simdNode);
829     void genSIMDIntrinsicInitN(GenTreeSIMD* simdNode);
830     void genSIMDIntrinsicInitArray(GenTreeSIMD* simdNode);
831     void genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode);
832     void genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode);
833     void genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode);
834     void genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode);
835     void genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode);
836     void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
837     void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
838     void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
839     void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
840     void genSIMDLo64BitConvert(SIMDIntrinsicID intrinsicID,
841                                var_types       simdType,
842                                var_types       baseType,
843                                regNumber       tmpReg,
844                                regNumber       tmpIntReg,
845                                regNumber       targetReg);
846     void genSIMDIntrinsic32BitConvert(GenTreeSIMD* simdNode);
847     void genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode);
848     void genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode);
849     void genSIMDExtractUpperHalf(GenTreeSIMD* simdNode, regNumber srcReg, regNumber tgtReg);
850     void genSIMDIntrinsicWiden(GenTreeSIMD* simdNode);
851     void genSIMDIntrinsic(GenTreeSIMD* simdNode);
852     void genSIMDCheck(GenTree* treeNode);
853
854     // TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires
855     // two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3
856     // values through an indirection. Note that Vector3 locals allocated on stack would have
857     // their size rounded to TARGET_POINTER_SIZE (which is 8 bytes on 64-bit targets) and hence
858     // Vector3 locals could be treated as TYP_SIMD16 while reading/writing.
859     void genStoreIndTypeSIMD12(GenTree* treeNode);
860     void genLoadIndTypeSIMD12(GenTree* treeNode);
861     void genStoreLclTypeSIMD12(GenTree* treeNode);
862     void genLoadLclTypeSIMD12(GenTree* treeNode);
863 #ifdef _TARGET_X86_
864     void genStoreSIMD12ToStack(regNumber operandReg, regNumber tmpReg);
865     void genPutArgStkSIMD12(GenTree* treeNode);
866 #endif // _TARGET_X86_
867 #endif // FEATURE_SIMD
868
869 #ifdef FEATURE_HW_INTRINSICS
870     void genHWIntrinsic(GenTreeHWIntrinsic* node);
871 #if defined(_TARGET_XARCH_)
872     void genHWIntrinsic_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
873     void genHWIntrinsic_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
874     void genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
875     void genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
876     void genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins);
877     void genHWIntrinsic_R_R_R_RM(
878         instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTree* op3);
879     void genSSEIntrinsic(GenTreeHWIntrinsic* node);
880     void genSSE2Intrinsic(GenTreeHWIntrinsic* node);
881     void genSSE41Intrinsic(GenTreeHWIntrinsic* node);
882     void genSSE42Intrinsic(GenTreeHWIntrinsic* node);
883     void genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node);
884     void genAESIntrinsic(GenTreeHWIntrinsic* node);
885     void genBMI1Intrinsic(GenTreeHWIntrinsic* node);
886     void genBMI2Intrinsic(GenTreeHWIntrinsic* node);
887     void genFMAIntrinsic(GenTreeHWIntrinsic* node);
888     void genLZCNTIntrinsic(GenTreeHWIntrinsic* node);
889     void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node);
890     void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node);
891     template <typename HWIntrinsicSwitchCaseBody>
892     void genHWIntrinsicJumpTableFallback(NamedIntrinsic            intrinsic,
893                                          regNumber                 nonConstImmReg,
894                                          regNumber                 baseReg,
895                                          regNumber                 offsReg,
896                                          HWIntrinsicSwitchCaseBody emitSwCase);
897 #endif // defined(_TARGET_XARCH_)
898 #if defined(_TARGET_ARM64_)
899     instruction getOpForHWIntrinsic(GenTreeHWIntrinsic* node, var_types instrType);
900     void genHWIntrinsicUnaryOp(GenTreeHWIntrinsic* node);
901     void genHWIntrinsicCrcOp(GenTreeHWIntrinsic* node);
902     void genHWIntrinsicSimdBinaryOp(GenTreeHWIntrinsic* node);
903     void genHWIntrinsicSimdExtractOp(GenTreeHWIntrinsic* node);
904     void genHWIntrinsicSimdInsertOp(GenTreeHWIntrinsic* node);
905     void genHWIntrinsicSimdSelectOp(GenTreeHWIntrinsic* node);
906     void genHWIntrinsicSimdSetAllOp(GenTreeHWIntrinsic* node);
907     void genHWIntrinsicSimdUnaryOp(GenTreeHWIntrinsic* node);
908     void genHWIntrinsicSimdBinaryRMWOp(GenTreeHWIntrinsic* node);
909     void genHWIntrinsicSimdTernaryRMWOp(GenTreeHWIntrinsic* node);
910     void genHWIntrinsicShaHashOp(GenTreeHWIntrinsic* node);
911     void genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node);
912     template <typename HWIntrinsicSwitchCaseBody>
913     void genHWIntrinsicSwitchTable(regNumber swReg, regNumber tmpReg, int swMax, HWIntrinsicSwitchCaseBody emitSwCase);
914 #endif // defined(_TARGET_XARCH_)
915 #endif // FEATURE_HW_INTRINSICS
916
917 #if !defined(_TARGET_64BIT_)
918
919     // CodeGen for Long Ints
920
921     void genStoreLongLclVar(GenTree* treeNode);
922
923 #endif // !defined(_TARGET_64BIT_)
924
925     void genProduceReg(GenTree* tree);
926     void genUnspillRegIfNeeded(GenTree* tree);
927     regNumber genConsumeReg(GenTree* tree);
928     void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
929     void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
930
931     void genConsumeIfReg(GenTree* tree)
932     {
933         if (!tree->isContained())
934         {
935             (void)genConsumeReg(tree);
936         }
937     }
938
939     void genRegCopy(GenTree* tree);
940     void genTransferRegGCState(regNumber dst, regNumber src);
941     void genConsumeAddress(GenTree* addr);
942     void genConsumeAddrMode(GenTreeAddrMode* mode);
943     void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
944     void genConsumeBlockSrc(GenTreeBlk* blkNode);
945     void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
946     void genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg);
947
948 #ifdef FEATURE_PUT_STRUCT_ARG_STK
949     void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode,
950                                    regNumber         dstReg,
951                                    regNumber         srcReg,
952                                    regNumber         sizeReg);
953 #endif // FEATURE_PUT_STRUCT_ARG_STK
954 #if FEATURE_ARG_SPLIT
955     void genConsumeArgSplitStruct(GenTreePutArgSplit* putArgNode);
956 #endif // FEATURE_ARG_SPLIT
957
958     void genConsumeRegs(GenTree* tree);
959     void genConsumeOperands(GenTreeOp* tree);
960     void genEmitGSCookieCheck(bool pushReg);
961     void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
962     void genCodeForShift(GenTree* tree);
963
964 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
965     void genCodeForShiftLong(GenTree* tree);
966 #endif
967
968 #ifdef _TARGET_XARCH_
969     void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
970     void genCodeForBT(GenTreeOp* bt);
971 #endif // _TARGET_XARCH_
972
973     void genCodeForCast(GenTreeOp* tree);
974     void genCodeForLclAddr(GenTree* tree);
975     void genCodeForIndexAddr(GenTreeIndexAddr* tree);
976     void genCodeForIndir(GenTreeIndir* tree);
977     void genCodeForNegNot(GenTree* tree);
978     void genCodeForLclVar(GenTreeLclVar* tree);
979     void genCodeForLclFld(GenTreeLclFld* tree);
980     void genCodeForStoreLclFld(GenTreeLclFld* tree);
981     void genCodeForStoreLclVar(GenTreeLclVar* tree);
982     void genCodeForReturnTrap(GenTreeOp* tree);
983     void genCodeForJcc(GenTreeCC* tree);
984     void genCodeForSetcc(GenTreeCC* setcc);
985     void genCodeForStoreInd(GenTreeStoreInd* tree);
986     void genCodeForSwap(GenTreeOp* tree);
987     void genCodeForCpObj(GenTreeObj* cpObjNode);
988     void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
989     void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
990     void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
991     void genCodeForPhysReg(GenTreePhysReg* tree);
992     void genCodeForNullCheck(GenTreeOp* tree);
993     void genCodeForCmpXchg(GenTreeCmpXchg* tree);
994
995     void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
996     void genAlignStackBeforeCall(GenTreeCall* call);
997     void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
998
999 #if defined(UNIX_X86_ABI)
1000
1001     unsigned curNestedAlignment; // Keep track of alignment adjustment required during codegen.
1002     unsigned maxNestedAlignment; // The maximum amount of alignment adjustment required.
1003
1004     void SubtractNestedAlignment(unsigned adjustment)
1005     {
1006         assert(curNestedAlignment >= adjustment);
1007         unsigned newNestedAlignment = curNestedAlignment - adjustment;
1008         if (curNestedAlignment != newNestedAlignment)
1009         {
1010             JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1011         }
1012         curNestedAlignment = newNestedAlignment;
1013     }
1014
1015     void AddNestedAlignment(unsigned adjustment)
1016     {
1017         unsigned newNestedAlignment = curNestedAlignment + adjustment;
1018         if (curNestedAlignment != newNestedAlignment)
1019         {
1020             JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1021         }
1022         curNestedAlignment = newNestedAlignment;
1023
1024         if (curNestedAlignment > maxNestedAlignment)
1025         {
1026             JITDUMP("Max stack nested alignment changed from %d to %d\n", maxNestedAlignment, curNestedAlignment);
1027             maxNestedAlignment = curNestedAlignment;
1028         }
1029     }
1030
1031 #endif
1032
1033 #ifndef _TARGET_X86_
1034     void genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArgVarNum);
1035 #endif // !_TARGET_X86_
1036
1037 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1038 #ifdef _TARGET_X86_
1039     bool genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk);
1040     void genPushReg(var_types type, regNumber srcReg);
1041     void genPutArgStkFieldList(GenTreePutArgStk* putArgStk);
1042 #endif // _TARGET_X86_
1043
1044     void genPutStructArgStk(GenTreePutArgStk* treeNode);
1045
1046     unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1047     unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1048     unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1049     unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1050     void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode);
1051     void genStructPutArgUnroll(GenTreePutArgStk* putArgStkNode);
1052     void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
1053 #endif // FEATURE_PUT_STRUCT_ARG_STK
1054
1055     void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
1056     void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
1057
1058 #ifdef _TARGET_ARM64_
1059     void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
1060     void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
1061 #endif // _TARGET_ARM64_
1062
1063     void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
1064     void genCodeForInitBlk(GenTreeBlk* initBlkNode);
1065     void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
1066     void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
1067     void genJumpTable(GenTree* tree);
1068     void genTableBasedSwitch(GenTree* tree);
1069     void genCodeForArrIndex(GenTreeArrIndex* treeNode);
1070     void genCodeForArrOffset(GenTreeArrOffs* treeNode);
1071     instruction genGetInsForOper(genTreeOps oper, var_types type);
1072     bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
1073     void genCallInstruction(GenTreeCall* call);
1074     void genJmpMethod(GenTree* jmp);
1075     BasicBlock* genCallFinally(BasicBlock* block);
1076     void genCodeForJumpTrue(GenTree* tree);
1077 #ifdef _TARGET_ARM64_
1078     void genCodeForJumpCompare(GenTreeOp* tree);
1079 #endif // _TARGET_ARM64_
1080
1081 #if FEATURE_EH_FUNCLETS
1082     void genEHCatchRet(BasicBlock* block);
1083 #else  // !FEATURE_EH_FUNCLETS
1084     void genEHFinallyOrFilterRet(BasicBlock* block);
1085 #endif // !FEATURE_EH_FUNCLETS
1086
1087     void genMultiRegCallStoreToLocal(GenTree* treeNode);
1088
1089     // Deals with codegen for muti-register struct returns.
1090     bool isStructReturn(GenTree* treeNode);
1091     void genStructReturn(GenTree* treeNode);
1092
1093 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
1094     void genLongReturn(GenTree* treeNode);
1095 #endif // _TARGET_X86_ ||  _TARGET_ARM_
1096
1097 #if defined(_TARGET_X86_)
1098     void genFloatReturn(GenTree* treeNode);
1099 #endif // _TARGET_X86_
1100
1101 #if defined(_TARGET_ARM64_)
1102     void genSimpleReturn(GenTree* treeNode);
1103 #endif // _TARGET_ARM64_
1104
1105     void genReturn(GenTree* treeNode);
1106
1107     void genLclHeap(GenTree* tree);
1108
1109     bool genIsRegCandidateLocal(GenTree* tree)
1110     {
1111         if (!tree->IsLocal())
1112         {
1113             return false;
1114         }
1115         const LclVarDsc* varDsc = &compiler->lvaTable[tree->gtLclVarCommon.gtLclNum];
1116         return (varDsc->lvIsRegCandidate());
1117     }
1118
1119 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1120 #ifdef _TARGET_X86_
1121     bool m_pushStkArg;
1122 #else  // !_TARGET_X86_
1123     unsigned m_stkArgVarNum;
1124     unsigned m_stkArgOffset;
1125 #endif // !_TARGET_X86_
1126 #endif // !FEATURE_PUT_STRUCT_ARG_STK
1127
1128 #ifdef DEBUG
1129     GenTree* lastConsumedNode;
1130     void genNumberOperandUse(GenTree* const operand, int& useNum) const;
1131     void genCheckConsumeNode(GenTree* const node);
1132 #else  // !DEBUG
1133     inline void genCheckConsumeNode(GenTree* treeNode)
1134     {
1135     }
1136 #endif // DEBUG
1137
1138     /*
1139     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1140     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1141     XX                                                                           XX
1142     XX                           Instruction                                     XX
1143     XX                                                                           XX
1144     XX  The interface to generate a machine-instruction.                         XX
1145     XX  Currently specific to x86                                                XX
1146     XX  TODO-Cleanup: Consider factoring this out of CodeGen                     XX
1147     XX                                                                           XX
1148     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1149     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1150     */
1151
1152 public:
1153     void instInit();
1154
1155     void instGen(instruction ins);
1156 #ifdef _TARGET_XARCH_
1157     void instNop(unsigned size);
1158 #endif
1159
1160     void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
1161
1162     void inst_SET(emitJumpKind condition, regNumber reg);
1163
1164     void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
1165
1166     void inst_RV_RV(instruction ins,
1167                     regNumber   reg1,
1168                     regNumber   reg2,
1169                     var_types   type  = TYP_I_IMPL,
1170                     emitAttr    size  = EA_UNKNOWN,
1171                     insFlags    flags = INS_FLAGS_DONT_CARE);
1172
1173     void inst_RV_RV_RV(instruction ins,
1174                        regNumber   reg1,
1175                        regNumber   reg2,
1176                        regNumber   reg3,
1177                        emitAttr    size,
1178                        insFlags    flags = INS_FLAGS_DONT_CARE);
1179
1180     void inst_IV(instruction ins, int val);
1181     void inst_IV_handle(instruction ins, int val);
1182     void inst_FS(instruction ins, unsigned stk = 0);
1183
1184     void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
1185
1186     void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
1187     void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
1188
1189     void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
1190     void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
1191
1192     void inst_RV_ST(
1193         instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
1194     void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
1195
1196     void instEmit_indCall(GenTreeCall* call,
1197                           size_t       argSize,
1198                           emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
1199
1200     void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
1201
1202     void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
1203
1204     void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
1205
1206     void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
1207
1208     void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
1209
1210     void inst_TT_RV(instruction ins,
1211                     GenTree*    tree,
1212                     regNumber   reg,
1213                     unsigned    offs  = 0,
1214                     emitAttr    size  = EA_UNKNOWN,
1215                     insFlags    flags = INS_FLAGS_DONT_CARE);
1216
1217     void inst_TT_IV(instruction ins,
1218                     GenTree*    tree,
1219                     ssize_t     val,
1220                     unsigned    offs  = 0,
1221                     emitAttr    size  = EA_UNKNOWN,
1222                     insFlags    flags = INS_FLAGS_DONT_CARE);
1223
1224     void inst_RV_AT(instruction ins,
1225                     emitAttr    size,
1226                     var_types   type,
1227                     regNumber   reg,
1228                     GenTree*    tree,
1229                     unsigned    offs  = 0,
1230                     insFlags    flags = INS_FLAGS_DONT_CARE);
1231
1232     void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
1233
1234     void inst_RV_TT(instruction ins,
1235                     regNumber   reg,
1236                     GenTree*    tree,
1237                     unsigned    offs  = 0,
1238                     emitAttr    size  = EA_UNKNOWN,
1239                     insFlags    flags = INS_FLAGS_DONT_CARE);
1240
1241     void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
1242
1243     void inst_FS_TT(instruction ins, GenTree* tree);
1244
1245     void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
1246
1247     void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
1248
1249     void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
1250
1251     void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
1252
1253 #if defined(_TARGET_XARCH_)
1254     void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
1255 #endif
1256
1257     void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
1258
1259     void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
1260
1261     void inst_mov_RV_ST(regNumber reg, GenTree* tree);
1262
1263     void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
1264
1265     void inst_set_SV_var(GenTree* tree);
1266
1267 #ifdef _TARGET_ARM_
1268     bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
1269     bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
1270     bool arm_Valid_Imm_For_Alu(ssize_t imm);
1271     bool arm_Valid_Imm_For_Mov(ssize_t imm);
1272     bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
1273     bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
1274     bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
1275     bool arm_Valid_Imm_For_BL(ssize_t addr);
1276
1277     bool ins_Writes_Dest(instruction ins);
1278 #endif
1279
1280     bool isMoveIns(instruction ins);
1281     instruction ins_Move_Extend(var_types srcType, bool srcInReg);
1282
1283     instruction ins_Copy(var_types dstType);
1284     instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
1285     instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
1286     static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
1287     static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
1288     instruction ins_FloatConv(var_types to, var_types from);
1289     instruction ins_FloatCompare(var_types type);
1290     instruction ins_MathOp(genTreeOps oper, var_types type);
1291     instruction ins_FloatSqrt(var_types type);
1292
1293     void instGen_Return(unsigned stkArgSize);
1294
1295 #ifdef _TARGET_ARM64_
1296     void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
1297 #else
1298     void instGen_MemoryBarrier();
1299 #endif
1300
1301     void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
1302
1303     void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
1304
1305     void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
1306
1307     void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
1308
1309     void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
1310
1311     void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
1312
1313     void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
1314
1315     void instGen_Store_Imm_Into_Lcl(
1316         var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
1317
1318 #ifdef DEBUG
1319     void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
1320 #endif
1321
1322 #ifdef _TARGET_XARCH_
1323     instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
1324 #endif // _TARGET_XARCH_
1325 };
1326
1327 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1328 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1329 XX                                                                           XX
1330 XX                       Instruction                                         XX
1331 XX                      Inline functions                                     XX
1332 XX                                                                           XX
1333 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1334 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1335 */
1336
1337 #ifdef _TARGET_XARCH_
1338 /*****************************************************************************
1339  *
1340  *  Generate a floating-point instruction that has one operand given by
1341  *  a tree (which has been made addressable).
1342  */
1343
1344 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
1345 {
1346     assert(instIsFP(ins));
1347
1348     assert(varTypeIsFloating(tree->gtType));
1349
1350     inst_TT(ins, tree, 0);
1351 }
1352 #endif
1353
1354 /*****************************************************************************
1355  *
1356  *  Generate a "shift reg, cl" instruction.
1357  */
1358
1359 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
1360 {
1361     inst_RV(ins, reg, type);
1362 }
1363
1364 #endif // _CODEGEN_H_