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