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