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