Sync may31 release/8.0-tizen (#510)
[platform/upstream/dotnet/runtime.git] / src / coreclr / 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
4 //
5 // This class contains all the data & functionality for code generation
6 // of a method, except for the target-specific elements, which are
7 // primarily in the Target class.
8 //
9
10 #ifndef _CODEGEN_H_
11 #define _CODEGEN_H_
12 #include "codegeninterface.h"
13 #include "compiler.h" // temporary??
14 #include "regset.h"
15 #include "jitgcinfo.h"
16
17 class CodeGen final : public CodeGenInterface
18 {
19     friend class emitter;
20     friend class DisAssembler;
21
22 public:
23     // This could use further abstraction
24     CodeGen(Compiler* theCompiler);
25
26     virtual void genGenerateCode(void** codePtr, uint32_t* nativeSizeOfCode);
27
28     void genGenerateMachineCode();
29     void genEmitMachineCode();
30     void genEmitUnwindDebugGCandEH();
31
32     // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
33     // move it to Lower
34     virtual bool genCreateAddrMode(
35         GenTree* addr, bool fold, bool* revPtr, GenTree** rv1Ptr, GenTree** rv2Ptr, unsigned* mulPtr, ssize_t* cnsPtr);
36
37 private:
38 #if defined(TARGET_XARCH)
39     // Bit masks used in negating a float or double number.
40     // This is to avoid creating more than one data constant for these bitmasks when a
41     // method has more than one GT_NEG operation on floating point values.
42     CORINFO_FIELD_HANDLE negBitmaskFlt;
43     CORINFO_FIELD_HANDLE negBitmaskDbl;
44
45     // Bit masks used in computing Math.Abs() of a float or double number.
46     CORINFO_FIELD_HANDLE absBitmaskFlt;
47     CORINFO_FIELD_HANDLE absBitmaskDbl;
48
49     // Bit mask used in zeroing the 3rd element of a SIMD12
50     CORINFO_FIELD_HANDLE zroSimd12Elm3;
51
52     // Bit mask used in U8 -> double conversion to adjust the result.
53     CORINFO_FIELD_HANDLE u8ToDblBitmask;
54
55     // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
56     void genSSE2BitwiseOp(GenTree* treeNode);
57
58     // Generates SSE41 code for the given tree as a round operation
59     void genSSE41RoundOp(GenTreeOp* treeNode);
60
61     instruction simdAlignedMovIns()
62     {
63         // We use movaps when non-VEX because it is a smaller instruction;
64         // however the VEX version vmovaps would be used which is the same size as vmovdqa;
65         // also vmovdqa has more available CPU ports on older processors so we switch to that
66         return compiler->canUseVexEncoding() ? INS_movdqa : INS_movaps;
67     }
68     instruction simdUnalignedMovIns()
69     {
70         // We use movups when non-VEX because it is a smaller instruction;
71         // however the VEX version vmovups would be used which is the same size as vmovdqu;
72         // but vmovdqu has more available CPU ports on older processors so we switch to that
73         return compiler->canUseVexEncoding() ? INS_movdqu : INS_movups;
74     }
75 #endif // defined(TARGET_XARCH)
76
77     void genPrepForCompiler();
78
79     void genMarkLabelsForCodegen();
80
81     regNumber genFramePointerReg()
82     {
83         if (isFramePointerUsed())
84         {
85             return REG_FPBASE;
86         }
87         else
88         {
89             return REG_SPBASE;
90         }
91     }
92
93     static bool genShouldRoundFP();
94
95     static GenTreeIndir indirForm(var_types type, GenTree* base);
96     static GenTreeStoreInd storeIndirForm(var_types type, GenTree* base, GenTree* data);
97
98     GenTreeIntCon intForm(var_types type, ssize_t value);
99
100     void genRangeCheck(GenTree* node);
101
102     void genLockedInstructions(GenTreeOp* node);
103 #ifdef TARGET_XARCH
104     void genCodeForLockAdd(GenTreeOp* node);
105 #endif
106
107 #ifdef REG_OPT_RSVD
108     // On some targets such as the ARM we may need to have an extra reserved register
109     //  that is used when addressing stack based locals and stack based temps.
110     //  This method returns the regNumber that should be used when an extra register
111     //  is needed to access the stack based locals and stack based temps.
112     //
113     regNumber rsGetRsvdReg()
114     {
115         // We should have already added this register to the mask
116         //  of reserved registers in regSet.rdMaskResvd
117         noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
118
119         return REG_OPT_RSVD;
120     }
121 #endif // REG_OPT_RSVD
122
123     //-------------------------------------------------------------------------
124
125     bool     genUseBlockInit;  // true if we plan to block-initialize the local stack frame
126     unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
127
128     void SubtractStackLevel(unsigned adjustment)
129     {
130         assert(genStackLevel >= adjustment);
131         unsigned newStackLevel = genStackLevel - adjustment;
132         if (genStackLevel != newStackLevel)
133         {
134             JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
135         }
136         genStackLevel = newStackLevel;
137     }
138
139     void AddStackLevel(unsigned adjustment)
140     {
141         unsigned newStackLevel = genStackLevel + adjustment;
142         if (genStackLevel != newStackLevel)
143         {
144             JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
145         }
146         genStackLevel = newStackLevel;
147     }
148
149     void SetStackLevel(unsigned newStackLevel)
150     {
151         if (genStackLevel != newStackLevel)
152         {
153             JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
154         }
155         genStackLevel = newStackLevel;
156     }
157
158     //-------------------------------------------------------------------------
159
160     void genReportEH();
161
162     // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
163     // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
164     // the GC info.  Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
165     // to be the sizes of the prolog and epilog, respectively.  In DEBUG, makes a check involving the
166     // "codePtr", assumed to be a pointer to the start of the generated code.
167     CLANG_FORMAT_COMMENT_ANCHOR;
168
169 #ifdef JIT32_GCENCODER
170     void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
171     void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
172                                        unsigned prologSize,
173                                        unsigned epilogSize DEBUGARG(void* codePtr));
174 #else  // !JIT32_GCENCODER
175     void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
176     void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
177 #endif // !JIT32_GCENCODER
178
179     /**************************************************************************
180      *                          PROTECTED
181      *************************************************************************/
182
183 protected:
184     // the current (pending) label ref, a label which has been referenced but not yet seen
185     BasicBlock* genPendingCallLabel;
186
187     void**    codePtr;
188     uint32_t* nativeSizeOfCode;
189     unsigned  codeSize;
190     void*     coldCodePtr;
191     void*     consPtr;
192
193     // Last instr we have displayed for dspInstrs
194     unsigned genCurDispOffset;
195
196     static const char* genInsName(instruction ins);
197     const char* genInsDisplayName(emitter::instrDesc* id);
198
199     static const char* genSizeStr(emitAttr size);
200
201     void genInitialize();
202
203     void genInitializeRegisterState();
204
205     void genCodeForBBlist();
206
207 public:
208     void genSpillVar(GenTree* tree);
209
210 protected:
211     void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
212
213     void genGCWriteBarrier(GenTreeStoreInd* store, GCInfo::WriteBarrierForm wbf);
214
215     BasicBlock* genCreateTempLabel();
216
217 private:
218     void genLogLabel(BasicBlock* bb);
219
220 protected:
221     void genDefineTempLabel(BasicBlock* label);
222     void genDefineInlineTempLabel(BasicBlock* label);
223
224     void genAdjustStackLevel(BasicBlock* block);
225
226     void genExitCode(BasicBlock* block);
227
228     void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, BasicBlock* failBlk = nullptr);
229
230 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
231     void genJumpToThrowHlpBlk_la(SpecialCodeKind codeKind,
232                                  instruction     ins,
233                                  regNumber       reg1,
234                                  BasicBlock*     failBlk = nullptr,
235                                  regNumber       reg2    = REG_R0);
236 #else
237     void genCheckOverflow(GenTree* tree);
238 #endif
239
240     //-------------------------------------------------------------------------
241     //
242     // Prolog/epilog generation
243     //
244     //-------------------------------------------------------------------------
245
246     unsigned prologSize;
247     unsigned epilogSize;
248
249     //
250     // Prolog functions and data (there are a few exceptions for more generally used things)
251     //
252
253     void genEstablishFramePointer(int delta, bool reportUnwindData);
254 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
255     void genFnPrologCalleeRegArgs();
256 #else
257     void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
258 #endif
259     void genEnregisterIncomingStackArgs();
260 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
261     void genEnregisterOSRArgsAndLocals(regNumber initReg, bool* pInitRegZeroed);
262 #else
263     void genEnregisterOSRArgsAndLocals();
264 #endif
265     void genCheckUseBlockInit();
266 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
267     void genClearStackVec3ArgUpperBits();
268 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
269
270 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
271     bool genInstrWithConstant(instruction ins,
272                               emitAttr    attr,
273                               regNumber   reg1,
274                               regNumber   reg2,
275                               ssize_t     imm,
276                               regNumber   tmpReg,
277                               bool        inUnwindRegion = false);
278
279     void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero, bool reportUnwindData);
280
281     void genPrologSaveRegPair(regNumber reg1,
282                               regNumber reg2,
283                               int       spOffset,
284                               int       spDelta,
285                               bool      useSaveNextPair,
286                               regNumber tmpReg,
287                               bool*     pTmpRegIsZero);
288
289     void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
290
291     void genEpilogRestoreRegPair(regNumber reg1,
292                                  regNumber reg2,
293                                  int       spOffset,
294                                  int       spDelta,
295                                  bool      useSaveNextPair,
296                                  regNumber tmpReg,
297                                  bool*     pTmpRegIsZero);
298
299     void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
300
301     // A simple struct to keep register pairs for prolog and epilog.
302     struct RegPair
303     {
304         regNumber reg1;
305         regNumber reg2;
306         bool      useSaveNextPair;
307
308         RegPair(regNumber reg1) : reg1(reg1), reg2(REG_NA), useSaveNextPair(false)
309         {
310         }
311
312         RegPair(regNumber reg1, regNumber reg2) : reg1(reg1), reg2(reg2), useSaveNextPair(false)
313         {
314             assert(reg2 == REG_NEXT(reg1));
315         }
316     };
317
318     static void genBuildRegPairsStack(regMaskTP regsMask, ArrayStack<RegPair>* regStack);
319     static void genSetUseSaveNextPairs(ArrayStack<RegPair>* regStack);
320
321     static int genGetSlotSizeForRegsInMask(regMaskTP regsMask);
322
323     void genSaveCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, int spOffset);
324     void genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, int spOffset);
325
326     void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
327     void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
328
329     void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
330
331 #else
332     void genPushCalleeSavedRegisters();
333 #endif
334
335 #if defined(TARGET_AMD64)
336     void genOSRRecordTier0CalleeSavedRegistersAndFrame();
337     void genOSRSaveRemainingCalleeSavedRegisters();
338 #endif // TARGET_AMD64
339
340 #if defined(TARGET_RISCV64)
341     void genStackProbe(ssize_t frameSize, regNumber rOffset, regNumber rLimit, regNumber rPageSize);
342 #endif
343
344     void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
345
346     void genPoisonFrame(regMaskTP bbRegLiveIn);
347
348 #if defined(TARGET_ARM)
349
350     bool genInstrWithConstant(
351         instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insFlags flags, regNumber tmpReg);
352
353     bool genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg);
354
355     void genPushFltRegs(regMaskTP regMask);
356     void genPopFltRegs(regMaskTP regMask);
357     regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
358
359     regMaskTP genJmpCallArgMask();
360
361     void genFreeLclFrame(unsigned           frameSize,
362                          /* IN OUT */ bool* pUnwindStarted);
363
364     void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
365     void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
366     void genMov32RelocatableImmediate(emitAttr size, BYTE* addr, regNumber reg);
367
368     bool genUsedPopToReturn; // True if we use the pop into PC to return,
369                              // False if we didn't and must branch to LR to return.
370
371     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
372     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
373     // same.
374     struct FuncletFrameInfoDsc
375     {
376         regMaskTP fiSaveRegs;                  // Set of registers saved in the funclet prolog (includes LR)
377         unsigned  fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
378         unsigned  fiSpDelta;                   // Stack pointer delta
379         unsigned  fiPSP_slot_SP_offset;        // PSP slot offset from SP
380         int       fiPSP_slot_CallerSP_offset;  // PSP slot offset from Caller SP
381     };
382
383     FuncletFrameInfoDsc genFuncletInfo;
384
385 #elif defined(TARGET_ARM64)
386
387     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
388     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
389     // same.
390     struct FuncletFrameInfoDsc
391     {
392         regMaskTP fiSaveRegs;                // Set of callee-saved registers saved in the funclet prolog (includes LR)
393         int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
394                                              // (negative)
395         int fiSP_to_FPLR_save_delta;         // FP/LR register save offset from SP (positive)
396         int fiSP_to_PSP_slot_delta;          // PSP slot offset from SP (positive)
397         int fiSP_to_CalleeSave_delta;        // First callee-saved register slot offset from SP (positive)
398         int fiCallerSP_to_PSP_slot_delta;    // PSP slot offset from Caller SP (negative)
399         int fiFrameType;                     // Funclet frame types are numbered. See genFuncletProlog() for details.
400         int fiSpDelta1;                      // Stack pointer delta 1 (negative)
401         int fiSpDelta2;                      // Stack pointer delta 2 (negative)
402     };
403
404     FuncletFrameInfoDsc genFuncletInfo;
405
406 #elif defined(TARGET_AMD64)
407
408     // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
409     // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
410     // same.
411     struct FuncletFrameInfoDsc
412     {
413         unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
414         unsigned fiSpDelta;                        // Stack pointer delta
415         int      fiPSP_slot_InitialSP_offset;      // PSP slot offset from Initial-SP
416     };
417
418     FuncletFrameInfoDsc genFuncletInfo;
419
420 #elif defined(TARGET_LOONGARCH64)
421
422     // A set of information that is used by funclet prolog and epilog generation.
423     // It is collected once, before funclet prologs and epilogs are generated,
424     // and used by all funclet prologs and epilogs, which must all be the same.
425     struct FuncletFrameInfoDsc
426     {
427         regMaskTP fiSaveRegs;                // Set of callee-saved registers saved in the funclet prolog (includes RA)
428         int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
429                                              // (negative)
430         int fiSP_to_CalleeSaved_delta;       // CalleeSaved register save offset from SP (positive)
431         int fiCalleeSavedPadding;            // CalleeSaved offset padding (positive)
432         int fiSP_to_PSP_slot_delta;          // PSP slot offset from SP (positive)
433         int fiCallerSP_to_PSP_slot_delta;    // PSP slot offset from Caller SP (negative)
434         int fiSpDelta;                       // Stack pointer delta (negative)
435     };
436
437     FuncletFrameInfoDsc genFuncletInfo;
438
439 #elif defined(TARGET_RISCV64)
440
441     // A set of information that is used by funclet prolog and epilog generation.
442     // It is collected once, before funclet prologs and epilogs are generated,
443     // and used by all funclet prologs and epilogs, which must all be the same.
444     struct FuncletFrameInfoDsc
445     {
446         regMaskTP fiSaveRegs;                // Set of callee-saved registers saved in the funclet prolog (includes RA)
447         int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
448                                              // (negative)
449         int fiSP_to_CalleeSaved_delta;       // CalleeSaved register save offset from SP (positive)
450         int fiCalleeSavedPadding;            // CalleeSaved offset padding (positive)
451         int fiSP_to_PSP_slot_delta;          // PSP slot offset from SP (positive)
452         int fiCallerSP_to_PSP_slot_delta;    // PSP slot offset from Caller SP (negative)
453         int fiSpDelta;                       // Stack pointer delta (negative)
454     };
455
456     FuncletFrameInfoDsc genFuncletInfo;
457
458 #endif // TARGET_ARM, TARGET_ARM64, TARGET_AMD64, TARGET_LOONGARCH64, TARGET_RISCV64
459
460 #if defined(TARGET_XARCH)
461
462     // Save/Restore callee saved float regs to stack
463     void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
464     void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
465     // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
466     void genVzeroupperIfNeeded(bool check256bitOnly = true);
467
468 #endif // TARGET_XARCH
469
470     void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
471
472     regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
473
474     void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
475     void genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
476
477     void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
478
479     void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
480
481     void genFinalizeFrame();
482
483 #ifdef PROFILING_SUPPORTED
484     void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
485     void genProfilingLeaveCallback(unsigned helper);
486 #endif // PROFILING_SUPPORTED
487
488     // clang-format off
489     void genEmitCall(int                   callType,
490                      CORINFO_METHOD_HANDLE methHnd,
491                      INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
492                      void*                 addr
493                      X86_ARG(int argSize),
494                      emitAttr              retSize
495                      MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
496                      const DebugInfo&      di,
497                      regNumber             base,
498                      bool                  isJump);
499     // clang-format on
500
501     // clang-format off
502     void genEmitCallIndir(int                   callType,
503                           CORINFO_METHOD_HANDLE methHnd,
504                           INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
505                           GenTreeIndir*         indir
506                           X86_ARG(int argSize),
507                           emitAttr              retSize
508                           MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
509                           const DebugInfo&      di,
510                           bool                  isJump);
511     // clang-format on
512
513     //
514     // Epilog functions
515     //
516     CLANG_FORMAT_COMMENT_ANCHOR;
517
518 #if defined(TARGET_ARM)
519     bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
520 #endif
521
522 #if defined(TARGET_ARM64)
523
524     void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
525
526 #else // !defined(TARGET_ARM64)
527
528     void genPopCalleeSavedRegisters(bool jmpEpilog = false);
529
530 #if defined(TARGET_XARCH)
531     unsigned genPopCalleeSavedRegistersFromMask(regMaskTP rsPopRegs);
532 #endif // !defined(TARGET_XARCH)
533
534 #endif // !defined(TARGET_ARM64)
535
536     //
537     // Common or driving functions
538     //
539
540     void genReserveProlog(BasicBlock* block); // currently unused
541     void genReserveEpilog(BasicBlock* block);
542     void genFnProlog();
543     void genFnEpilog(BasicBlock* block);
544
545 #if defined(FEATURE_EH_FUNCLETS)
546
547     void genReserveFuncletProlog(BasicBlock* block);
548     void genReserveFuncletEpilog(BasicBlock* block);
549     void genFuncletProlog(BasicBlock* block);
550     void genFuncletEpilog();
551     void genCaptureFuncletPrologEpilogInfo();
552
553     /*-----------------------------------------------------------------------------
554      *
555      *  Set the main function PSPSym value in the frame.
556      *  Funclets use different code to load the PSP sym and save it in their frame.
557      *  See the document "CLR ABI.md" for a full description of the PSPSym.
558      *  The PSPSym section of that document is copied here.
559      *
560      ***********************************
561      *  The name PSPSym stands for Previous Stack Pointer Symbol.  It is how a funclet
562      *  accesses locals from the main function body.
563      *
564      *  First, two definitions.
565      *
566      *  Caller-SP is the value of the stack pointer in a function's caller before the call
567      *  instruction is executed. That is, when function A calls function B, Caller-SP for B
568      *  is the value of the stack pointer immediately before the call instruction in A
569      *  (calling B) was executed. Note that this definition holds for both AMD64, which
570      *  pushes the return value when a call instruction is executed, and for ARM, which
571      *  doesn't. For AMD64, Caller-SP is the address above the call return address.
572      *
573      *  Initial-SP is the initial value of the stack pointer after the fixed-size portion of
574      *  the frame has been allocated. That is, before any "alloca"-type allocations.
575      *
576      *  The PSPSym is a pointer-sized local variable in the frame of the main function and
577      *  of each funclet. The value stored in PSPSym is the value of Initial-SP/Caller-SP
578      *  for the main function.  The stack offset of the PSPSym is reported to the VM in the
579      *  GC information header.  The value reported in the GC information is the offset of the
580      *  PSPSym from Initial-SP/Caller-SP. (Note that both the value stored, and the way the
581      *  value is reported to the VM, differs between architectures. In particular, note that
582      *  most things in the GC information header are reported as offsets relative to Caller-SP,
583      *  but PSPSym on AMD64 is one (maybe the only) exception.)
584      *
585      *  The VM uses the PSPSym to find other locals it cares about (such as the generics context
586      *  in a funclet frame). The JIT uses it to re-establish the frame pointer register, so that
587      *  the frame pointer is the same value in a funclet as it is in the main function body.
588      *
589      *  When a funclet is called, it is passed the Establisher Frame Pointer. For AMD64 this is
590      *  true for all funclets and it is passed as the first argument in RCX, but for ARM this is
591      *  only true for first pass funclets (currently just filters) and it is passed as the second
592      *  argument in R1. The Establisher Frame Pointer is a stack pointer of an interesting "parent"
593      *  frame in the exception processing system. For the CLR, it points either to the main function
594      *  frame or a dynamically enclosing funclet frame from the same function, for the funclet being
595      *  invoked. The value of the Establisher Frame Pointer is Initial-SP on AMD64, Caller-SP on ARM.
596      *
597      *  Using the establisher frame, the funclet wants to load the value of the PSPSym. Since we
598      *  don't know if the Establisher Frame is from the main function or a funclet, we design the
599      *  main function and funclet frame layouts to place the PSPSym at an identical, small, constant
600      *  offset from the Establisher Frame in each case. (This is also required because we only report
601      *  a single offset to the PSPSym in the GC information, and that offset must be valid for the main
602      *  function and all of its funclets). Then, the funclet uses this known offset to compute the
603      *  PSPSym address and read its value. From this, it can compute the value of the frame pointer
604      *  (which is a constant offset from the PSPSym value) and set the frame register to be the same
605      *  as the parent function. Also, the funclet writes the value of the PSPSym to its own frame's
606      *  PSPSym. This "copying" of the PSPSym happens for every funclet invocation, in particular,
607      *  for every nested funclet invocation.
608      *
609      *  On ARM, for all second pass funclets (finally, fault, catch, and filter-handler) the VM
610      *  restores all non-volatile registers to their values within the parent frame. This includes
611      *  the frame register (R11). Thus, the PSPSym is not used to recompute the frame pointer register
612      *  in this case, though the PSPSym is copied to the funclet's frame, as for all funclets.
613      *
614      *  Catch, Filter, and Filter-handlers also get an Exception object (GC ref) as an argument
615      *  (REG_EXCEPTION_OBJECT).  On AMD64 it is the second argument and thus passed in RDX.  On
616      *  ARM this is the first argument and passed in R0.
617      *
618      *  (Note that the JIT64 source code contains a comment that says, "The current CLR doesn't always
619      *  pass the correct establisher frame to the funclet. Funclet may receive establisher frame of
620      *  funclet when expecting that of original routine." It indicates this is the reason that a PSPSym
621      *  is required in all funclets as well as the main function, whereas if the establisher frame was
622      *  correctly reported, the PSPSym could be omitted in some cases.)
623      ***********************************
624      */
625     void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
626
627     void genUpdateCurrentFunclet(BasicBlock* block);
628 #if defined(TARGET_ARM)
629     void genInsertNopForUnwinder(BasicBlock* block);
630 #endif
631
632 #else // !FEATURE_EH_FUNCLETS
633
634     // This is a no-op when there are no funclets!
635     void genUpdateCurrentFunclet(BasicBlock* block)
636     {
637         return;
638     }
639
640 #endif // !FEATURE_EH_FUNCLETS
641
642     void genGeneratePrologsAndEpilogs();
643
644 #if defined(DEBUG) && defined(TARGET_ARM64)
645     void genArm64EmitterUnitTests();
646 #endif
647
648 #if defined(DEBUG) && defined(TARGET_LOONGARCH64)
649     void genLoongArch64EmitterUnitTests();
650 #endif
651
652 #if defined(DEBUG) && defined(LATE_DISASM) && defined(TARGET_AMD64)
653     void genAmd64EmitterUnitTests();
654 #endif
655
656 #ifdef TARGET_ARM64
657     virtual void SetSaveFpLrWithAllCalleeSavedRegisters(bool value);
658     virtual bool IsSaveFpLrWithAllCalleeSavedRegisters() const;
659     bool         genSaveFpLrWithAllCalleeSavedRegisters;
660     bool         genForceFuncletFrameType5;
661 #endif // TARGET_ARM64
662
663     //-------------------------------------------------------------------------
664     //
665     // End prolog/epilog generation
666     //
667     //-------------------------------------------------------------------------
668
669     void      genSinglePush();
670     void      genSinglePop();
671     regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
672     void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
673
674 /*
675 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
676 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
677 XX                                                                           XX
678 XX                           Debugging Support                               XX
679 XX                                                                           XX
680 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
681 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
682 */
683
684 #ifdef DEBUG
685     void genIPmappingDisp(unsigned mappingNum, const IPmappingDsc* ipMapping);
686     void genIPmappingListDisp();
687 #endif // DEBUG
688
689     void genIPmappingAdd(IPmappingDscKind kind, const DebugInfo& di, bool isLabel);
690     void genIPmappingAddToFront(IPmappingDscKind kind, const DebugInfo& di, bool isLabel);
691     void genIPmappingGen();
692     void genAddRichIPMappingHere(const DebugInfo& di);
693
694     void genReportRichDebugInfo();
695
696     void genRecordRichDebugInfoInlineTree(InlineContext* context, ICorDebugInfo::InlineTreeNode* tree);
697
698 #ifdef DEBUG
699     void genReportRichDebugInfoToFile();
700     void genReportRichDebugInfoInlineTreeToFile(FILE* file, InlineContext* context, bool* first);
701 #endif
702
703     void genEnsureCodeEmitted(const DebugInfo& di);
704
705     //-------------------------------------------------------------------------
706     // scope info for the variables
707
708     void genSetScopeInfo(unsigned       which,
709                          UNATIVE_OFFSET startOffs,
710                          UNATIVE_OFFSET length,
711                          unsigned       varNum,
712                          unsigned       LVnum,
713                          bool           avail,
714                          siVarLoc*      varLoc);
715
716     void genSetScopeInfo();
717     // Send VariableLiveRanges as debug info to the debugger
718     void genSetScopeInfoUsingVariableRanges();
719
720 public:
721     void siInit();
722     void checkICodeDebugInfo();
723
724     // The logic used to report debug info on debug code is the same for ScopeInfo and
725     // VariableLiveRange
726     void siBeginBlock(BasicBlock* block);
727     void siEndBlock(BasicBlock* block);
728
729     // VariableLiveRange and siScope needs this method to report variables on debug code
730     void siOpenScopesForNonTrackedVars(const BasicBlock* block, unsigned int lastBlockILEndOffset);
731
732 protected:
733 #if defined(FEATURE_EH_FUNCLETS)
734     bool siInFuncletRegion; // Have we seen the start of the funclet region?
735 #endif                      // FEATURE_EH_FUNCLETS
736
737     IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
738
739     /*
740     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
741     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
742     XX                                                                           XX
743     XX                          PrologScopeInfo                                  XX
744     XX                                                                           XX
745     XX We need special handling in the prolog block, as the parameter variables  XX
746     XX may not be in the same position described by genLclVarTable - they all    XX
747     XX start out on the stack                                                    XX
748     XX                                                                           XX
749     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
750     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
751     */
752 public:
753     void psiBegProlog();
754
755     void psiEndProlog();
756
757     NATIVE_OFFSET psiGetVarStackOffset(const LclVarDsc* lclVarDsc) const;
758
759     /*****************************************************************************
760      *                        TrnslLocalVarInfo
761      *
762      * This struct holds the LocalVarInfo in terms of the generated native code
763      * after a call to genSetScopeInfo()
764      */
765
766 protected:
767 #ifdef DEBUG
768
769     struct TrnslLocalVarInfo
770     {
771         unsigned       tlviVarNum;
772         unsigned       tlviLVnum;
773         VarName        tlviName;
774         UNATIVE_OFFSET tlviStartPC;
775         size_t         tlviLength;
776         bool           tlviAvailable;
777         siVarLoc       tlviVarLoc;
778     };
779
780     // Array of scopes of LocalVars in terms of native code
781
782     TrnslLocalVarInfo* genTrnslLocalVarInfo;
783     unsigned           genTrnslLocalVarCount;
784 #endif
785
786     void genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree);
787 #if defined(FEATURE_SIMD)
788     void genSetRegToConst(regNumber targetReg, var_types targetType, simd_t* val);
789 #endif
790     void genCodeForTreeNode(GenTree* treeNode);
791     void genCodeForBinary(GenTreeOp* treeNode);
792
793 #if defined(TARGET_X86)
794     void genCodeForLongUMod(GenTreeOp* node);
795 #endif // TARGET_X86
796
797     void genCodeForDivMod(GenTreeOp* treeNode);
798     void genCodeForMul(GenTreeOp* treeNode);
799     void genCodeForIncSaturate(GenTree* treeNode);
800     void genCodeForMulHi(GenTreeOp* treeNode);
801     void genLeaInstruction(GenTreeAddrMode* lea);
802     void genSetRegToCond(regNumber dstReg, GenTree* tree);
803
804 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
805     void genScaledAdd(emitAttr  attr,
806                       regNumber targetReg,
807                       regNumber baseReg,
808                       regNumber indexReg,
809                       int scale RISCV64_ARG(regNumber scaleTempReg));
810 #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64
811
812 #if defined(TARGET_ARMARCH)
813     void genCodeForMulLong(GenTreeOp* mul);
814 #endif // TARGET_ARMARCH
815
816 #if !defined(TARGET_64BIT)
817     void genLongToIntCast(GenTree* treeNode);
818 #endif
819
820     // Generate code for a GT_BITCAST that is not contained.
821     void genCodeForBitCast(GenTreeOp* treeNode);
822
823     // Generate the instruction to move a value between register files
824     void genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg);
825
826 public:
827     struct GenIntCastDesc
828     {
829         enum CheckKind
830         {
831             CHECK_NONE,
832             CHECK_SMALL_INT_RANGE,
833             CHECK_POSITIVE,
834 #ifdef TARGET_64BIT
835             CHECK_UINT_RANGE,
836             CHECK_POSITIVE_INT_RANGE,
837             CHECK_INT_RANGE,
838 #endif
839         };
840
841         enum ExtendKind
842         {
843             COPY,
844             ZERO_EXTEND_SMALL_INT,
845             SIGN_EXTEND_SMALL_INT,
846 #ifdef TARGET_64BIT
847             ZERO_EXTEND_INT,
848             SIGN_EXTEND_INT,
849 #endif
850             LOAD_ZERO_EXTEND_SMALL_INT,
851             LOAD_SIGN_EXTEND_SMALL_INT,
852 #ifdef TARGET_64BIT
853             LOAD_ZERO_EXTEND_INT,
854             LOAD_SIGN_EXTEND_INT,
855 #endif
856             LOAD_SOURCE
857         };
858
859     private:
860         CheckKind  m_checkKind;
861         unsigned   m_checkSrcSize;
862         int        m_checkSmallIntMin;
863         int        m_checkSmallIntMax;
864         ExtendKind m_extendKind;
865         unsigned   m_extendSrcSize;
866
867     public:
868         GenIntCastDesc(GenTreeCast* cast);
869
870         CheckKind CheckKind() const
871         {
872             return m_checkKind;
873         }
874
875         unsigned CheckSrcSize() const
876         {
877             assert(m_checkKind != CHECK_NONE);
878             return m_checkSrcSize;
879         }
880
881         int CheckSmallIntMin() const
882         {
883             assert(m_checkKind == CHECK_SMALL_INT_RANGE);
884             return m_checkSmallIntMin;
885         }
886
887         int CheckSmallIntMax() const
888         {
889             assert(m_checkKind == CHECK_SMALL_INT_RANGE);
890             return m_checkSmallIntMax;
891         }
892
893         ExtendKind ExtendKind() const
894         {
895             return m_extendKind;
896         }
897
898         unsigned ExtendSrcSize() const
899         {
900             return m_extendSrcSize;
901         }
902     };
903
904 protected:
905     void genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& desc, regNumber reg);
906     void genIntToIntCast(GenTreeCast* cast);
907     void genFloatToFloatCast(GenTree* treeNode);
908     void genFloatToIntCast(GenTree* treeNode);
909     void genIntToFloatCast(GenTree* treeNode);
910     void genCkfinite(GenTree* treeNode);
911     void genCodeForCompare(GenTreeOp* tree);
912 #ifdef TARGET_ARM64
913     void genCodeForCCMP(GenTreeCCMP* ccmp);
914 #endif
915     void genCodeForSelect(GenTreeOp* select);
916     void genIntrinsic(GenTreeIntrinsic* treeNode);
917     void genPutArgStk(GenTreePutArgStk* treeNode);
918     void genPutArgReg(GenTreeOp* tree);
919 #if FEATURE_ARG_SPLIT
920     void genPutArgSplit(GenTreePutArgSplit* treeNode);
921 #endif // FEATURE_ARG_SPLIT
922
923 #if defined(TARGET_XARCH)
924     unsigned getBaseVarForPutArgStk(GenTree* treeNode);
925 #endif // TARGET_XARCH
926
927     unsigned getFirstArgWithStackSlot();
928
929     void genCompareFloat(GenTree* treeNode);
930     void genCompareInt(GenTree* treeNode);
931 #ifdef TARGET_XARCH
932     bool genCanAvoidEmittingCompareAgainstZero(GenTree* tree, var_types opType);
933     GenTree* genTryFindFlagsConsumer(GenTree* flagsProducer, GenCondition** condition);
934 #endif
935
936 #ifdef FEATURE_SIMD
937 #ifdef TARGET_ARM64
938     insOpts genGetSimdInsOpt(emitAttr size, var_types elementType);
939 #endif
940     void genSimdUpperSave(GenTreeIntrinsic* node);
941     void genSimdUpperRestore(GenTreeIntrinsic* node);
942
943     void genSimd12UpperClear(regNumber tgtReg);
944
945     // TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires
946     // two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3
947     // values through an indirection. Note that Vector3 locals allocated on stack would have
948     // their size rounded to TARGET_POINTER_SIZE (which is 8 bytes on 64-bit targets) and hence
949     // Vector3 locals could be treated as TYP_SIMD16 while reading/writing.
950     void genStoreIndTypeSimd12(GenTreeStoreInd* treeNode);
951     void genLoadIndTypeSimd12(GenTreeIndir* treeNode);
952     void genStoreLclTypeSimd12(GenTreeLclVarCommon* treeNode);
953     void genLoadLclTypeSimd12(GenTreeLclVarCommon* treeNode);
954 #ifdef TARGET_XARCH
955     void genEmitStoreLclTypeSimd12(GenTree* store, unsigned lclNum, unsigned offset);
956     void genEmitLoadLclTypeSimd12(regNumber tgtReg, unsigned lclNum, unsigned offset);
957 #endif // TARGET_XARCH
958 #ifdef TARGET_X86
959     void genStoreSimd12ToStack(regNumber dataReg, regNumber tmpReg);
960     void genPutArgStkSimd12(GenTreePutArgStk* treeNode);
961 #endif // TARGET_X86
962 #endif // FEATURE_SIMD
963
964 #ifdef FEATURE_HW_INTRINSICS
965     void genHWIntrinsic(GenTreeHWIntrinsic* node);
966 #if defined(TARGET_XARCH)
967     void genHWIntrinsic_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, regNumber reg, GenTree* rmOp);
968     void genHWIntrinsic_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, int8_t ival);
969     void genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
970     void genHWIntrinsic_R_R_RM(
971         GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTree* op2);
972     void genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, int8_t ival);
973     void genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
974     void genHWIntrinsic_R_R_R_RM(
975         instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTree* op3);
976     void genHWIntrinsic_R_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, int8_t ival);
977     void genBaseIntrinsic(GenTreeHWIntrinsic* node);
978     void genX86BaseIntrinsic(GenTreeHWIntrinsic* node);
979     void genSSEIntrinsic(GenTreeHWIntrinsic* node);
980     void genSSE2Intrinsic(GenTreeHWIntrinsic* node);
981     void genSSE41Intrinsic(GenTreeHWIntrinsic* node);
982     void genSSE42Intrinsic(GenTreeHWIntrinsic* node);
983     void genAvxFamilyIntrinsic(GenTreeHWIntrinsic* node);
984     void genAESIntrinsic(GenTreeHWIntrinsic* node);
985     void genBMI1OrBMI2Intrinsic(GenTreeHWIntrinsic* node);
986     void genFMAIntrinsic(GenTreeHWIntrinsic* node);
987     void genPermuteVar2x(GenTreeHWIntrinsic* node);
988     void genLZCNTIntrinsic(GenTreeHWIntrinsic* node);
989     void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node);
990     void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node);
991     void genXCNTIntrinsic(GenTreeHWIntrinsic* node, instruction ins);
992     void genX86SerializeIntrinsic(GenTreeHWIntrinsic* node);
993     template <typename HWIntrinsicSwitchCaseBody>
994     void genHWIntrinsicJumpTableFallback(NamedIntrinsic            intrinsic,
995                                          regNumber                 nonConstImmReg,
996                                          regNumber                 baseReg,
997                                          regNumber                 offsReg,
998                                          HWIntrinsicSwitchCaseBody emitSwCase);
999 #endif // defined(TARGET_XARCH)
1000
1001 #ifdef TARGET_ARM64
1002     class HWIntrinsicImmOpHelper final
1003     {
1004     public:
1005         HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTree* immOp, GenTreeHWIntrinsic* intrin);
1006
1007         void EmitBegin();
1008         void EmitCaseEnd();
1009
1010         // Returns true after the last call to EmitCaseEnd() (i.e. this signals that code generation is done).
1011         bool Done() const
1012         {
1013             return (immValue > immUpperBound);
1014         }
1015
1016         // Returns a value of the immediate operand that should be used for a case.
1017         int ImmValue() const
1018         {
1019             return immValue;
1020         }
1021
1022     private:
1023         // Returns true if immOp is non contained immediate (i.e. the value of the immediate operand is enregistered in
1024         // nonConstImmReg).
1025         bool NonConstImmOp() const
1026         {
1027             return nonConstImmReg != REG_NA;
1028         }
1029
1030         // Returns true if a non constant immediate operand can be either 0 or 1.
1031         bool TestImmOpZeroOrOne() const
1032         {
1033             assert(NonConstImmOp());
1034             return (immLowerBound == 0) && (immUpperBound == 1);
1035         }
1036
1037         emitter* GetEmitter() const
1038         {
1039             return codeGen->GetEmitter();
1040         }
1041
1042         CodeGen* const codeGen;
1043         BasicBlock*    endLabel;
1044         BasicBlock*    nonZeroLabel;
1045         int            immValue;
1046         int            immLowerBound;
1047         int            immUpperBound;
1048         regNumber      nonConstImmReg;
1049         regNumber      branchTargetReg;
1050     };
1051 #endif // TARGET_ARM64
1052
1053 #endif // FEATURE_HW_INTRINSICS
1054
1055 #if !defined(TARGET_64BIT)
1056
1057     // CodeGen for Long Ints
1058
1059     void genStoreLongLclVar(GenTree* treeNode);
1060
1061 #endif // !defined(TARGET_64BIT)
1062
1063     //-------------------------------------------------------------------------
1064     // genUpdateLifeStore: Do liveness udpate after tree store instructions
1065     // were emitted, update result var's home if it was stored on stack.
1066     //
1067     // Arguments:
1068     //     tree        -  Gentree node
1069     //     targetReg   -  of the tree
1070     //     varDsc      -  result value's variable
1071     //
1072     // Return Value:
1073     //     None.
1074     __forceinline void genUpdateLifeStore(GenTree* tree, regNumber targetReg, LclVarDsc* varDsc)
1075     {
1076         if (targetReg != REG_NA)
1077         {
1078             genProduceReg(tree);
1079         }
1080         else
1081         {
1082             genUpdateLife(tree);
1083             varDsc->SetRegNum(REG_STK);
1084         }
1085     }
1086
1087     // Do liveness update for register produced by the current node in codegen after
1088     // code has been emitted for it.
1089     void genProduceReg(GenTree* tree);
1090     void genSpillLocal(unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum);
1091     void genUnspillLocal(
1092         unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum, bool reSpill, bool isLastUse);
1093     void genUnspillRegIfNeeded(GenTree* tree);
1094     void genUnspillRegIfNeeded(GenTree* tree, unsigned multiRegIndex);
1095     regNumber genConsumeReg(GenTree* tree);
1096     regNumber genConsumeReg(GenTree* tree, unsigned multiRegIndex);
1097     void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
1098     void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
1099
1100     void genConsumeIfReg(GenTree* tree)
1101     {
1102         if (!tree->isContained())
1103         {
1104             (void)genConsumeReg(tree);
1105         }
1106     }
1107
1108     void genRegCopy(GenTree* tree);
1109     regNumber genRegCopy(GenTree* tree, unsigned multiRegIndex);
1110     void genTransferRegGCState(regNumber dst, regNumber src);
1111     void genConsumeAddress(GenTree* addr);
1112     void genConsumeAddrMode(GenTreeAddrMode* mode);
1113     void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
1114     void genConsumeBlockSrc(GenTreeBlk* blkNode);
1115     void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
1116     void genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg);
1117
1118 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1119     void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode,
1120                                    regNumber         dstReg,
1121                                    regNumber         srcReg,
1122                                    regNumber         sizeReg);
1123 #endif // FEATURE_PUT_STRUCT_ARG_STK
1124 #if FEATURE_ARG_SPLIT
1125     void genConsumeArgSplitStruct(GenTreePutArgSplit* putArgNode);
1126 #endif // FEATURE_ARG_SPLIT
1127
1128     void genConsumeRegs(GenTree* tree);
1129     void genConsumeOperands(GenTreeOp* tree);
1130 #if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
1131     void genConsumeMultiOpOperands(GenTreeMultiOp* tree);
1132 #endif
1133     void genEmitGSCookieCheck(bool pushReg);
1134     void genCodeForShift(GenTree* tree);
1135
1136 #if defined(TARGET_X86) || defined(TARGET_ARM)
1137     void genCodeForShiftLong(GenTree* tree);
1138 #endif
1139
1140 #ifdef TARGET_XARCH
1141     void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
1142 #endif // TARGET_XARCH
1143
1144     void genCodeForCast(GenTreeOp* tree);
1145     void genCodeForLclAddr(GenTreeLclFld* lclAddrNode);
1146     void genCodeForIndexAddr(GenTreeIndexAddr* tree);
1147     void genCodeForIndir(GenTreeIndir* tree);
1148     void genCodeForNegNot(GenTree* tree);
1149     void genCodeForBswap(GenTree* tree);
1150     bool genCanOmitNormalizationForBswap16(GenTree* tree);
1151     void genCodeForLclVar(GenTreeLclVar* tree);
1152     void genCodeForLclFld(GenTreeLclFld* tree);
1153     void genCodeForStoreLclFld(GenTreeLclFld* tree);
1154     void genCodeForStoreLclVar(GenTreeLclVar* tree);
1155     void genCodeForReturnTrap(GenTreeOp* tree);
1156     void genCodeForStoreInd(GenTreeStoreInd* tree);
1157     void genCodeForSwap(GenTreeOp* tree);
1158     void genCodeForCpObj(GenTreeBlk* cpObjNode);
1159     void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
1160     void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
1161 #ifndef TARGET_X86
1162     void genCodeForCpBlkHelper(GenTreeBlk* cpBlkNode);
1163 #endif
1164     void genCodeForPhysReg(GenTreePhysReg* tree);
1165     void genCodeForNullCheck(GenTreeIndir* tree);
1166     void genCodeForCmpXchg(GenTreeCmpXchg* tree);
1167     void genCodeForReuseVal(GenTree* treeNode);
1168
1169     void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
1170     void genAlignStackBeforeCall(GenTreeCall* call);
1171     void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
1172
1173 #if defined(UNIX_X86_ABI)
1174
1175     unsigned curNestedAlignment; // Keep track of alignment adjustment required during codegen.
1176     unsigned maxNestedAlignment; // The maximum amount of alignment adjustment required.
1177
1178     void SubtractNestedAlignment(unsigned adjustment)
1179     {
1180         assert(curNestedAlignment >= adjustment);
1181         unsigned newNestedAlignment = curNestedAlignment - adjustment;
1182         if (curNestedAlignment != newNestedAlignment)
1183         {
1184             JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1185         }
1186         curNestedAlignment = newNestedAlignment;
1187     }
1188
1189     void AddNestedAlignment(unsigned adjustment)
1190     {
1191         unsigned newNestedAlignment = curNestedAlignment + adjustment;
1192         if (curNestedAlignment != newNestedAlignment)
1193         {
1194             JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1195         }
1196         curNestedAlignment = newNestedAlignment;
1197
1198         if (curNestedAlignment > maxNestedAlignment)
1199         {
1200             JITDUMP("Max stack nested alignment changed from %d to %d\n", maxNestedAlignment, curNestedAlignment);
1201             maxNestedAlignment = curNestedAlignment;
1202         }
1203     }
1204
1205 #endif
1206
1207 #ifndef TARGET_X86
1208     void genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArgVarNum);
1209 #endif // !TARGET_X86
1210
1211 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1212 #ifdef TARGET_X86
1213     bool genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk);
1214     void genPushReg(var_types type, regNumber srcReg);
1215     void genPutArgStkFieldList(GenTreePutArgStk* putArgStk);
1216 #endif // TARGET_X86
1217
1218     void genPutStructArgStk(GenTreePutArgStk* treeNode);
1219
1220     unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset);
1221     unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset);
1222     unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset);
1223     unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset);
1224     void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
1225     void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
1226     void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode);
1227     void genStructPutArgUnroll(GenTreePutArgStk* putArgStkNode);
1228 #ifdef TARGET_X86
1229     void genStructPutArgPush(GenTreePutArgStk* putArgStkNode);
1230 #else
1231     void genStructPutArgPartialRepMovs(GenTreePutArgStk* putArgStkNode);
1232 #endif
1233 #endif // FEATURE_PUT_STRUCT_ARG_STK
1234
1235     void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
1236 #ifndef TARGET_X86
1237     void genCodeForInitBlkHelper(GenTreeBlk* initBlkNode);
1238 #endif
1239     void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
1240     void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
1241     void genJumpTable(GenTree* tree);
1242     void genTableBasedSwitch(GenTree* tree);
1243 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1244     instruction genGetInsForOper(GenTree* treeNode);
1245 #else
1246     instruction genGetInsForOper(genTreeOps oper, var_types type);
1247 #endif
1248     bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
1249     GenTree* getCallTarget(const GenTreeCall* call, CORINFO_METHOD_HANDLE* methHnd);
1250     regNumber getCallIndirectionCellReg(GenTreeCall* call);
1251     void genCall(GenTreeCall* call);
1252     void genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackArgBytes));
1253     void genDefinePendingCallLabel(GenTreeCall* call);
1254     void genJmpMethod(GenTree* jmp);
1255     BasicBlock* genCallFinally(BasicBlock* block);
1256 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1257     // TODO: refactor for LA.
1258     void genCodeForJumpCompare(GenTreeOpCC* tree);
1259 #endif
1260 #if defined(TARGET_ARM64)
1261     void genCodeForJumpCompare(GenTreeOpCC* tree);
1262     void genCodeForBfiz(GenTreeOp* tree);
1263 #endif // TARGET_ARM64
1264
1265 #if defined(FEATURE_EH_FUNCLETS)
1266     void genEHCatchRet(BasicBlock* block);
1267 #else  // !FEATURE_EH_FUNCLETS
1268     void genEHFinallyOrFilterRet(BasicBlock* block);
1269 #endif // !FEATURE_EH_FUNCLETS
1270
1271     void genMultiRegStoreToSIMDLocal(GenTreeLclVar* lclNode);
1272     void genMultiRegStoreToLocal(GenTreeLclVar* lclNode);
1273
1274     // Codegen for multi-register struct returns.
1275     bool isStructReturn(GenTree* treeNode);
1276 #ifdef FEATURE_SIMD
1277     void genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc);
1278 #endif
1279     void genStructReturn(GenTree* treeNode);
1280
1281 #if defined(TARGET_X86) || defined(TARGET_ARM)
1282     void genLongReturn(GenTree* treeNode);
1283 #endif // TARGET_X86 ||  TARGET_ARM
1284
1285 #if defined(TARGET_X86)
1286     void genFloatReturn(GenTree* treeNode);
1287 #endif // TARGET_X86
1288
1289 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1290     void genSimpleReturn(GenTree* treeNode);
1291 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
1292
1293     void genReturn(GenTree* treeNode);
1294
1295 #ifdef TARGET_XARCH
1296     void genStackPointerConstantAdjustment(ssize_t spDelta, bool trackSpAdjustments);
1297     void genStackPointerConstantAdjustmentWithProbe(ssize_t spDelta, bool trackSpAdjustments);
1298     target_ssize_t genStackPointerConstantAdjustmentLoopWithProbe(ssize_t spDelta, bool trackSpAdjustments);
1299     void genStackPointerDynamicAdjustmentWithProbe(regNumber regSpDelta);
1300 #else  // !TARGET_XARCH
1301     void genStackPointerConstantAdjustment(ssize_t spDelta, regNumber regTmp);
1302     void genStackPointerConstantAdjustmentWithProbe(ssize_t spDelta, regNumber regTmp);
1303     target_ssize_t genStackPointerConstantAdjustmentLoopWithProbe(ssize_t spDelta, regNumber regTmp);
1304 #endif // !TARGET_XARCH
1305
1306     void genLclHeap(GenTree* tree);
1307     void genCodeForMemmove(GenTreeBlk* tree);
1308
1309     bool genIsRegCandidateLocal(GenTree* tree)
1310     {
1311         if (!tree->IsLocal())
1312         {
1313             return false;
1314         }
1315         return compiler->lvaGetDesc(tree->AsLclVarCommon())->lvIsRegCandidate();
1316     }
1317
1318 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1319 #ifdef TARGET_X86
1320     bool m_pushStkArg;
1321 #else  // !TARGET_X86
1322     unsigned m_stkArgVarNum;
1323     unsigned m_stkArgOffset;
1324 #endif // !TARGET_X86
1325 #endif // !FEATURE_PUT_STRUCT_ARG_STK
1326
1327 #if defined(DEBUG) && defined(TARGET_XARCH)
1328     void genStackPointerCheck(bool      doStackPointerCheck,
1329                               unsigned  lvaStackPointerVar,
1330                               ssize_t   offset = 0,
1331                               regNumber regTmp = REG_NA);
1332 #endif // defined(DEBUG) && defined(TARGET_XARCH)
1333
1334 #ifdef DEBUG
1335     GenTree* lastConsumedNode;
1336     void genNumberOperandUse(GenTree* const operand, int& useNum) const;
1337     void genCheckConsumeNode(GenTree* const node);
1338 #else  // !DEBUG
1339     inline void genCheckConsumeNode(GenTree* treeNode)
1340     {
1341     }
1342 #endif // DEBUG
1343
1344     /*
1345     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1346     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1347     XX                                                                           XX
1348     XX                           Instruction                                     XX
1349     XX                                                                           XX
1350     XX  The interface to generate a machine-instruction.                         XX
1351     XX  Currently specific to x86                                                XX
1352     XX  TODO-Cleanup: Consider factoring this out of CodeGen                     XX
1353     XX                                                                           XX
1354     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1355     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1356     */
1357
1358 public:
1359     void instGen(instruction ins);
1360 #if defined(TARGET_XARCH)
1361     void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock, bool isRemovableJmpCandidate = false);
1362 #else
1363     void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
1364 #endif
1365
1366     void inst_SET(emitJumpKind condition, regNumber reg);
1367
1368     void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
1369
1370     void inst_Mov(var_types dstType,
1371                   regNumber dstReg,
1372                   regNumber srcReg,
1373                   bool      canSkip,
1374                   emitAttr  size  = EA_UNKNOWN,
1375                   insFlags  flags = INS_FLAGS_DONT_CARE);
1376
1377     void inst_Mov_Extend(var_types srcType,
1378                          bool      srcInReg,
1379                          regNumber dstReg,
1380                          regNumber srcReg,
1381                          bool      canSkip,
1382                          emitAttr  size  = EA_UNKNOWN,
1383                          insFlags  flags = INS_FLAGS_DONT_CARE);
1384
1385     void inst_RV_RV(instruction ins,
1386                     regNumber   reg1,
1387                     regNumber   reg2,
1388                     var_types   type  = TYP_I_IMPL,
1389                     emitAttr    size  = EA_UNKNOWN,
1390                     insFlags    flags = INS_FLAGS_DONT_CARE);
1391
1392     void inst_RV_RV_RV(instruction ins,
1393                        regNumber   reg1,
1394                        regNumber   reg2,
1395                        regNumber   reg3,
1396                        emitAttr    size,
1397                        insFlags    flags = INS_FLAGS_DONT_CARE);
1398
1399     void inst_IV(instruction ins, cnsval_ssize_t val);
1400     void inst_IV_handle(instruction ins, cnsval_ssize_t val);
1401
1402     void inst_RV_IV(
1403         instruction ins, regNumber reg, target_ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
1404
1405     void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
1406
1407     void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
1408
1409     void inst_TT_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg);
1410
1411     void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
1412
1413 #if defined(TARGET_XARCH)
1414
1415     enum class OperandKind{
1416         ClsVar, // [CLS_VAR_ADDR]                 - "C" in the emitter.
1417         Local,  // [Local or spill temp + offset] - "S" in the emitter.
1418         Indir,  // [base+index*scale+disp]        - "A" in the emitter.
1419         Imm,    // immediate                      - "I" in the emitter.
1420         Reg     // reg                            - "R" in the emitter.
1421     };
1422
1423     class OperandDesc
1424     {
1425         OperandKind m_kind;
1426         union {
1427             struct
1428             {
1429                 CORINFO_FIELD_HANDLE m_fieldHnd;
1430             };
1431             struct
1432             {
1433                 int      m_varNum;
1434                 uint16_t m_offset;
1435             };
1436             struct
1437             {
1438                 GenTree*      m_addr;
1439                 GenTreeIndir* m_indir;
1440                 var_types     m_indirType;
1441             };
1442             struct
1443             {
1444                 ssize_t m_immediate;
1445                 bool    m_immediateNeedsReloc;
1446             };
1447             struct
1448             {
1449                 regNumber m_reg;
1450             };
1451         };
1452
1453     public:
1454         OperandDesc(CORINFO_FIELD_HANDLE fieldHnd) : m_kind(OperandKind::ClsVar), m_fieldHnd(fieldHnd)
1455         {
1456         }
1457
1458         OperandDesc(int varNum, uint16_t offset) : m_kind(OperandKind::Local), m_varNum(varNum), m_offset(offset)
1459         {
1460         }
1461
1462         OperandDesc(GenTreeIndir* indir)
1463             : m_kind(OperandKind::Indir), m_addr(indir->Addr()), m_indir(indir), m_indirType(indir->TypeGet())
1464         {
1465         }
1466
1467         OperandDesc(var_types indirType, GenTree* addr)
1468             : m_kind(OperandKind::Indir), m_addr(addr), m_indir(nullptr), m_indirType(indirType)
1469         {
1470         }
1471
1472         OperandDesc(ssize_t immediate, bool immediateNeedsReloc)
1473             : m_kind(OperandKind::Imm), m_immediate(immediate), m_immediateNeedsReloc(immediateNeedsReloc)
1474         {
1475         }
1476
1477         OperandDesc(regNumber reg) : m_kind(OperandKind::Reg), m_reg(reg)
1478         {
1479         }
1480
1481         OperandKind GetKind() const
1482         {
1483             return m_kind;
1484         }
1485
1486         CORINFO_FIELD_HANDLE GetFieldHnd() const
1487         {
1488             assert(m_kind == OperandKind::ClsVar);
1489             return m_fieldHnd;
1490         }
1491
1492         int GetVarNum() const
1493         {
1494             assert(m_kind == OperandKind::Local);
1495             return m_varNum;
1496         }
1497
1498         int GetLclOffset() const
1499         {
1500             assert(m_kind == OperandKind::Local);
1501             return m_offset;
1502         }
1503
1504         // TODO-Cleanup: instead of this rather unsightly workaround with
1505         // "indirForm", create a new abstraction for address modes to pass
1506         // to the emitter (or at least just use "addr"...).
1507         GenTreeIndir* GetIndirForm(GenTreeIndir* pIndirForm)
1508         {
1509             if (m_indir == nullptr)
1510             {
1511                 GenTreeIndir indirForm = CodeGen::indirForm(m_indirType, m_addr);
1512                 memcpy((void*)pIndirForm, (void*)&indirForm, sizeof(GenTreeIndir));
1513             }
1514             else
1515             {
1516                 pIndirForm = m_indir;
1517             }
1518
1519             return pIndirForm;
1520         }
1521
1522         ssize_t GetImmediate() const
1523         {
1524             assert(m_kind == OperandKind::Imm);
1525             return m_immediate;
1526         }
1527
1528         emitAttr GetEmitAttrForImmediate(emitAttr baseAttr) const
1529         {
1530             assert(m_kind == OperandKind::Imm);
1531             return m_immediateNeedsReloc ? EA_SET_FLG(baseAttr, EA_CNS_RELOC_FLG) : baseAttr;
1532         }
1533
1534         regNumber GetReg() const
1535         {
1536             return m_reg;
1537         }
1538
1539         bool IsContained() const
1540         {
1541             return m_kind != OperandKind::Reg;
1542         }
1543     };
1544
1545     OperandDesc genOperandDesc(GenTree* op);
1546
1547     void inst_TT(instruction ins, emitAttr size, GenTree* op1);
1548     void inst_RV_TT(instruction ins, emitAttr size, regNumber op1Reg, GenTree* op2);
1549     void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
1550     void inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenTree* rmOp, int ival);
1551     void inst_RV_RV_TT(instruction ins, emitAttr size, regNumber targetReg, regNumber op1Reg, GenTree* op2, bool isRMW);
1552     void inst_RV_RV_TT_IV(
1553         instruction ins, emitAttr size, regNumber targetReg, regNumber op1Reg, GenTree* op2, int8_t ival, bool isRMW);
1554 #endif
1555
1556     void inst_set_SV_var(GenTree* tree);
1557
1558 #ifdef TARGET_ARM
1559     bool arm_Valid_Imm_For_Instr(instruction ins, target_ssize_t imm, insFlags flags);
1560     bool arm_Valid_Imm_For_Add(target_ssize_t imm, insFlags flag);
1561     bool arm_Valid_Imm_For_Add_SP(target_ssize_t imm);
1562 #endif
1563
1564     instruction ins_Move_Extend(var_types srcType, bool srcInReg);
1565
1566     instruction ins_Copy(var_types dstType);
1567     instruction ins_Copy(regNumber srcReg, var_types dstType);
1568 #if defined(TARGET_XARCH)
1569     instruction ins_FloatConv(var_types to, var_types from, emitAttr attr);
1570 #elif defined(TARGET_ARM)
1571     instruction ins_FloatConv(var_types to, var_types from);
1572 #endif
1573     instruction ins_MathOp(genTreeOps oper, var_types type);
1574
1575     void instGen_Return(unsigned stkArgSize);
1576
1577     enum BarrierKind
1578     {
1579         BARRIER_FULL,      // full barrier
1580         BARRIER_LOAD_ONLY, // load barier
1581     };
1582
1583     void instGen_MemoryBarrier(BarrierKind barrierKind = BARRIER_FULL);
1584
1585     void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
1586
1587     void instGen_Set_Reg_To_Imm(emitAttr  size,
1588                                 regNumber reg,
1589                                 ssize_t   imm,
1590                                 insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(size_t targetHandle = 0)
1591                                     DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
1592
1593 #ifdef TARGET_XARCH
1594     instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
1595 #endif // TARGET_XARCH
1596
1597 #if defined(TARGET_ARM64)
1598     static insCond JumpKindToInsCond(emitJumpKind condition);
1599     static insOpts ShiftOpToInsOpts(genTreeOps op);
1600 #elif defined(TARGET_XARCH)
1601     static instruction JumpKindToCmov(emitJumpKind condition);
1602 #endif
1603
1604 #if !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1605     // Maps a GenCondition code to a sequence of conditional jumps or other conditional instructions
1606     // such as X86's SETcc. A sequence of instructions rather than just a single one is required for
1607     // certain floating point conditions.
1608     // For example, X86's UCOMISS sets ZF to indicate equality but it also sets it, together with PF,
1609     // to indicate an unordered result. So for GenCondition::FEQ we first need to check if PF is 0
1610     // and then jump if ZF is 1:
1611     //       JP fallThroughBlock
1612     //       JE jumpDestBlock
1613     //   fallThroughBlock:
1614     //       ...
1615     //   jumpDestBlock:
1616     //
1617     // This is very similar to the way shortcircuit evaluation of bool AND and OR operators works so
1618     // in order to make the GenConditionDesc mapping tables easier to read, a bool expression-like
1619     // pattern is used to encode the above:
1620     //     { EJ_jnp, GT_AND, EJ_je  }
1621     //     { EJ_jp,  GT_OR,  EJ_jne }
1622     //
1623     // For more details check inst_JCC and inst_SETCC functions.
1624     //
1625     struct GenConditionDesc
1626     {
1627         emitJumpKind jumpKind1;
1628         genTreeOps   oper;
1629         emitJumpKind jumpKind2;
1630         char         padTo4Bytes;
1631
1632         static const GenConditionDesc& Get(GenCondition condition)
1633         {
1634             assert(condition.GetCode() < ArrLen(map));
1635             const GenConditionDesc& desc = map[condition.GetCode()];
1636             assert(desc.jumpKind1 != EJ_NONE);
1637             assert((desc.oper == GT_NONE) || (desc.oper == GT_AND) || (desc.oper == GT_OR));
1638             assert((desc.oper == GT_NONE) == (desc.jumpKind2 == EJ_NONE));
1639             return desc;
1640         }
1641
1642     private:
1643         static const GenConditionDesc map[32];
1644     };
1645
1646     void inst_JCC(GenCondition condition, BasicBlock* target);
1647     void inst_SETCC(GenCondition condition, var_types type, regNumber dstReg);
1648
1649     void genCodeForJcc(GenTreeCC* tree);
1650     void genCodeForSetcc(GenTreeCC* setcc);
1651     void genCodeForJTrue(GenTreeOp* jtrue);
1652 #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64
1653 };
1654
1655 // A simple phase that just invokes a method on the codegen instance
1656 //
1657 class CodeGenPhase final : public Phase
1658 {
1659 public:
1660     CodeGenPhase(CodeGen* _codeGen, Phases _phase, void (CodeGen::*_action)())
1661         : Phase(_codeGen->GetCompiler(), _phase), codeGen(_codeGen), action(_action)
1662     {
1663     }
1664
1665 protected:
1666     virtual PhaseStatus DoPhase() override
1667     {
1668         (codeGen->*action)();
1669         return PhaseStatus::MODIFIED_EVERYTHING;
1670     }
1671
1672 private:
1673     CodeGen* codeGen;
1674     void (CodeGen::*action)();
1675 };
1676
1677 // Wrapper for using CodeGenPhase
1678 //
1679 inline void DoPhase(CodeGen* _codeGen, Phases _phase, void (CodeGen::*_action)())
1680 {
1681     CodeGenPhase phase(_codeGen, _phase, _action);
1682     phase.Run();
1683 }
1684
1685 #endif // _CODEGEN_H_