Sync may31 release/8.0-tizen (#510)
[platform/upstream/dotnet/runtime.git] / src / coreclr / jit / emit.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 #ifndef _EMIT_H_
6 #define _EMIT_H_
7
8 #include "instr.h"
9
10 #ifndef _GCINFO_H_
11 #include "gcinfo.h"
12 #endif
13
14 #include "jitgcinfo.h"
15
16 /*****************************************************************************/
17 #ifdef _MSC_VER
18 #pragma warning(disable : 4200) // allow arrays of 0 size inside structs
19 #endif
20
21 /*****************************************************************************/
22
23 #if 0
24 #define EMITVERBOSE 1
25 #else
26 #define EMITVERBOSE (emitComp->verbose)
27 #endif
28
29 #if 0
30 #define EMIT_GC_VERBOSE 0
31 #else
32 #define EMIT_GC_VERBOSE (emitComp->verbose)
33 #endif
34
35 #if 1
36 #define EMIT_INSTLIST_VERBOSE 0
37 #else
38 #define EMIT_INSTLIST_VERBOSE (emitComp->verbose)
39 #endif
40
41 #ifdef TARGET_XARCH
42 #define EMIT_BACKWARDS_NAVIGATION 1 // If 1, enable backwards navigation code for MIR (insGroup/instrDesc).
43 #else
44 #define EMIT_BACKWARDS_NAVIGATION 0
45 #endif
46
47 /*****************************************************************************/
48
49 #ifdef DEBUG
50 #define DEBUG_EMIT 1
51 #else
52 #define DEBUG_EMIT 0
53 #endif
54
55 #if EMITTER_STATS
56 void emitterStats(FILE* fout);
57 void emitterStaticStats(FILE* fout); // Static stats about the emitter (data structure offsets, sizes, etc.)
58 #endif
59
60 void printRegMaskInt(regMaskTP mask);
61
62 /*****************************************************************************/
63 /* Forward declarations */
64
65 class emitLocation;
66 class emitter;
67 struct insGroup;
68
69 typedef void (*emitSplitCallbackType)(void* context, emitLocation* emitLoc);
70
71 /*****************************************************************************/
72
73 //-----------------------------------------------------------------------------
74
75 inline bool needsGC(GCtype gcType)
76 {
77     if (gcType == GCT_NONE)
78     {
79         return false;
80     }
81     else
82     {
83         assert(gcType == GCT_GCREF || gcType == GCT_BYREF);
84         return true;
85     }
86 }
87
88 //-----------------------------------------------------------------------------
89
90 #ifdef DEBUG
91
92 inline bool IsValidGCtype(GCtype gcType)
93 {
94     return (gcType == GCT_NONE || gcType == GCT_GCREF || gcType == GCT_BYREF);
95 }
96
97 // Get a string name to represent the GC type
98
99 inline const char* GCtypeStr(GCtype gcType)
100 {
101     switch (gcType)
102     {
103         case GCT_NONE:
104             return "npt";
105         case GCT_GCREF:
106             return "gcr";
107         case GCT_BYREF:
108             return "byr";
109         default:
110             assert(!"Invalid GCtype");
111             return "err";
112     }
113 }
114
115 #endif // DEBUG
116
117 /*****************************************************************************/
118
119 #if DEBUG_EMIT
120 #define INTERESTING_JUMP_NUM -1 // set to 0 to see all jump info
121 //#define INTERESTING_JUMP_NUM    0
122 #endif
123
124 /*****************************************************************************
125  *
126  *  Represent an emitter location.
127  */
128
129 class emitLocation
130 {
131 public:
132     emitLocation() : ig(nullptr), codePos(0)
133     {
134     }
135
136     emitLocation(insGroup* _ig) : ig(_ig), codePos(0)
137     {
138     }
139
140     emitLocation(insGroup* _ig, unsigned _codePos)
141     {
142         SetLocation(_ig, _codePos);
143     }
144
145     emitLocation(emitter* emit)
146     {
147         CaptureLocation(emit);
148     }
149
150     emitLocation(void* emitCookie) : ig((insGroup*)emitCookie), codePos(0)
151     {
152     }
153
154     // A constructor for code that needs to call it explicitly.
155     void Init()
156     {
157         *this = emitLocation();
158     }
159
160     void CaptureLocation(emitter* emit);
161     void SetLocation(insGroup* _ig, unsigned _codePos);
162     void SetLocation(emitLocation newLocation);
163
164     bool IsCurrentLocation(emitter* emit) const;
165
166     // This function is highly suspect, since it presumes knowledge of the codePos "cookie",
167     // and doesn't look at the 'ig' pointer.
168     bool IsOffsetZero() const
169     {
170         return (codePos == 0);
171     }
172
173     UNATIVE_OFFSET CodeOffset(emitter* emit) const;
174
175     insGroup* GetIG() const
176     {
177         return ig;
178     }
179
180     int GetInsNum() const;
181     int GetInsOffset() const;
182
183     bool operator!=(const emitLocation& other) const
184     {
185         return (ig != other.ig) || (codePos != other.codePos);
186     }
187
188     bool operator==(const emitLocation& other) const
189     {
190         return !(*this != other);
191     }
192
193     bool Valid() const
194     {
195         // Things we could validate:
196         //   1. the instruction group pointer is non-nullptr.
197         //   2. 'ig' is a legal pointer to an instruction group.
198         //   3. 'codePos' is a legal offset into 'ig'.
199         // Currently, we just do #1.
200         // #2 and #3 should only be done in DEBUG, if they are implemented.
201
202         if (ig == nullptr)
203         {
204             return false;
205         }
206
207         return true;
208     }
209
210     UNATIVE_OFFSET GetFuncletPrologOffset(emitter* emit) const;
211
212     bool IsPreviousInsNum(emitter* emit) const;
213
214 #ifdef DEBUG
215     void Print(LONG compMethodID) const;
216 #endif // DEBUG
217
218 private:
219     insGroup* ig;      // the instruction group
220     unsigned  codePos; // the code position within the IG (see emitCurOffset())
221 };
222
223 /************************************************************************/
224 /*          The following describes an instruction group                */
225 /************************************************************************/
226
227 enum insGroupPlaceholderType : unsigned char
228 {
229     IGPT_PROLOG, // currently unused
230     IGPT_EPILOG,
231 #if defined(FEATURE_EH_FUNCLETS)
232     IGPT_FUNCLET_PROLOG,
233     IGPT_FUNCLET_EPILOG,
234 #endif // FEATURE_EH_FUNCLETS
235 };
236
237 #if defined(_MSC_VER) && defined(TARGET_ARM)
238 // ARM aligns structures that contain 64-bit ints or doubles on 64-bit boundaries. This causes unwanted
239 // padding to be added to the end, so sizeof() is unnecessarily big.
240 #pragma pack(push)
241 #pragma pack(4)
242 #endif // defined(_MSC_VER) && defined(TARGET_ARM)
243
244 struct insPlaceholderGroupData
245 {
246     insGroup*               igPhNext;
247     BasicBlock*             igPhBB;
248     VARSET_TP               igPhInitGCrefVars;
249     regMaskTP               igPhInitGCrefRegs;
250     regMaskTP               igPhInitByrefRegs;
251     VARSET_TP               igPhPrevGCrefVars;
252     regMaskTP               igPhPrevGCrefRegs;
253     regMaskTP               igPhPrevByrefRegs;
254     insGroupPlaceholderType igPhType;
255 }; // end of struct insPlaceholderGroupData
256
257 struct insGroup
258 {
259     insGroup* igNext;
260
261 #if EMIT_BACKWARDS_NAVIGATION
262     insGroup* igPrev;
263 #endif
264
265 #ifdef DEBUG
266     insGroup* igSelf; // for consistency checking
267 #endif
268 #if defined(DEBUG) || defined(LATE_DISASM)
269     weight_t igWeight;    // the block weight used for this insGroup
270     double   igPerfScore; // The PerfScore for this insGroup
271 #endif
272
273 #ifdef DEBUG
274     BasicBlock*               lastGeneratedBlock; // The last block that generated code into this insGroup.
275     jitstd::list<BasicBlock*> igBlocks;           // All the blocks that generated code into this insGroup.
276     size_t                    igDataSize;         // size of instrDesc data pointed to by 'igData'
277 #endif
278
279     UNATIVE_OFFSET igNum;     // for ordering (and display) purposes
280     UNATIVE_OFFSET igOffs;    // offset of this group within method
281     unsigned int   igFuncIdx; // Which function/funclet does this belong to? (Index into Compiler::compFuncInfos array.)
282     unsigned short igFlags;   // see IGF_xxx below
283     unsigned short igSize;    // # of bytes of code in this group
284
285 #if FEATURE_LOOP_ALIGN
286     insGroup* igLoopBackEdge; // "last" back-edge that branches back to an aligned loop head.
287 #endif
288
289 #define IGF_GC_VARS 0x0001    // new set of live GC ref variables
290 #define IGF_BYREF_REGS 0x0002 // new set of live by-ref registers
291 #if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
292 #define IGF_FINALLY_TARGET 0x0004 // this group is the start of a basic block that is returned to after a finally.
293 #endif                            // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
294 #define IGF_FUNCLET_PROLOG 0x0008 // this group belongs to a funclet prolog
295 #define IGF_FUNCLET_EPILOG 0x0010 // this group belongs to a funclet epilog.
296 #define IGF_EPILOG 0x0020         // this group belongs to a main function epilog
297 #define IGF_NOGCINTERRUPT 0x0040  // this IG is in a no-interrupt region (prolog, epilog, etc.)
298 #define IGF_UPD_ISZ 0x0080        // some instruction sizes updated
299 #define IGF_PLACEHOLDER 0x0100    // this is a placeholder group, to be filled in later
300 #define IGF_EXTEND 0x0200         // this block is conceptually an extension of the previous block
301                                   // and the emitter should continue to track GC info as if there was no new block.
302 #define IGF_HAS_ALIGN 0x0400      // this group contains an alignment instruction(s) at the end to align either the next
303                                   // IG, or, if this IG contains with an unconditional branch, some subsequent IG.
304 #define IGF_REMOVED_ALIGN 0x0800  // IG was marked as having an alignment instruction(s), but was later unmarked
305                                   // without updating the IG's size/offsets.
306 #define IGF_HAS_REMOVABLE_JMP 0x1000 // this group ends with an unconditional jump which is a candidate for removal
307 #ifdef TARGET_ARM64
308 #define IGF_HAS_REMOVED_INSTR 0x2000 // this group has an instruction that was removed.
309 #endif
310
311 // Mask of IGF_* flags that should be propagated to new blocks when they are created.
312 // This allows prologs and epilogs to be any number of IGs, but still be
313 // automatically marked properly.
314 #if defined(FEATURE_EH_FUNCLETS)
315 #ifdef DEBUG
316 #define IGF_PROPAGATE_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG)
317 #else // DEBUG
318 #define IGF_PROPAGATE_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG)
319 #endif // DEBUG
320 #else  // !FEATURE_EH_FUNCLETS
321 #define IGF_PROPAGATE_MASK (IGF_EPILOG)
322 #endif // !FEATURE_EH_FUNCLETS
323
324     // Try to do better packing based on how large regMaskSmall is (8, 16, or 64 bits).
325     CLANG_FORMAT_COMMENT_ANCHOR;
326
327 #if !(REGMASK_BITS <= 32)
328     regMaskSmall igGCregs; // set of registers with live GC refs
329 #endif                     // !(REGMASK_BITS <= 32)
330
331     union {
332         BYTE*                    igData;   // addr of instruction descriptors
333         insPlaceholderGroupData* igPhData; // when igFlags & IGF_PLACEHOLDER
334     };
335
336 #if EMIT_BACKWARDS_NAVIGATION
337     // Last instruction in group, if any (nullptr if none); used for backwards navigation.
338     // (Should be type emitter::instrDesc*).
339     void* igLastIns;
340 #endif // EMIT_BACKWARDS_NAVIGATION
341
342 #if EMIT_TRACK_STACK_DEPTH
343     unsigned igStkLvl; // stack level on entry
344 #endif                 // EMIT_TRACK_STACK_DEPTH
345
346 #if REGMASK_BITS <= 32
347     regMaskSmall igGCregs; // set of registers with live GC refs
348 #endif                     // REGMASK_BITS <= 32
349
350     unsigned char igInsCnt; // # of instructions  in this group
351
352     VARSET_VALRET_TP igGCvars() const
353     {
354         assert(igFlags & IGF_GC_VARS);
355
356         BYTE* ptr = (BYTE*)igData;
357         ptr -= sizeof(VARSET_TP);
358
359         return *(VARSET_TP*)ptr;
360     }
361
362     unsigned igByrefRegs() const
363     {
364         assert(igFlags & IGF_BYREF_REGS);
365
366         BYTE* ptr = (BYTE*)igData;
367
368         if (igFlags & IGF_GC_VARS)
369         {
370             ptr -= sizeof(VARSET_TP);
371         }
372
373         ptr -= sizeof(unsigned);
374
375         return *(unsigned*)ptr;
376     }
377
378     bool endsWithAlignInstr() const
379     {
380         return (igFlags & IGF_HAS_ALIGN) != 0;
381     }
382
383     //  hadAlignInstr: Checks if this IG was ever marked as aligned and later
384     //                 decided to not align. Sometimes, a loop is marked as not
385     //                 needing alignment, but the igSize was not adjusted immediately.
386     //                 This method is used during loopSize calculation, where we adjust
387     //                 the loop size by removed alignment bytes.
388     bool hadAlignInstr() const
389     {
390         return (igFlags & IGF_REMOVED_ALIGN) != 0;
391     }
392
393 }; // end of struct insGroup
394
395 //  For AMD64 the maximum prolog/epilog size supported on the OS is 256 bytes
396 //  Since it is incorrect for us to be jumping across funclet prolog/epilogs
397 //  we will use the following estimate as the maximum placeholder size.
398 //
399 #define MAX_PLACEHOLDER_IG_SIZE 256
400
401 #if defined(_MSC_VER) && defined(TARGET_ARM)
402 #pragma pack(pop)
403 #endif // defined(_MSC_VER) && defined(TARGET_ARM)
404
405 /*****************************************************************************/
406
407 #define DEFINE_ID_OPS
408 #include "emitfmts.h"
409 #undef DEFINE_ID_OPS
410
411 enum LclVarAddrTag
412 {
413     LVA_STANDARD_ENCODING = 0,
414     LVA_LARGE_OFFSET      = 1,
415     LVA_COMPILER_TEMP     = 2,
416     LVA_LARGE_VARNUM      = 3
417 };
418
419 struct emitLclVarAddr
420 {
421     // Constructor
422     void initLclVarAddr(int varNum, unsigned offset);
423
424     int lvaVarNum() const; // Returns the variable to access. Note that it returns a negative number for compiler spill
425                            // temps.
426     unsigned lvaOffset() const; // returns the offset into the variable to access
427
428     // This struct should be 32 bits in size for the release build.
429     // We have this constraint because this type is used in a union
430     // with several other pointer sized types in the instrDesc struct.
431     //
432 protected:
433     unsigned _lvaVarNum : 15; // Usually the lvaVarNum
434     unsigned _lvaExtra : 15;  // Usually the lvaOffset
435     unsigned _lvaTag : 2;     // tag field to support larger varnums
436 };
437
438 enum idAddrUnionTag
439 {
440     iaut_ALIGNED_POINTER = 0x0,
441     iaut_DATA_OFFSET     = 0x1,
442     iaut_INST_COUNT      = 0x2,
443     iaut_UNUSED_TAG      = 0x3,
444
445     iaut_MASK  = 0x3,
446     iaut_SHIFT = 2
447 };
448
449 class emitter
450 {
451     friend class emitLocation;
452     friend class Compiler;
453     friend class CodeGen;
454     friend class CodeGenInterface;
455
456 public:
457     /*************************************************************************
458      *
459      *  Define the public entry points.
460      */
461
462     // Constructor.
463     emitter()
464     {
465 #ifdef DEBUG
466         // There seem to be some cases where this is used without being initialized via CodeGen::inst_set_SV_var().
467         emitVarRefOffs = 0;
468 #endif // DEBUG
469
470 #ifdef TARGET_XARCH
471         SetUseVEXEncoding(false);
472         SetUseEvexEncoding(false);
473 #endif // TARGET_XARCH
474
475         emitDataSecCur = nullptr;
476     }
477
478 #include "emitpub.h"
479
480 protected:
481     /************************************************************************/
482     /*                        Miscellaneous stuff                           */
483     /************************************************************************/
484
485     Compiler* emitComp;
486     GCInfo*   gcInfo;
487     CodeGen*  codeGen;
488
489     size_t m_debugInfoSize;
490
491     typedef GCInfo::varPtrDsc varPtrDsc;
492     typedef GCInfo::regPtrDsc regPtrDsc;
493     typedef GCInfo::CallDsc   callDsc;
494
495     void* emitGetMem(size_t sz);
496
497     enum opSize : unsigned
498     {
499         OPSZ1  = 0,
500         OPSZ2  = 1,
501         OPSZ4  = 2,
502         OPSZ8  = 3,
503         OPSZ16 = 4,
504
505 #if defined(TARGET_XARCH)
506         OPSZ32     = 5,
507         OPSZ64     = 6,
508         OPSZ_COUNT = 7,
509 #else
510         OPSZ_COUNT = 5,
511 #endif
512
513 #ifdef TARGET_AMD64
514         OPSZP = OPSZ8,
515 #else
516         OPSZP      = OPSZ4,
517 #endif
518     };
519
520 #define OPSIZE_INVALID ((opSize)0xffff)
521
522     static const emitAttr emitSizeDecode[];
523
524     static emitter::opSize emitEncodeSize(emitAttr size);
525     static emitAttr emitDecodeSize(emitter::opSize ensz);
526
527     // Currently, we only allow one IG for the prolog
528     bool emitIGisInProlog(const insGroup* ig)
529     {
530         return ig == emitPrologIG;
531     }
532
533     bool emitIGisInEpilog(const insGroup* ig)
534     {
535         return (ig != nullptr) && ((ig->igFlags & IGF_EPILOG) != 0);
536     }
537
538 #if defined(FEATURE_EH_FUNCLETS)
539
540     bool emitIGisInFuncletProlog(const insGroup* ig)
541     {
542         return (ig != nullptr) && ((ig->igFlags & IGF_FUNCLET_PROLOG) != 0);
543     }
544
545     bool emitIGisInFuncletEpilog(const insGroup* ig)
546     {
547         return (ig != nullptr) && ((ig->igFlags & IGF_FUNCLET_EPILOG) != 0);
548     }
549
550 #endif // FEATURE_EH_FUNCLETS
551
552     // If "ig" corresponds to the start of a basic block that is the
553     // target of a funclet return, generate GC information for it's start
554     // address "cp", as if it were the return address of a call.
555     void emitGenGCInfoIfFuncletRetTarget(insGroup* ig, BYTE* cp);
556
557     void emitRecomputeIGoffsets();
558
559     void emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlags flags);
560
561     /************************************************************************/
562     /*          The following describes a single instruction                */
563     /************************************************************************/
564
565     enum insFormat : unsigned
566     {
567 #define IF_DEF(en, op1, op2) IF_##en,
568 #include "emitfmts.h"
569
570         IF_COUNT
571     };
572
573 #ifdef TARGET_XARCH
574
575 #define AM_DISP_BITS ((sizeof(unsigned) * 8) - 2 * (REGNUM_BITS + 1) - 2)
576 #define AM_DISP_BIG_VAL (-(1 << (AM_DISP_BITS - 1)))
577 #define AM_DISP_MIN (-((1 << (AM_DISP_BITS - 1)) - 1))
578 #define AM_DISP_MAX (+((1 << (AM_DISP_BITS - 1)) - 1))
579
580     struct emitAddrMode
581     {
582         regNumber       amBaseReg : REGNUM_BITS + 1;
583         regNumber       amIndxReg : REGNUM_BITS + 1;
584         emitter::opSize amScale : 2;
585         int             amDisp : AM_DISP_BITS;
586     };
587
588 #endif // TARGET_XARCH
589
590     struct instrDescDebugInfo
591     {
592         unsigned          idNum;
593         size_t            idSize;        // size of the instruction descriptor
594         unsigned          idVarRefOffs;  // IL offset for LclVar reference
595         unsigned          idVarRefOffs2; // IL offset for 2nd LclVar reference (in case this is a pair)
596         size_t            idMemCookie;   // compile time handle (check idFlags)
597         GenTreeFlags      idFlags;       // for determining type of handle in idMemCookie
598         bool              idFinallyCall; // Branch instruction is a call to finally
599         bool              idCatchRet;    // Instruction is for a catch 'return'
600         CORINFO_SIG_INFO* idCallSig;     // Used to report native call site signatures to the EE
601     };
602
603 #ifdef TARGET_ARM
604     unsigned insEncodeSetFlags(insFlags sf);
605
606     enum insSize : unsigned
607     {
608         ISZ_16BIT,
609         ISZ_32BIT,
610         ISZ_48BIT // pseudo-instruction for conditional branch with imm24 range,
611                   // encoded as IT of condition followed by an unconditional branch
612     };
613
614     unsigned insEncodeShiftOpts(insOpts opt);
615     unsigned insEncodePUW_G0(insOpts opt, int imm);
616     unsigned insEncodePUW_H0(insOpts opt, int imm);
617
618 #endif // TARGET_ARM
619
620     struct instrDescCns;
621
622     struct instrDesc
623     {
624     private:
625 // The assembly instruction
626 #if defined(TARGET_XARCH)
627         static_assert_no_msg(INS_count <= 1024);
628         instruction _idIns : 10;
629 #define MAX_ENCODED_SIZE 15
630 #elif defined(TARGET_ARM64)
631 #define INSTR_ENCODED_SIZE 4
632         static_assert_no_msg(INS_count <= 512);
633         instruction _idIns : 9;
634 #elif defined(TARGET_LOONGARCH64)
635         // TODO-LoongArch64: not include SIMD-vector.
636         static_assert_no_msg(INS_count <= 512);
637         instruction _idIns : 9;
638 #else
639         static_assert_no_msg(INS_count <= 256);
640         instruction _idIns : 8;
641 #endif // !(defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64))
642
643 // The format for the instruction
644 #if defined(TARGET_XARCH)
645         static_assert_no_msg(IF_COUNT <= 128);
646         insFormat _idInsFmt : 7;
647 #elif defined(TARGET_LOONGARCH64)
648         unsigned    _idCodeSize : 5; // the instruction(s) size of this instrDesc described.
649 #elif defined(TARGET_RISCV64)
650         unsigned    _idCodeSize : 6; // the instruction(s) size of this instrDesc described.
651 #else
652         static_assert_no_msg(IF_COUNT <= 256);
653         insFormat _idInsFmt : 8;
654 #endif
655
656     public:
657         instrDesc() = delete; // Do not stack alloc this due to debug info that has to come before it.
658
659         instruction idIns() const
660         {
661             return _idIns;
662         }
663         void idIns(instruction ins)
664         {
665             assert((ins != INS_invalid) && (ins < INS_count));
666             _idIns = ins;
667         }
668         bool idInsIs(instruction ins) const
669         {
670             return idIns() == ins;
671         }
672         template <typename... T>
673         bool idInsIs(instruction ins, T... rest) const
674         {
675             return idInsIs(ins) || idInsIs(rest...);
676         }
677
678 #if defined(TARGET_LOONGARCH64)
679         insFormat idInsFmt() const
680         { // not used for LOONGARCH64.
681             return (insFormat)0;
682         }
683         void idInsFmt(insFormat insFmt)
684         {
685         }
686 #elif defined(TARGET_RISCV64)
687         insFormat   idInsFmt() const
688         {
689             NYI_RISCV64("idInsFmt-----unimplemented on RISCV64 yet----");
690             return (insFormat)0;
691         }
692         void idInsFmt(insFormat insFmt)
693         {
694             NYI_RISCV64("idInsFmt-----unimplemented on RISCV64 yet----");
695         }
696 #else
697         insFormat   idInsFmt() const
698         {
699             return _idInsFmt;
700         }
701         void idInsFmt(insFormat insFmt)
702         {
703 #if defined(TARGET_ARM64)
704             noway_assert(insFmt != IF_NONE); // Only the x86 emitter uses IF_NONE, it is invalid for ARM64 (and ARM32)
705 #endif
706             assert(insFmt < IF_COUNT);
707             _idInsFmt = insFmt;
708         }
709 #endif
710
711         ////////////////////////////////////////////////////////////////////////
712         // Space taken up to here:
713         // x86:         17 bits
714         // amd64:       17 bits
715         // arm:         16 bits
716         // arm64:       17 bits
717         // loongarch64: 14 bits
718         // risc-v:      14 bits
719
720     private:
721 #if defined(TARGET_XARCH)
722         unsigned _idCodeSize : 4; // size of instruction in bytes. Max size of an Intel instruction is 15 bytes.
723         opSize   _idOpSize : 3;   // operand size: 0=1 , 1=2 , 2=4 , 3=8, 4=16, 5=32
724                                   // At this point we have fully consumed first DWORD so that next field
725                                   // doesn't cross a byte boundary.
726 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
727 /* _idOpSize defined below. */
728 #else
729         opSize _idOpSize : 2; // operand size: 0=1 , 1=2 , 2=4 , 3=8
730 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
731
732         // On Amd64, this is where the second DWORD begins
733         // On System V a call could return a struct in 2 registers. The instrDescCGCA struct below has  member that
734         // stores the GC-ness of the second register.
735         // It is added to the instrDescCGCA and not here (the base struct) since it is not needed by all the
736         // instructions. This struct (instrDesc) is very carefully kept to be no more than 128 bytes. There is no more
737         // space to add members for keeping GC-ness of the second return registers. It will also bloat the base struct
738         // unnecessarily since the GC-ness of the second register is only needed for call instructions.
739         // The instrDescCGCA struct's member keeping the GC-ness of the first return register is _idcSecondRetRegGCType.
740         GCtype _idGCref : 2; // GCref operand? (value is a "GCtype")
741
742         // The idReg1 and idReg2 fields hold the first and second register
743         // operand(s), whenever these are present. Note that currently the
744         // size of these fields is 6 bits on all targets, and care needs to
745         // be taken to make sure all of these fields stay reasonably packed.
746
747         // Note that we use the _idReg1 and _idReg2 fields to hold
748         // the live gcrefReg mask for the call instructions on x86/x64
749         //
750         regNumber _idReg1 : REGNUM_BITS; // register num
751         regNumber _idReg2 : REGNUM_BITS;
752
753         ////////////////////////////////////////////////////////////////////////
754         // Space taken up to here:
755         // x86:         38 bits
756         // amd64:       38 bits
757         // arm:         32 bits
758         // arm64:       31 bits
759         // loongarch64: 28 bits
760         // risc-v:      28 bits
761
762         unsigned _idSmallDsc : 1;  // is this a "small" descriptor?
763         unsigned _idLargeCns : 1;  // does a large constant     follow?
764         unsigned _idLargeDsp : 1;  // does a large displacement follow?
765         unsigned _idLargeCall : 1; // large call descriptor used
766
767         unsigned _idBound : 1;      // jump target / frame offset bound
768         unsigned _idCallRegPtr : 1; // IL indirect calls: addr in reg
769         unsigned _idCallAddr : 1;   // IL indirect calls: can make a direct call to iiaAddr
770         unsigned _idNoGC : 1;       // Some helpers don't get recorded in GC tables
771 #if defined(TARGET_XARCH)
772         unsigned _idEvexbContext : 1; // does EVEX.b need to be set.
773 #endif                                //  TARGET_XARCH
774
775 #ifdef TARGET_ARM64
776         opSize   _idOpSize : 3;    // operand size: 0=1 , 1=2 , 2=4 , 3=8, 4=16
777         insOpts  _idInsOpt : 6;    // options for instructions
778         unsigned _idLclVar : 1;    // access a local on stack
779         unsigned _idLclVarPair : 1 // carries information for 2 GC lcl vars.
780 #endif
781
782 #ifdef TARGET_LOONGARCH64
783             // TODO-LoongArch64: maybe delete on future.
784             opSize _idOpSize : 3; // operand size: 0=1 , 1=2 , 2=4 , 3=8, 4=16
785         insOpts    _idInsOpt : 6; // loongarch options for special: placeholders. e.g emitIns_R_C, also identifying the
786                                   // accessing a local on stack.
787         unsigned _idLclVar : 1;   // access a local on stack.
788 #endif
789
790 #ifdef TARGET_RISCV64
791         // TODO-RISCV64: maybe delete on future
792         opSize   _idOpSize : 3; // operand size: 0=1 , 1=2 , 2=4 , 3=8, 4=16
793         insOpts  _idInsOpt : 6; // options for instructions
794         unsigned _idLclVar : 1; // access a local on stack
795 #endif
796
797 #ifdef TARGET_ARM
798         insSize  _idInsSize : 2;   // size of instruction: 16, 32 or 48 bits
799         insFlags _idInsFlags : 1;  // will this instruction set the flags
800         unsigned _idLclVar : 1;    // access a local on stack
801         unsigned _idLclFPBase : 1; // access a local on stack - SP based offset
802         insOpts  _idInsOpt : 3;    // options for Load/Store instructions
803 #endif
804
805         ////////////////////////////////////////////////////////////////////////
806         // Space taken up to here:
807         // x86:         47 bits
808         // amd64:       47 bits
809         // arm:         48 bits
810         // arm64:       50 bits
811         // loongarch64: 46 bits
812         // risc-v:      46 bits
813
814         //
815         // How many bits have been used beyond the first 32?
816         // Define ID_EXTRA_BITFIELD_BITS to that number.
817         //
818         CLANG_FORMAT_COMMENT_ANCHOR;
819
820 #if defined(TARGET_ARM)
821 #define ID_EXTRA_BITFIELD_BITS (16)
822 #elif defined(TARGET_ARM64)
823 #define ID_EXTRA_BITFIELD_BITS (18)
824 #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
825 #define ID_EXTRA_BITFIELD_BITS (14)
826 #elif defined(TARGET_XARCH)
827 #define ID_EXTRA_BITFIELD_BITS (15)
828 #else
829 #error Unsupported or unset target architecture
830 #endif
831
832         unsigned _idCnsReloc : 1; // LargeCns is an RVA and needs reloc tag
833         unsigned _idDspReloc : 1; // LargeDsp is an RVA and needs reloc tag
834
835 #define ID_EXTRA_RELOC_BITS (2)
836
837 #if EMIT_BACKWARDS_NAVIGATION
838
839         // "Pointer" to previous instrDesc in this group. If zero, there is
840         // no previous instrDesc. If non-zero, then _idScaledPrevOffset * 4
841         // is the size in bytes of the previous instrDesc; subtract that from
842         // the current instrDesc* to reach the previous one.
843         // All instrDesc types are <= 56 bytes, but we also need m_debugInfoSize,
844         // which is pointer sized, so 5 bits are required on 64-bit and 4 bits
845         // on 32-bit.
846         CLANG_FORMAT_COMMENT_ANCHOR;
847
848 #ifdef HOST_64BIT
849         unsigned _idScaledPrevOffset : 5;
850 #define ID_EXTRA_PREV_OFFSET_BITS (5)
851 #else
852         unsigned _idScaledPrevOffset : 4;
853 #define ID_EXTRA_PREV_OFFSET_BITS (4)
854 #endif
855
856 #else // !EMIT_BACKWARDS_NAVIGATION
857 #define ID_EXTRA_PREV_OFFSET_BITS (0)
858 #endif // !EMIT_BACKWARDS_NAVIGATION
859
860         ////////////////////////////////////////////////////////////////////////
861         // Space taken up to here (with/without prev offset, assuming host==target):
862         // x86:         53/49 bits
863         // amd64:       54/49 bits
864         // arm:         54/50 bits
865         // arm64:       57/52 bits
866         // loongarch64: 53/48 bits
867         // risc-v:      53/48 bits
868         CLANG_FORMAT_COMMENT_ANCHOR;
869
870 #define ID_EXTRA_BITS (ID_EXTRA_RELOC_BITS + ID_EXTRA_BITFIELD_BITS + ID_EXTRA_PREV_OFFSET_BITS)
871
872 /* Use whatever bits are left over for small constants */
873
874 #define ID_BIT_SMALL_CNS (32 - ID_EXTRA_BITS)
875         C_ASSERT(ID_BIT_SMALL_CNS > 0);
876
877         ////////////////////////////////////////////////////////////////////////
878         // Small constant size (with/without prev offset, assuming host==target):
879         // x86:         11/15 bits
880         // amd64:       10/15 bits
881         // arm:         10/14 bits
882         // arm64:        7/12 bits
883         // loongarch64: 11/16 bits
884         // risc-v:      11/16 bits
885         CLANG_FORMAT_COMMENT_ANCHOR;
886
887 #define ID_ADJ_SMALL_CNS (int)(1 << (ID_BIT_SMALL_CNS - 1))
888 #define ID_CNT_SMALL_CNS (int)(1 << ID_BIT_SMALL_CNS)
889
890 #define ID_MIN_SMALL_CNS (int)(0 - ID_ADJ_SMALL_CNS)
891 #define ID_MAX_SMALL_CNS (int)(ID_CNT_SMALL_CNS - ID_ADJ_SMALL_CNS - 1)
892
893         // We encounter many constants, but there is a disproportionate amount that are in the range [-1, +4]
894         // and otherwise powers of 2. We therefore allow the tracked range here to include negative values.
895         signed _idSmallCns : ID_BIT_SMALL_CNS;
896
897         ////////////////////////////////////////////////////////////////////////
898         // Space taken up to here: 64 bits, all architectures, by design.
899         ////////////////////////////////////////////////////////////////////////
900
901         //
902         // This is the end of the 'small' instrDesc which is the same on all platforms
903         //
904         // If you add lots more fields that need to be cleared (such
905         // as various flags), you might need to update the body of
906         // emitter::emitAllocInstr() to clear them.
907         //
908         // SMALL_IDSC_SIZE is this size, in bytes.
909         //
910         CLANG_FORMAT_COMMENT_ANCHOR;
911
912 #define SMALL_IDSC_SIZE 8
913
914     public:
915         instrDescDebugInfo* idDebugOnlyInfo() const
916         {
917             const char* addr = reinterpret_cast<const char*>(this);
918             return *reinterpret_cast<instrDescDebugInfo* const*>(addr - sizeof(instrDescDebugInfo*));
919         }
920         void idDebugOnlyInfo(instrDescDebugInfo* info)
921         {
922             char* addr                                                                  = reinterpret_cast<char*>(this);
923             *reinterpret_cast<instrDescDebugInfo**>(addr - sizeof(instrDescDebugInfo*)) = info;
924         }
925
926     private:
927         CLANG_FORMAT_COMMENT_ANCHOR;
928
929         void checkSizes();
930
931         union idAddrUnion {
932 // TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
933 // about reading what we think is here, to avoid unexpected corruption issues.
934
935 #if !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64)
936             emitLclVarAddr iiaLclVar;
937 #endif
938             BasicBlock* iiaBBlabel;
939             insGroup*   iiaIGlabel;
940             BYTE*       iiaAddr;
941 #ifdef TARGET_XARCH
942             emitAddrMode iiaAddrMode;
943 #endif // TARGET_XARCH
944
945             CORINFO_FIELD_HANDLE iiaFieldHnd; // iiaFieldHandle is also used to encode
946                                               // an offset into the JIT data constant area
947             bool iiaIsJitDataOffset() const;
948             int  iiaGetJitDataOffset() const;
949
950             // iiaEncodedInstrCount and its accessor functions are used to specify an instruction
951             // count for jumps, instead of using a label and multiple blocks. This is used in the
952             // prolog as well as for IF_LARGEJMP pseudo-branch instructions.
953             int iiaEncodedInstrCount;
954
955             bool iiaHasInstrCount() const
956             {
957                 return (iiaEncodedInstrCount & iaut_MASK) == iaut_INST_COUNT;
958             }
959             int iiaGetInstrCount() const
960             {
961                 assert(iiaHasInstrCount());
962                 return (iiaEncodedInstrCount >> iaut_SHIFT);
963             }
964             void iiaSetInstrCount(int count)
965             {
966                 assert(abs(count) < 10);
967                 iiaEncodedInstrCount = (count << iaut_SHIFT) | iaut_INST_COUNT;
968             }
969
970 #ifdef TARGET_ARMARCH
971
972             struct
973             {
974 #ifdef TARGET_ARM64
975                 // For 64-bit architecture this 32-bit structure can pack with these unsigned bit fields
976                 emitLclVarAddr iiaLclVar;
977                 unsigned       _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
978                 GCtype         _idGCref2 : 2;
979 #endif
980                 regNumber _idReg3 : REGNUM_BITS;
981                 regNumber _idReg4 : REGNUM_BITS;
982             };
983 #elif defined(TARGET_XARCH)
984             struct
985             {
986                 regNumber _idReg3 : REGNUM_BITS;
987                 regNumber _idReg4 : REGNUM_BITS;
988             };
989 #elif defined(TARGET_LOONGARCH64)
990             struct
991             {
992                 unsigned int iiaEncodedInstr; // instruction's binary encoding.
993                 regNumber    _idReg3 : REGNUM_BITS;
994                 regNumber    _idReg4 : REGNUM_BITS;
995             };
996
997             struct
998             {
999                 int            iiaJmpOffset; // temporary saving the offset of jmp or data.
1000                 emitLclVarAddr iiaLclVar;
1001             };
1002
1003             void iiaSetInstrEncode(unsigned int encode)
1004             {
1005                 iiaEncodedInstr = encode;
1006             }
1007             unsigned int iiaGetInstrEncode() const
1008             {
1009                 return iiaEncodedInstr;
1010             }
1011
1012             void iiaSetJmpOffset(int offset)
1013             {
1014                 iiaJmpOffset = offset;
1015             }
1016             int iiaGetJmpOffset() const
1017             {
1018                 return iiaJmpOffset;
1019             }
1020 #elif defined(TARGET_RISCV64)
1021             struct
1022             {
1023                 regNumber    _idReg3 : REGNUM_BITS;
1024                 regNumber    _idReg4 : REGNUM_BITS;
1025                 unsigned int iiaEncodedInstr; // instruction's binary encoding.
1026             };
1027
1028             void iiaSetInstrEncode(unsigned int encode)
1029             {
1030                 iiaEncodedInstr = encode;
1031             }
1032             unsigned int iiaGetInstrEncode() const
1033             {
1034                 return iiaEncodedInstr;
1035             }
1036 #endif // defined(TARGET_RISCV64)
1037
1038         } _idAddrUnion;
1039
1040         /* Trivial wrappers to return properly typed enums */
1041     public:
1042         bool idIsSmallDsc() const
1043         {
1044             return (_idSmallDsc != 0);
1045         }
1046         void idSetIsSmallDsc()
1047         {
1048             _idSmallDsc = 1;
1049         }
1050
1051 #if defined(TARGET_XARCH)
1052
1053         unsigned idCodeSize() const
1054         {
1055             return _idCodeSize;
1056         }
1057         void idCodeSize(unsigned sz)
1058         {
1059             assert(sz <= 15); // Intel decoder limit.
1060             _idCodeSize = sz;
1061             assert(sz == _idCodeSize);
1062         }
1063
1064 #elif defined(TARGET_ARM64)
1065
1066         inline bool idIsEmptyAlign() const
1067         {
1068             return (idIns() == INS_align) && (idInsOpt() == INS_OPTS_NONE);
1069         }
1070
1071         unsigned idCodeSize() const
1072         {
1073             int size = 4;
1074             switch (idInsFmt())
1075             {
1076                 case IF_LARGEADR:
1077                 // adrp + add
1078                 case IF_LARGEJMP:
1079                     // b<cond> + b<uncond>
1080                     size = 8;
1081                     break;
1082                 case IF_LARGELDC:
1083                     if (isVectorRegister(idReg1()))
1084                     {
1085                         // (adrp + ldr + fmov) or (adrp + add + ld1)
1086                         size = 12;
1087                     }
1088                     else
1089                     {
1090                         // adrp + ldr
1091                         size = 8;
1092                     }
1093                     break;
1094                 case IF_SN_0A:
1095                     if (idIsEmptyAlign())
1096                     {
1097                         size = 0;
1098                     }
1099                     break;
1100                 default:
1101                     break;
1102             }
1103
1104             return size;
1105         }
1106
1107 #elif defined(TARGET_ARM)
1108
1109         bool idInstrIsT1() const
1110         {
1111             return (_idInsSize == ISZ_16BIT);
1112         }
1113         unsigned idCodeSize() const
1114         {
1115             unsigned result = (_idInsSize == ISZ_16BIT) ? 2 : (_idInsSize == ISZ_32BIT) ? 4 : 6;
1116             return result;
1117         }
1118         insSize idInsSize() const
1119         {
1120             return _idInsSize;
1121         }
1122         void idInsSize(insSize isz)
1123         {
1124             _idInsSize = isz;
1125             assert(isz == _idInsSize);
1126         }
1127         insFlags idInsFlags() const
1128         {
1129             return _idInsFlags;
1130         }
1131         void idInsFlags(insFlags sf)
1132         {
1133             _idInsFlags = sf;
1134             assert(sf == _idInsFlags);
1135         }
1136
1137 #elif defined(TARGET_LOONGARCH64)
1138         unsigned idCodeSize() const
1139         {
1140             return _idCodeSize;
1141         }
1142         void idCodeSize(unsigned sz)
1143         {
1144             // LoongArch64's instrDesc is not always meaning only one instruction.
1145             // e.g. the `emitter::emitIns_I_la` for emitting the immediates.
1146             assert(sz <= 16);
1147             _idCodeSize = sz;
1148         }
1149 #elif defined(TARGET_RISCV64)
1150         unsigned idCodeSize() const
1151         {
1152             return _idCodeSize;
1153         }
1154         void idCodeSize(unsigned sz)
1155         {
1156             // RISCV64's instrDesc is not always meaning only one instruction.
1157             // e.g. the `emitter::emitLoadImmediate` for emitting the immediates.
1158             assert(sz <= 32);
1159             _idCodeSize = sz;
1160         }
1161 #endif
1162
1163         emitAttr idOpSize() const
1164         {
1165             return emitDecodeSize(_idOpSize);
1166         }
1167         void idOpSize(emitAttr opsz)
1168         {
1169             _idOpSize = emitEncodeSize(opsz);
1170         }
1171
1172         GCtype idGCref() const
1173         {
1174             return (GCtype)_idGCref;
1175         }
1176         void idGCref(GCtype gctype)
1177         {
1178             _idGCref = gctype;
1179         }
1180
1181         regNumber idReg1() const
1182         {
1183             return _idReg1;
1184         }
1185         void idReg1(regNumber reg)
1186         {
1187             _idReg1 = reg;
1188             assert(reg == _idReg1);
1189         }
1190
1191 #ifdef TARGET_ARM64
1192         GCtype idGCrefReg2() const
1193         {
1194             assert(!idIsSmallDsc());
1195             return (GCtype)idAddr()->_idGCref2;
1196         }
1197         void idGCrefReg2(GCtype gctype)
1198         {
1199             assert(!idIsSmallDsc());
1200             idAddr()->_idGCref2 = gctype;
1201         }
1202 #endif // TARGET_ARM64
1203
1204         regNumber idReg2() const
1205         {
1206             return _idReg2;
1207         }
1208         void idReg2(regNumber reg)
1209         {
1210             _idReg2 = reg;
1211             assert(reg == _idReg2);
1212         }
1213
1214 #if defined(TARGET_XARCH)
1215         regNumber idReg3() const
1216         {
1217             assert(!idIsSmallDsc());
1218             return idAddr()->_idReg3;
1219         }
1220         void idReg3(regNumber reg)
1221         {
1222             assert(!idIsSmallDsc());
1223             idAddr()->_idReg3 = reg;
1224             assert(reg == idAddr()->_idReg3);
1225         }
1226
1227         regNumber idReg4() const
1228         {
1229             assert(!idIsSmallDsc());
1230             return idAddr()->_idReg4;
1231         }
1232         void idReg4(regNumber reg)
1233         {
1234             assert(!idIsSmallDsc());
1235             idAddr()->_idReg4 = reg;
1236             assert(reg == idAddr()->_idReg4);
1237         }
1238
1239         bool idHasReg1() const
1240         {
1241             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1242             return (isInfo & (IS_R1_RD | IS_R1_RW | IS_R1_WR)) != 0;
1243         }
1244         bool idIsReg1Read() const
1245         {
1246             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1247             return (isInfo & (IS_R1_RD | IS_R1_RW)) != 0;
1248         }
1249         bool idIsReg1Write() const
1250         {
1251             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1252             return (isInfo & (IS_R1_RW | IS_R1_WR)) != 0;
1253         }
1254
1255         bool idHasReg2() const
1256         {
1257             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1258             return (isInfo & (IS_R2_RD | IS_R2_RW | IS_R2_WR)) != 0;
1259         }
1260         bool idIsReg2Read() const
1261         {
1262             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1263             return (isInfo & (IS_R2_RD | IS_R2_RW)) != 0;
1264         }
1265         bool idIsReg2Write() const
1266         {
1267             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1268             return (isInfo & (IS_R2_RW | IS_R2_WR)) != 0;
1269         }
1270
1271         bool idHasReg3() const
1272         {
1273             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1274             return (isInfo & (IS_R3_RD | IS_R3_RW | IS_R3_WR)) != 0;
1275         }
1276         bool idIsReg3Read() const
1277         {
1278             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1279             return (isInfo & (IS_R3_RD | IS_R3_RW)) != 0;
1280         }
1281         bool idIsReg3Write() const
1282         {
1283             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1284             return (isInfo & (IS_R3_RW | IS_R3_WR)) != 0;
1285         }
1286
1287         bool idHasReg4() const
1288         {
1289             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1290             return (isInfo & (IS_R4_RD | IS_R4_RW | IS_R4_WR)) != 0;
1291         }
1292         bool idIsReg4Read() const
1293         {
1294             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1295             return (isInfo & (IS_R4_RD | IS_R4_RW)) != 0;
1296         }
1297         bool idIsReg4Write() const
1298         {
1299             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1300             return (isInfo & (IS_R4_RW | IS_R4_WR)) != 0;
1301         }
1302
1303         bool idHasMemGen() const
1304         {
1305             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1306             return (isInfo & (IS_GM_RD | IS_GM_RW | IS_GM_WR)) != 0;
1307         }
1308         bool idHasMemGenRead() const
1309         {
1310             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1311             return (isInfo & (IS_GM_RD | IS_GM_RW)) != 0;
1312         }
1313         bool idHasMemGenWrite() const
1314         {
1315             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1316             return (isInfo & (IS_GM_RW | IS_GM_WR)) != 0;
1317         }
1318
1319         bool idHasMemStk() const
1320         {
1321             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1322             return (isInfo & (IS_SF_RD | IS_SF_RW | IS_SF_WR)) != 0;
1323         }
1324         bool idHasMemStkRead() const
1325         {
1326             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1327             return (isInfo & (IS_SF_RD | IS_SF_RW)) != 0;
1328         }
1329         bool idHasMemStkWrite() const
1330         {
1331             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1332             return (isInfo & (IS_SF_RW | IS_SF_WR)) != 0;
1333         }
1334
1335         bool idHasMemAdr() const
1336         {
1337             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1338             return (isInfo & (IS_AM_RD | IS_AM_RW | IS_AM_WR)) != 0;
1339         }
1340         bool idHasMemAdrRead() const
1341         {
1342             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1343             return (isInfo & (IS_AM_RD | IS_AM_RW)) != 0;
1344         }
1345         bool idHasMemAdrWrite() const
1346         {
1347             IS_INFO isInfo = emitGetSchedInfo(idInsFmt());
1348             return (isInfo & (IS_AM_RW | IS_AM_WR)) != 0;
1349         }
1350
1351         bool idHasMem() const
1352         {
1353             return idHasMemGen() || idHasMemStk() || idHasMemAdr();
1354         }
1355         bool idHasMemRead() const
1356         {
1357             return idHasMemGenRead() || idHasMemStkRead() || idHasMemAdrRead();
1358         }
1359         bool idHasMemWrite() const
1360         {
1361             return idHasMemGenWrite() || idHasMemStkWrite() || idHasMemAdrWrite();
1362         }
1363 #endif // defined(TARGET_XARCH)
1364 #ifdef TARGET_ARMARCH
1365         insOpts idInsOpt() const
1366         {
1367             return (insOpts)_idInsOpt;
1368         }
1369         void idInsOpt(insOpts opt)
1370         {
1371             _idInsOpt = opt;
1372             assert(opt == _idInsOpt);
1373         }
1374
1375         regNumber idReg3() const
1376         {
1377             assert(!idIsSmallDsc());
1378             return idAddr()->_idReg3;
1379         }
1380         void idReg3(regNumber reg)
1381         {
1382             assert(!idIsSmallDsc());
1383             idAddr()->_idReg3 = reg;
1384             assert(reg == idAddr()->_idReg3);
1385         }
1386         regNumber idReg4() const
1387         {
1388             assert(!idIsSmallDsc());
1389             return idAddr()->_idReg4;
1390         }
1391         void idReg4(regNumber reg)
1392         {
1393             assert(!idIsSmallDsc());
1394             idAddr()->_idReg4 = reg;
1395             assert(reg == idAddr()->_idReg4);
1396         }
1397 #ifdef TARGET_ARM64
1398         bool idReg3Scaled() const
1399         {
1400             assert(!idIsSmallDsc());
1401             return (idAddr()->_idReg3Scaled == 1);
1402         }
1403         void idReg3Scaled(bool val)
1404         {
1405             assert(!idIsSmallDsc());
1406             idAddr()->_idReg3Scaled = val ? 1 : 0;
1407         }
1408 #endif // TARGET_ARM64
1409
1410 #endif // TARGET_ARMARCH
1411
1412 #ifdef TARGET_LOONGARCH64
1413         insOpts idInsOpt() const
1414         {
1415             return (insOpts)_idInsOpt;
1416         }
1417         void idInsOpt(insOpts opt)
1418         {
1419             _idInsOpt = opt;
1420             assert(opt == _idInsOpt);
1421         }
1422
1423         regNumber idReg3() const
1424         {
1425             assert(!idIsSmallDsc());
1426             return idAddr()->_idReg3;
1427         }
1428         void idReg3(regNumber reg)
1429         {
1430             assert(!idIsSmallDsc());
1431             idAddr()->_idReg3 = reg;
1432             assert(reg == idAddr()->_idReg3);
1433         }
1434         regNumber idReg4() const
1435         {
1436             assert(!idIsSmallDsc());
1437             return idAddr()->_idReg4;
1438         }
1439         void idReg4(regNumber reg)
1440         {
1441             assert(!idIsSmallDsc());
1442             idAddr()->_idReg4 = reg;
1443             assert(reg == idAddr()->_idReg4);
1444         }
1445
1446 #endif // TARGET_LOONGARCH64
1447
1448 #ifdef TARGET_RISCV64
1449         insOpts idInsOpt() const
1450         {
1451             return (insOpts)_idInsOpt;
1452         }
1453         void idInsOpt(insOpts opt)
1454         {
1455             _idInsOpt = opt;
1456             assert(opt == _idInsOpt);
1457         }
1458
1459         regNumber idReg3() const
1460         {
1461             assert(!idIsSmallDsc());
1462             return idAddr()->_idReg3;
1463         }
1464         void idReg3(regNumber reg)
1465         {
1466             assert(!idIsSmallDsc());
1467             idAddr()->_idReg3 = reg;
1468             assert(reg == idAddr()->_idReg3);
1469         }
1470         regNumber idReg4() const
1471         {
1472             assert(!idIsSmallDsc());
1473             return idAddr()->_idReg4;
1474         }
1475         void idReg4(regNumber reg)
1476         {
1477             assert(!idIsSmallDsc());
1478             idAddr()->_idReg4 = reg;
1479             assert(reg == idAddr()->_idReg4);
1480         }
1481
1482 #endif // TARGET_RISCV64
1483
1484         inline static bool fitsInSmallCns(cnsval_ssize_t val)
1485         {
1486             return ((val >= ID_MIN_SMALL_CNS) && (val <= ID_MAX_SMALL_CNS));
1487         }
1488
1489         bool idIsLargeCns() const
1490         {
1491             return _idLargeCns != 0;
1492         }
1493         void idSetIsLargeCns()
1494         {
1495             _idLargeCns = 1;
1496         }
1497
1498         bool idIsLargeDsp() const
1499         {
1500             return _idLargeDsp != 0;
1501         }
1502         void idSetIsLargeDsp()
1503         {
1504             _idLargeDsp = 1;
1505         }
1506         void idSetIsSmallDsp()
1507         {
1508             _idLargeDsp = 0;
1509         }
1510
1511         bool idIsLargeCall() const
1512         {
1513             return _idLargeCall != 0;
1514         }
1515         void idSetIsLargeCall()
1516         {
1517             _idLargeCall = 1;
1518         }
1519
1520         bool idIsBound() const
1521         {
1522             return _idBound != 0;
1523         }
1524         void idSetIsBound()
1525         {
1526             _idBound = 1;
1527         }
1528
1529         bool idIsCallRegPtr() const
1530         {
1531             return _idCallRegPtr != 0;
1532         }
1533         void idSetIsCallRegPtr()
1534         {
1535             _idCallRegPtr = 1;
1536         }
1537
1538         // Only call instructions that call helper functions may be marked as "IsNoGC", indicating
1539         // that a thread executing such a call cannot be stopped for GC.  Thus, in partially-interruptible
1540         // code, it is not necessary to generate GC info for a call so labeled.
1541         bool idIsNoGC() const
1542         {
1543             return _idNoGC != 0;
1544         }
1545         void idSetIsNoGC(bool val)
1546         {
1547             _idNoGC = val;
1548         }
1549
1550 #ifdef TARGET_XARCH
1551         bool idIsEvexbContext() const
1552         {
1553             return _idEvexbContext != 0;
1554         }
1555         void idSetEvexbContext()
1556         {
1557             assert(_idEvexbContext == 0);
1558             _idEvexbContext = 1;
1559             assert(_idEvexbContext == 1);
1560         }
1561 #endif
1562
1563 #ifdef TARGET_ARMARCH
1564         bool idIsLclVar() const
1565         {
1566             return _idLclVar != 0;
1567         }
1568         void idSetIsLclVar()
1569         {
1570             _idLclVar = 1;
1571         }
1572 #ifdef TARGET_ARM64
1573         bool idIsLclVarPair() const
1574         {
1575             return _idLclVarPair != 0;
1576         }
1577         void idSetIsLclVarPair()
1578         {
1579             _idLclVarPair = 1;
1580         }
1581 #endif // TARGET_ARM64
1582 #endif // TARGET_ARMARCH
1583
1584 #if defined(TARGET_ARM)
1585         bool idIsLclFPBase() const
1586         {
1587             return _idLclFPBase != 0;
1588         }
1589         void idSetIsLclFPBase()
1590         {
1591             _idLclFPBase = 1;
1592         }
1593 #endif // defined(TARGET_ARM)
1594
1595 #ifdef TARGET_LOONGARCH64
1596         bool idIsLclVar() const
1597         {
1598             return _idLclVar != 0;
1599         }
1600         void idSetIsLclVar()
1601         {
1602             _idLclVar = 1;
1603         }
1604 #endif // TARGET_LOONGARCH64
1605
1606 #ifdef TARGET_RISCV64
1607         bool idIsLclVar() const
1608         {
1609             return _idLclVar != 0;
1610         }
1611         void idSetIsLclVar()
1612         {
1613             _idLclVar = 1;
1614         }
1615 #endif // TARGET_RISCV64
1616
1617         bool idIsCnsReloc() const
1618         {
1619             return _idCnsReloc != 0;
1620         }
1621         void idSetIsCnsReloc()
1622         {
1623             _idCnsReloc = 1;
1624         }
1625
1626         bool idIsDspReloc() const
1627         {
1628             return _idDspReloc != 0;
1629         }
1630         void idSetIsDspReloc(bool val = true)
1631         {
1632             _idDspReloc = val;
1633         }
1634         bool idIsReloc() const
1635         {
1636             return idIsDspReloc() || idIsCnsReloc();
1637         }
1638
1639         void idSetRelocFlags(emitAttr attr)
1640         {
1641             _idCnsReloc = (EA_IS_CNS_RELOC(attr) ? 1 : 0);
1642             _idDspReloc = (EA_IS_DSP_RELOC(attr) ? 1 : 0);
1643         }
1644
1645 #if EMIT_BACKWARDS_NAVIGATION
1646
1647         // Return the stored size of the previous instrDesc in bytes, or zero if there
1648         // is no previous instrDesc in this group.
1649         unsigned idPrevSize()
1650         {
1651             return _idScaledPrevOffset * 4;
1652         }
1653         void idSetPrevSize(unsigned prevInstrDescSizeInBytes)
1654         {
1655             assert(prevInstrDescSizeInBytes % 4 == 0);
1656             _idScaledPrevOffset = prevInstrDescSizeInBytes / 4;
1657             assert(idPrevSize() == prevInstrDescSizeInBytes);
1658         }
1659
1660 #endif // EMIT_BACKWARDS_NAVIGATION
1661
1662         signed idSmallCns() const
1663         {
1664             return _idSmallCns;
1665         }
1666         void idSmallCns(cnsval_ssize_t value)
1667         {
1668             assert(fitsInSmallCns(value));
1669             _idSmallCns = value;
1670             assert(value == idSmallCns());
1671         }
1672
1673         inline const idAddrUnion* idAddr() const
1674         {
1675             assert(!idIsSmallDsc());
1676             return &this->_idAddrUnion;
1677         }
1678
1679         inline idAddrUnion* idAddr()
1680         {
1681             assert(!idIsSmallDsc());
1682             return &this->_idAddrUnion;
1683         }
1684     }; // End of  struct instrDesc
1685
1686 #if defined(TARGET_XARCH)
1687     insFormat getMemoryOperation(instrDesc* id) const;
1688     insFormat ExtractMemoryFormat(insFormat insFmt) const;
1689 #elif defined(TARGET_ARM64)
1690     void getMemoryOperation(instrDesc* id, unsigned* pMemAccessKind, bool* pIsLocalAccess);
1691 #endif
1692
1693 #if defined(DEBUG) || defined(LATE_DISASM)
1694
1695 #define PERFSCORE_THROUGHPUT_ILLEGAL -1024.0f
1696
1697 #define PERFSCORE_THROUGHPUT_ZERO 0.0f // Only used for pseudo-instructions that don't generate code
1698
1699 #define PERFSCORE_THROUGHPUT_6X (1.0f / 6.0f) // Hextuple issue
1700 #define PERFSCORE_THROUGHPUT_5X 0.20f         // Pentuple issue
1701 #define PERFSCORE_THROUGHPUT_4X 0.25f         // Quad issue
1702 #define PERFSCORE_THROUGHPUT_3X (1.0f / 3.0f) // Three issue
1703 #define PERFSCORE_THROUGHPUT_2X 0.5f          // Dual issue
1704
1705 #define PERFSCORE_THROUGHPUT_1C 1.0f // Single Issue
1706
1707 #define PERFSCORE_THROUGHPUT_2C 2.0f     // slower - 2 cycles
1708 #define PERFSCORE_THROUGHPUT_3C 3.0f     // slower - 3 cycles
1709 #define PERFSCORE_THROUGHPUT_4C 4.0f     // slower - 4 cycles
1710 #define PERFSCORE_THROUGHPUT_5C 5.0f     // slower - 5 cycles
1711 #define PERFSCORE_THROUGHPUT_6C 6.0f     // slower - 6 cycles
1712 #define PERFSCORE_THROUGHPUT_7C 7.0f     // slower - 7 cycles
1713 #define PERFSCORE_THROUGHPUT_8C 8.0f     // slower - 8 cycles
1714 #define PERFSCORE_THROUGHPUT_9C 9.0f     // slower - 9 cycles
1715 #define PERFSCORE_THROUGHPUT_10C 10.0f   // slower - 10 cycles
1716 #define PERFSCORE_THROUGHPUT_13C 13.0f   // slower - 13 cycles
1717 #define PERFSCORE_THROUGHPUT_19C 19.0f   // slower - 19 cycles
1718 #define PERFSCORE_THROUGHPUT_25C 25.0f   // slower - 25 cycles
1719 #define PERFSCORE_THROUGHPUT_33C 33.0f   // slower - 33 cycles
1720 #define PERFSCORE_THROUGHPUT_50C 50.0f   // slower - 50 cycles
1721 #define PERFSCORE_THROUGHPUT_52C 52.0f   // slower - 52 cycles
1722 #define PERFSCORE_THROUGHPUT_57C 57.0f   // slower - 57 cycles
1723 #define PERFSCORE_THROUGHPUT_140C 140.0f // slower - 140 cycles
1724
1725 #define PERFSCORE_LATENCY_ILLEGAL -1024.0f
1726
1727 #define PERFSCORE_LATENCY_ZERO 0.0f
1728 #define PERFSCORE_LATENCY_1C 1.0f
1729 #define PERFSCORE_LATENCY_2C 2.0f
1730 #define PERFSCORE_LATENCY_3C 3.0f
1731 #define PERFSCORE_LATENCY_4C 4.0f
1732 #define PERFSCORE_LATENCY_5C 5.0f
1733 #define PERFSCORE_LATENCY_6C 6.0f
1734 #define PERFSCORE_LATENCY_7C 7.0f
1735 #define PERFSCORE_LATENCY_8C 8.0f
1736 #define PERFSCORE_LATENCY_9C 9.0f
1737 #define PERFSCORE_LATENCY_10C 10.0f
1738 #define PERFSCORE_LATENCY_11C 11.0f
1739 #define PERFSCORE_LATENCY_12C 12.0f
1740 #define PERFSCORE_LATENCY_13C 13.0f
1741 #define PERFSCORE_LATENCY_15C 15.0f
1742 #define PERFSCORE_LATENCY_16C 16.0f
1743 #define PERFSCORE_LATENCY_18C 18.0f
1744 #define PERFSCORE_LATENCY_20C 20.0f
1745 #define PERFSCORE_LATENCY_22C 22.0f
1746 #define PERFSCORE_LATENCY_23C 23.0f
1747 #define PERFSCORE_LATENCY_26C 26.0f
1748 #define PERFSCORE_LATENCY_62C 62.0f
1749 #define PERFSCORE_LATENCY_69C 69.0f
1750 #define PERFSCORE_LATENCY_140C 140.0f
1751 #define PERFSCORE_LATENCY_400C 400.0f // Intel microcode issue with these instructions
1752
1753 #define PERFSCORE_LATENCY_BRANCH_DIRECT 1.0f   // cost of an unconditional branch
1754 #define PERFSCORE_LATENCY_BRANCH_COND 2.0f     // includes cost of a possible misprediction
1755 #define PERFSCORE_LATENCY_BRANCH_INDIRECT 2.0f // includes cost of a possible misprediction
1756
1757 #if defined(TARGET_XARCH)
1758
1759 // a read,write or modify from stack location, possible def to use latency from L0 cache
1760 #define PERFSCORE_LATENCY_RD_STACK PERFSCORE_LATENCY_2C
1761 #define PERFSCORE_LATENCY_WR_STACK PERFSCORE_LATENCY_2C
1762 #define PERFSCORE_LATENCY_RD_WR_STACK PERFSCORE_LATENCY_5C
1763
1764 // a read, write or modify from constant location, possible def to use latency from L0 cache
1765 #define PERFSCORE_LATENCY_RD_CONST_ADDR PERFSCORE_LATENCY_2C
1766 #define PERFSCORE_LATENCY_WR_CONST_ADDR PERFSCORE_LATENCY_2C
1767 #define PERFSCORE_LATENCY_RD_WR_CONST_ADDR PERFSCORE_LATENCY_5C
1768
1769 // a read, write or modify from memory location, possible def to use latency from L0 or L1 cache
1770 // plus an extra cost  (of 1.0) for a increased chance  of a cache miss
1771 #define PERFSCORE_LATENCY_RD_GENERAL PERFSCORE_LATENCY_3C
1772 #define PERFSCORE_LATENCY_WR_GENERAL PERFSCORE_LATENCY_3C
1773 #define PERFSCORE_LATENCY_RD_WR_GENERAL PERFSCORE_LATENCY_6C
1774
1775 #elif defined(TARGET_ARM64) || defined(TARGET_ARM)
1776
1777 // a read,write or modify from stack location, possible def to use latency from L0 cache
1778 #define PERFSCORE_LATENCY_RD_STACK PERFSCORE_LATENCY_3C
1779 #define PERFSCORE_LATENCY_WR_STACK PERFSCORE_LATENCY_1C
1780 #define PERFSCORE_LATENCY_RD_WR_STACK PERFSCORE_LATENCY_3C
1781
1782 // a read, write or modify from constant location, possible def to use latency from L0 cache
1783 #define PERFSCORE_LATENCY_RD_CONST_ADDR PERFSCORE_LATENCY_3C
1784 #define PERFSCORE_LATENCY_WR_CONST_ADDR PERFSCORE_LATENCY_1C
1785 #define PERFSCORE_LATENCY_RD_WR_CONST_ADDR PERFSCORE_LATENCY_3C
1786
1787 // a read, write or modify from memory location, possible def to use latency from L0 or L1 cache
1788 // plus an extra cost  (of 1.0) for a increased chance  of a cache miss
1789 #define PERFSCORE_LATENCY_RD_GENERAL PERFSCORE_LATENCY_4C
1790 #define PERFSCORE_LATENCY_WR_GENERAL PERFSCORE_LATENCY_1C
1791 #define PERFSCORE_LATENCY_RD_WR_GENERAL PERFSCORE_LATENCY_4C
1792
1793 #elif defined(TARGET_LOONGARCH64)
1794 // a read,write or modify from stack location, possible def to use latency from L0 cache
1795 #define PERFSCORE_LATENCY_RD_STACK PERFSCORE_LATENCY_3C
1796 #define PERFSCORE_LATENCY_WR_STACK PERFSCORE_LATENCY_1C
1797 #define PERFSCORE_LATENCY_RD_WR_STACK PERFSCORE_LATENCY_3C
1798
1799 // a read, write or modify from constant location, possible def to use latency from L0 cache
1800 #define PERFSCORE_LATENCY_RD_CONST_ADDR PERFSCORE_LATENCY_3C
1801 #define PERFSCORE_LATENCY_WR_CONST_ADDR PERFSCORE_LATENCY_1C
1802 #define PERFSCORE_LATENCY_RD_WR_CONST_ADDR PERFSCORE_LATENCY_3C
1803
1804 // a read, write or modify from memory location, possible def to use latency from L0 or L1 cache
1805 // plus an extra cost  (of 1.0) for a increased chance  of a cache miss
1806 #define PERFSCORE_LATENCY_RD_GENERAL PERFSCORE_LATENCY_4C
1807 #define PERFSCORE_LATENCY_WR_GENERAL PERFSCORE_LATENCY_1C
1808 #define PERFSCORE_LATENCY_RD_WR_GENERAL PERFSCORE_LATENCY_4C
1809
1810 #elif defined(TARGET_RISCV64)
1811 // a read,write or modify from stack location, possible def to use latency from L0 cache
1812 #define PERFSCORE_LATENCY_RD_STACK PERFSCORE_LATENCY_3C
1813 #define PERFSCORE_LATENCY_WR_STACK PERFSCORE_LATENCY_1C
1814 #define PERFSCORE_LATENCY_RD_WR_STACK PERFSCORE_LATENCY_3C
1815
1816 // a read, write or modify from constant location, possible def to use latency from L0 cache
1817 #define PERFSCORE_LATENCY_RD_CONST_ADDR PERFSCORE_LATENCY_3C
1818 #define PERFSCORE_LATENCY_WR_CONST_ADDR PERFSCORE_LATENCY_1C
1819 #define PERFSCORE_LATENCY_RD_WR_CONST_ADDR PERFSCORE_LATENCY_3C
1820
1821 // a read, write or modify from memory location, possible def to use latency from L0 or L1 cache
1822 // plus an extra cost  (of 1.0) for a increased chance  of a cache miss
1823 #define PERFSCORE_LATENCY_RD_GENERAL PERFSCORE_LATENCY_4C
1824 #define PERFSCORE_LATENCY_WR_GENERAL PERFSCORE_LATENCY_1C
1825 #define PERFSCORE_LATENCY_RD_WR_GENERAL PERFSCORE_LATENCY_4C
1826
1827 #endif // TARGET_XXX
1828
1829 // Make this an enum:
1830 //
1831 #define PERFSCORE_MEMORY_NONE 0
1832 #define PERFSCORE_MEMORY_READ 1
1833 #define PERFSCORE_MEMORY_WRITE 2
1834 #define PERFSCORE_MEMORY_READ_WRITE 3
1835
1836 #define PERFSCORE_CODESIZE_COST_HOT 0.10f
1837 #define PERFSCORE_CODESIZE_COST_COLD 0.01f
1838
1839 #define PERFSCORE_CALLEE_SPILL_COST 0.75f
1840
1841     struct insExecutionCharacteristics
1842     {
1843         float    insThroughput;
1844         float    insLatency;
1845         unsigned insMemoryAccessKind;
1846     };
1847
1848     float insEvaluateExecutionCost(instrDesc* id);
1849
1850     insExecutionCharacteristics getInsExecutionCharacteristics(instrDesc* id);
1851
1852     void perfScoreUnhandledInstruction(instrDesc* id, insExecutionCharacteristics* result);
1853
1854 #endif // defined(DEBUG) || defined(LATE_DISASM)
1855
1856     weight_t getCurrentBlockWeight();
1857
1858     void dispIns(instrDesc* id);
1859
1860     void appendToCurIG(instrDesc* id);
1861
1862     /********************************************************************************************/
1863
1864     struct instrDescJmp : instrDesc
1865     {
1866         instrDescJmp() = delete;
1867
1868         instrDescJmp* idjNext; // next jump in the group/method
1869         insGroup*     idjIG;   // containing group
1870
1871         union {
1872             BYTE* idjAddr; // address of jump ins (for patching)
1873         } idjTemp;
1874
1875         // Before jump emission, this is the byte offset within IG of the jump instruction.
1876         // After emission, for forward jumps, this is the target offset -- in bytes from the
1877         // beginning of the function -- of the target instruction of the jump, used to
1878         // determine if this jump needs to be patched.
1879         unsigned idjOffs :
1880 #if defined(TARGET_XARCH)
1881             29;
1882         // indicates that the jump was added at the end of a BBJ_ALWAYS basic block and is
1883         // a candidate for being removed if it jumps to the next instruction
1884         unsigned idjIsRemovableJmpCandidate : 1;
1885 #else
1886             30;
1887 #endif
1888         unsigned idjShort : 1;    // is the jump known to be a short one?
1889         unsigned idjKeepLong : 1; // should the jump be kept long? (used for hot to cold and cold to hot jumps)
1890     };
1891
1892 #if FEATURE_LOOP_ALIGN
1893     struct instrDescAlign : instrDesc
1894     {
1895         instrDescAlign() = delete;
1896
1897         instrDescAlign* idaNext;           // next align in the group/method
1898         insGroup*       idaIG;             // containing group
1899         insGroup*       idaLoopHeadPredIG; // The IG before the loop IG.
1900                                            // If no 'jmp' instructions were found until idaLoopHeadPredIG,
1901                                            // then idaLoopHeadPredIG == idaIG.
1902 #ifdef DEBUG
1903         bool isPlacedAfterJmp; // Is the 'align' instruction placed after jmp. Used to decide
1904                                // if the instruction cost should be included in PerfScore
1905                                // calculation or not.
1906 #endif
1907
1908         inline insGroup* loopHeadIG()
1909         {
1910             assert(idaLoopHeadPredIG);
1911             return idaLoopHeadPredIG->igNext;
1912         }
1913
1914         void removeAlignFlags()
1915         {
1916             idaIG->igFlags &= ~IGF_HAS_ALIGN;
1917             idaIG->igFlags |= IGF_REMOVED_ALIGN;
1918         }
1919     };
1920     void emitCheckAlignFitInCurIG(unsigned nAlignInstr);
1921 #endif // FEATURE_LOOP_ALIGN
1922
1923 #if !defined(TARGET_ARM64) // This shouldn't be needed for ARM32, either, but I don't want to touch the ARM32 JIT.
1924     struct instrDescLbl : instrDescJmp
1925     {
1926         emitLclVarAddr dstLclVar;
1927     };
1928 #endif // !TARGET_ARM64
1929
1930     struct instrDescCns : instrDesc // large const
1931     {
1932         instrDescCns() = delete;
1933
1934         cnsval_ssize_t idcCnsVal;
1935     };
1936
1937     struct instrDescDsp : instrDesc // large displacement
1938     {
1939         instrDescDsp() = delete;
1940
1941         target_ssize_t iddDspVal;
1942     };
1943
1944     struct instrDescCnsDsp : instrDesc // large cons + disp
1945     {
1946         instrDescCnsDsp() = delete;
1947
1948         target_ssize_t iddcCnsVal;
1949         int            iddcDspVal;
1950     };
1951
1952 #ifdef TARGET_XARCH
1953
1954     struct instrDescAmd : instrDesc // large addrmode disp
1955     {
1956         instrDescAmd() = delete;
1957
1958         ssize_t idaAmdVal;
1959     };
1960
1961     struct instrDescCnsAmd : instrDesc // large cons + addrmode disp
1962     {
1963         instrDescCnsAmd() = delete;
1964
1965         ssize_t idacCnsVal;
1966         ssize_t idacAmdVal;
1967     };
1968
1969 #endif // TARGET_XARCH
1970
1971 #ifdef TARGET_ARM64
1972     struct instrDescLclVarPair : instrDesc // contains 2 gc vars to be tracked
1973     {
1974         instrDescLclVarPair() = delete;
1975
1976         emitLclVarAddr iiaLclVar2;
1977     };
1978
1979     struct instrDescLclVarPairCns : instrDescCns // contains 2 gc vars to be tracked, with large cons
1980     {
1981         instrDescLclVarPairCns() = delete;
1982
1983         emitLclVarAddr iiaLclVar2;
1984     };
1985 #endif
1986
1987     struct instrDescCGCA : instrDesc // call with ...
1988     {
1989         instrDescCGCA() = delete;
1990
1991         VARSET_TP idcGCvars;    // ... updated GC vars or
1992         ssize_t   idcDisp;      // ... big addrmode disp
1993         regMaskTP idcGcrefRegs; // ... gcref registers
1994         regMaskTP idcByrefRegs; // ... byref registers
1995         unsigned  idcArgCnt;    // ... lots of args or (<0 ==> caller pops args)
1996
1997 #if MULTIREG_HAS_SECOND_GC_RET
1998         // This method handle the GC-ness of the second register in a 2 register returned struct on System V.
1999         GCtype idSecondGCref() const
2000         {
2001             return (GCtype)_idcSecondRetRegGCType;
2002         }
2003         void idSecondGCref(GCtype gctype)
2004         {
2005             _idcSecondRetRegGCType = gctype;
2006         }
2007
2008     private:
2009         // This member stores the GC-ness of the second register in a 2 register returned struct on System V.
2010         // It is added to the call struct since it is not needed by the base instrDesc struct, which keeps GC-ness
2011         // of the first register for the instCall nodes.
2012         // The base instrDesc is very carefully kept to be no more than 128 bytes. There is no more space to add members
2013         // for keeping GC-ness of the second return registers. It will also bloat the base struct unnecessarily
2014         // since the GC-ness of the second register is only needed for call instructions.
2015         // The base struct's member keeping the GC-ness of the first return register is _idGCref.
2016         GCtype _idcSecondRetRegGCType : 2; // ... GC type for the second return register.
2017 #endif                                     // MULTIREG_HAS_SECOND_GC_RET
2018     };
2019
2020     // TODO-Cleanup: Uses of stack-allocated instrDescs should be refactored to be unnecessary.
2021     template <typename T>
2022     struct inlineInstrDesc
2023     {
2024     private:
2025         instrDescDebugInfo* idDebugInfo;
2026         alignas(alignof(T)) char idStorage[sizeof(T)];
2027
2028     public:
2029         inlineInstrDesc() : idDebugInfo(nullptr), idStorage()
2030         {
2031             static_assert_no_msg((offsetof(inlineInstrDesc<T>, idStorage) - sizeof(instrDescDebugInfo*)) ==
2032                                  offsetof(inlineInstrDesc<T>, idDebugInfo));
2033         }
2034
2035         T* id()
2036         {
2037             return reinterpret_cast<T*>(idStorage);
2038         }
2039     };
2040
2041 #ifdef TARGET_ARM
2042
2043     struct instrDescReloc : instrDesc
2044     {
2045         instrDescReloc() = delete;
2046
2047         BYTE* idrRelocVal;
2048     };
2049
2050     BYTE* emitGetInsRelocValue(instrDesc* id);
2051
2052 #endif // TARGET_ARM
2053
2054     insUpdateModes emitInsUpdateMode(instruction ins);
2055     insFormat emitInsModeFormat(instruction ins, insFormat base);
2056
2057     static const BYTE emitInsModeFmtTab[];
2058 #ifdef DEBUG
2059     static const unsigned emitInsModeFmtCnt;
2060 #endif
2061
2062     size_t emitGetInstrDescSize(const instrDesc* id);
2063
2064 #ifdef TARGET_XARCH
2065
2066     ssize_t emitGetInsCns(instrDesc* id);
2067     ssize_t emitGetInsDsp(instrDesc* id);
2068     ssize_t emitGetInsAmd(instrDesc* id);
2069
2070     ssize_t emitGetInsCIdisp(instrDesc* id);
2071     unsigned emitGetInsCIargs(instrDesc* id);
2072
2073     inline emitAttr emitGetMemOpSize(instrDesc* id) const;
2074     inline emitAttr emitGetBaseMemOpSize(instrDesc*) const;
2075
2076     // Return the argument count for a direct call "id".
2077     int emitGetInsCDinfo(instrDesc* id);
2078
2079     static const IS_INFO emitGetSchedInfo(insFormat f);
2080 #endif // TARGET_XARCH
2081
2082     cnsval_ssize_t emitGetInsSC(const instrDesc* id) const;
2083     unsigned emitInsCount;
2084
2085     /************************************************************************/
2086     /*           A few routines used for debug display purposes             */
2087     /************************************************************************/
2088
2089     static const char* emitIfName(unsigned f);
2090
2091 #ifdef DEBUG
2092     unsigned emitVarRefOffs;
2093 #else // !DEBUG
2094 #define emitVarRefOffs 0
2095 #endif // !DEBUG
2096
2097     const char* emitRegName(regNumber reg, emitAttr size = EA_PTRSIZE, bool varName = true) const;
2098     const char* emitFloatRegName(regNumber reg, emitAttr size = EA_PTRSIZE, bool varName = true);
2099
2100     // GC Info changes are not readily available at each instruction.
2101     // We use debug-only sets to track the per-instruction state, and to remember
2102     // what the state was at the last time it was output (instruction or label).
2103     VARSET_TP  debugPrevGCrefVars;
2104     VARSET_TP  debugThisGCrefVars;
2105     regPtrDsc* debugPrevRegPtrDsc;
2106     regMaskTP  debugPrevGCrefRegs;
2107     regMaskTP  debugPrevByrefRegs;
2108     void       emitDispInsIndent();
2109     void emitDispGCDeltaTitle(const char* title);
2110     void emitDispGCRegDelta(const char* title, regMaskTP prevRegs, regMaskTP curRegs);
2111     void emitDispGCVarDelta();
2112     void emitDispRegPtrListDelta();
2113     void emitDispGCInfoDelta();
2114
2115     void emitDispIGflags(unsigned flags);
2116     void emitDispIG(insGroup* ig,
2117                     bool      displayFunc         = false,
2118                     bool      displayInstructions = false,
2119                     bool      displayLocation     = true);
2120     void emitDispIGlist(bool displayInstructions = false);
2121     void emitDispGCinfo();
2122     void emitDispJumpList();
2123     void emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool reloc = false);
2124     void emitDispFrameRef(int varx, int disp, int offs, bool asmfm);
2125     void emitDispInsAddr(const BYTE* code);
2126     void emitDispInsOffs(unsigned offs, bool doffs);
2127     void emitDispInsHex(instrDesc* id, BYTE* code, size_t sz);
2128     void emitDispEmbBroadcastCount(instrDesc* id);
2129     void emitDispIns(instrDesc* id,
2130                      bool       isNew,
2131                      bool       doffs,
2132                      bool       asmfm,
2133                      unsigned   offs  = 0,
2134                      BYTE*      pCode = nullptr,
2135                      size_t     sz    = 0,
2136                      insGroup*  ig    = nullptr);
2137
2138     /************************************************************************/
2139     /*                      Method prolog and epilog                        */
2140     /************************************************************************/
2141
2142     unsigned emitPrologEndPos;
2143
2144     unsigned       emitEpilogCnt;
2145     UNATIVE_OFFSET emitEpilogSize;
2146
2147 #ifdef TARGET_XARCH
2148
2149     void           emitStartExitSeq(); // Mark the start of the "return" sequence
2150     emitLocation   emitExitSeqBegLoc;
2151     UNATIVE_OFFSET emitExitSeqSize; // minimum size of any return sequence - the 'ret' after the epilog
2152
2153 #endif // TARGET_XARCH
2154
2155     insGroup* emitPlaceholderList; // per method placeholder list - head
2156     insGroup* emitPlaceholderLast; // per method placeholder list - tail
2157
2158 #ifdef JIT32_GCENCODER
2159
2160     // The x86 GC encoder needs to iterate over a list of epilogs to generate a table of
2161     // epilog offsets. Epilogs always start at the beginning of an IG, so save the first
2162     // IG of the epilog, and use it to find the epilog offset at the end of code generation.
2163     struct EpilogList
2164     {
2165         EpilogList*  elNext;
2166         emitLocation elLoc;
2167
2168         EpilogList() : elNext(nullptr), elLoc()
2169         {
2170         }
2171     };
2172
2173     EpilogList* emitEpilogList; // per method epilog list - head
2174     EpilogList* emitEpilogLast; // per method epilog list - tail
2175
2176 public:
2177     void emitStartEpilog();
2178
2179     bool emitHasEpilogEnd();
2180
2181     size_t emitGenEpilogLst(size_t (*fp)(void*, unsigned), void* cp);
2182
2183 #endif // JIT32_GCENCODER
2184
2185     void emitBegPrologEpilog(insGroup* igPh);
2186     void emitEndPrologEpilog();
2187
2188     void emitBegFnEpilog(insGroup* igPh);
2189     void emitEndFnEpilog();
2190
2191 #if defined(FEATURE_EH_FUNCLETS)
2192
2193     void emitBegFuncletProlog(insGroup* igPh);
2194     void emitEndFuncletProlog();
2195
2196     void emitBegFuncletEpilog(insGroup* igPh);
2197     void emitEndFuncletEpilog();
2198
2199 #endif // FEATURE_EH_FUNCLETS
2200
2201     /************************************************************************/
2202     /*    Methods to record a code position and later convert to offset     */
2203     /************************************************************************/
2204
2205     unsigned emitFindInsNum(const insGroup* ig, const instrDesc* id) const;
2206     UNATIVE_OFFSET emitFindOffset(const insGroup* ig, unsigned insNum) const;
2207
2208 /************************************************************************/
2209 /*        Members and methods used to issue (encode) instructions.      */
2210 /************************************************************************/
2211
2212 #ifdef DEBUG
2213     // If we have started issuing instructions from the list of instrDesc, this is set
2214     bool emitIssuing;
2215 #endif
2216
2217     BYTE*  emitCodeBlock;     // Hot code block
2218     BYTE*  emitColdCodeBlock; // Cold code block
2219     BYTE*  emitConsBlock;     // Read-only (constant) data block
2220     size_t writeableOffset;   // Offset applied to a code address to get memory location that can be written
2221
2222     UNATIVE_OFFSET emitTotalHotCodeSize;
2223     UNATIVE_OFFSET emitTotalColdCodeSize;
2224
2225     UNATIVE_OFFSET emitCurCodeOffs(const BYTE* dst) const
2226     {
2227         size_t distance;
2228         if ((dst >= emitCodeBlock) && (dst <= (emitCodeBlock + emitTotalHotCodeSize)))
2229         {
2230             distance = (dst - emitCodeBlock);
2231         }
2232         else
2233         {
2234             assert(emitFirstColdIG);
2235             assert(emitColdCodeBlock);
2236             assert((dst >= emitColdCodeBlock) && (dst <= (emitColdCodeBlock + emitTotalColdCodeSize)));
2237
2238             distance = (dst - emitColdCodeBlock + emitTotalHotCodeSize);
2239         }
2240         noway_assert((UNATIVE_OFFSET)distance == distance);
2241         return (UNATIVE_OFFSET)distance;
2242     }
2243
2244     BYTE* emitOffsetToPtr(UNATIVE_OFFSET offset) const
2245     {
2246         if (offset < emitTotalHotCodeSize)
2247         {
2248             return emitCodeBlock + offset;
2249         }
2250         else
2251         {
2252             assert(offset < (emitTotalHotCodeSize + emitTotalColdCodeSize));
2253
2254             return emitColdCodeBlock + (offset - emitTotalHotCodeSize);
2255         }
2256     }
2257
2258     BYTE* emitDataOffsetToPtr(UNATIVE_OFFSET offset)
2259     {
2260         assert(offset < emitDataSize());
2261         return emitConsBlock + offset;
2262     }
2263
2264     bool emitJumpCrossHotColdBoundary(size_t srcOffset, size_t dstOffset)
2265     {
2266         if (emitTotalColdCodeSize == 0)
2267         {
2268             return false;
2269         }
2270
2271         assert(srcOffset < (emitTotalHotCodeSize + emitTotalColdCodeSize));
2272         assert(dstOffset < (emitTotalHotCodeSize + emitTotalColdCodeSize));
2273
2274         return ((srcOffset < emitTotalHotCodeSize) != (dstOffset < emitTotalHotCodeSize));
2275     }
2276
2277     unsigned char emitOutputByte(BYTE* dst, ssize_t val);
2278     unsigned char emitOutputWord(BYTE* dst, ssize_t val);
2279     unsigned char emitOutputLong(BYTE* dst, ssize_t val);
2280     unsigned char emitOutputSizeT(BYTE* dst, ssize_t val);
2281
2282 #if !defined(HOST_64BIT)
2283 #if defined(TARGET_X86)
2284     unsigned char emitOutputByte(BYTE* dst, size_t val);
2285     unsigned char emitOutputWord(BYTE* dst, size_t val);
2286     unsigned char emitOutputLong(BYTE* dst, size_t val);
2287     unsigned char emitOutputSizeT(BYTE* dst, size_t val);
2288
2289     unsigned char emitOutputByte(BYTE* dst, unsigned __int64 val);
2290     unsigned char emitOutputWord(BYTE* dst, unsigned __int64 val);
2291     unsigned char emitOutputLong(BYTE* dst, unsigned __int64 val);
2292     unsigned char emitOutputSizeT(BYTE* dst, unsigned __int64 val);
2293 #endif // defined(TARGET_X86)
2294 #endif // !defined(HOST_64BIT)
2295
2296 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
2297     unsigned int emitCounts_INS_OPTS_J;
2298 #endif // TARGET_LOONGARCH64 || TARGET_RISCV64
2299
2300     instrDesc* emitFirstInstrDesc(BYTE* idData) const;
2301     void emitAdvanceInstrDesc(instrDesc** id, size_t idSize) const;
2302     size_t emitIssue1Instr(insGroup* ig, instrDesc* id, BYTE** dp);
2303     size_t emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp);
2304
2305     bool emitHasFramePtr;
2306
2307 #ifdef PSEUDORANDOM_NOP_INSERTION
2308     bool emitInInstrumentation;
2309 #endif // PSEUDORANDOM_NOP_INSERTION
2310
2311 #ifdef DEBUG
2312     bool emitChkAlign; // perform some alignment checks
2313 #endif
2314
2315     insGroup* emitCurIG;
2316
2317     void emitSetShortJump(instrDescJmp* id);
2318     void emitSetMediumJump(instrDescJmp* id);
2319
2320 public:
2321     CORINFO_FIELD_HANDLE emitBlkConst(const void* cnsAddr, unsigned cnsSize, unsigned cnsAlign, var_types elemType);
2322
2323 private:
2324 #if defined(TARGET_AMD64)
2325     regMaskTP rbmFltCalleeTrash;
2326
2327     FORCEINLINE regMaskTP get_RBM_FLT_CALLEE_TRASH() const
2328     {
2329         return this->rbmFltCalleeTrash;
2330     }
2331 #endif // TARGET_AMD64
2332
2333 #if defined(TARGET_XARCH)
2334     regMaskTP rbmMskCalleeTrash;
2335
2336     FORCEINLINE regMaskTP get_RBM_MSK_CALLEE_TRASH() const
2337     {
2338         return this->rbmMskCalleeTrash;
2339     }
2340 #endif // TARGET_AMD64
2341
2342     CORINFO_FIELD_HANDLE emitFltOrDblConst(double constValue, emitAttr attr);
2343 #if defined(FEATURE_SIMD)
2344     CORINFO_FIELD_HANDLE emitSimd8Const(simd8_t constValue);
2345     CORINFO_FIELD_HANDLE emitSimd16Const(simd16_t constValue);
2346 #if defined(TARGET_XARCH)
2347     CORINFO_FIELD_HANDLE emitSimd32Const(simd32_t constValue);
2348     CORINFO_FIELD_HANDLE emitSimd64Const(simd64_t constValue);
2349 #endif // TARGET_XARCH
2350 #endif // FEATURE_SIMD
2351     regNumber emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src);
2352     regNumber emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2);
2353     void emitInsLoadInd(instruction ins, emitAttr attr, regNumber dstReg, GenTreeIndir* mem);
2354     void emitInsStoreInd(instruction ins, emitAttr attr, GenTreeStoreInd* mem);
2355     void emitInsStoreLcl(instruction ins, emitAttr attr, GenTreeLclVarCommon* varNode);
2356     insFormat emitMapFmtForIns(insFormat fmt, instruction ins);
2357     insFormat emitMapFmtAtoM(insFormat fmt);
2358     void emitHandleMemOp(GenTreeIndir* indir, instrDesc* id, insFormat fmt, instruction ins);
2359     void spillIntArgRegsToShadowSlots();
2360
2361 #ifdef TARGET_XARCH
2362     bool emitIsInstrWritingToReg(instrDesc* id, regNumber reg);
2363     bool emitDoesInsModifyFlags(instruction ins);
2364 #endif // TARGET_XARCH
2365
2366     /************************************************************************/
2367     /*      The logic that creates and keeps track of instruction groups    */
2368     /************************************************************************/
2369
2370     // The IG buffer size is the size, in bytes, of the single, global instruction group buffer.
2371     // It is computed dynamically based on SC_IG_BUFFER_NUM_SMALL_DESCS, SC_IG_BUFFER_NUM_LARGE_DESCS,
2372     // and whether a debug info pointer is being saved.
2373     //
2374     // When a label is reached, or the buffer is filled, the precise amount of the buffer that was
2375     // used is copied to a newly allocated, precisely sized buffer, and the global buffer is reset
2376     // for use with the next set of instructions (see emitSavIG). If the buffer was filled before
2377     // reaching a label, the next instruction group will be an "overflow", or "extension" group
2378     // (marked with IGF_EXTEND). Thus, the size of the global buffer shouldn't matter (as long as it
2379     // can hold at least one of the largest instruction descriptor forms), since we can always overflow
2380     // to subsequent instruction groups.
2381     //
2382     // The only place where this fixed instruction group size is a problem is in the main function prolog,
2383     // where we only support a single instruction group, and no extension groups. We should really fix that.
2384     // Thus, the buffer size needs to be large enough to hold the maximum number of instructions that
2385     // can possibly be generated into the prolog instruction group. That is difficult to statically determine.
2386     //
2387     // If we do generate an overflow prolog group, we will hit a NOWAY assert and fall back to MinOpts.
2388     // This should reduce the number of instructions generated into the prolog.
2389     //
2390     // Note that OSR prologs require additional code not seen in normal prologs.
2391     //
2392     // Also, note that DEBUG and non-DEBUG builds have different instrDesc sizes, and there are multiple
2393     // sizes of instruction descriptors, so the number of instructions that will fit in the largest
2394     // instruction group depends on the instruction mix as well as DEBUG/non-DEBUG build type. See the
2395     // EMITTER_STATS output for various statistics related to this.
2396     //
2397     CLANG_FORMAT_COMMENT_ANCHOR;
2398
2399 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
2400 // ARM32/64, LoongArch and RISC-V can require a bigger prolog instruction group. One scenario
2401 // is where a function uses all the incoming integer and single-precision floating-point arguments,
2402 // and must store them all to the frame on entry. If the frame is very large, we generate
2403 // ugly code like:
2404 //     movw r10, 0x488
2405 //     add r10, sp
2406 //     vstr s0, [r10]
2407 // for each store, or, to load arguments into registers:
2408 //     movz    xip1, #0x6cd0
2409 //     movk    xip1, #2 LSL #16
2410 //     ldr     w8, [fp, xip1]        // [V10 arg10]
2411 // which eats up our insGroup buffer.
2412 #define SC_IG_BUFFER_NUM_SMALL_DESCS 0
2413 #define SC_IG_BUFFER_NUM_LARGE_DESCS 200
2414
2415 #else
2416 #define SC_IG_BUFFER_NUM_SMALL_DESCS 14
2417 #define SC_IG_BUFFER_NUM_LARGE_DESCS 50
2418 #endif // !(TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64)
2419
2420     size_t emitIGbuffSize;
2421
2422     insGroup* emitIGlist; // first  instruction group
2423     insGroup* emitIGlast; // last   instruction group
2424     insGroup* emitIGthis; // issued instruction group
2425
2426     insGroup* emitPrologIG; // prolog instruction group
2427
2428     instrDescJmp* emitJumpList;       // list of local jumps in method
2429     instrDescJmp* emitJumpLast;       // last of local jumps in method
2430     void          emitJumpDistBind(); // Bind all the local jumps in method
2431     bool          emitContainsRemovableJmpCandidates;
2432     void          emitRemoveJumpToNextInst(); // try to remove unconditional jumps to the next instruction
2433
2434 #if FEATURE_LOOP_ALIGN
2435     instrDescAlign* emitCurIGAlignList;   // list of align instructions in current IG
2436     unsigned        emitLastLoopStart;    // Start IG of last inner loop
2437     unsigned        emitLastLoopEnd;      // End IG of last inner loop
2438     unsigned        emitLastAlignedIgNum; // last IG that has align instruction
2439     instrDescAlign* emitAlignList;        // list of all align instructions in method
2440     instrDescAlign* emitAlignLast;        // last align instruction in method
2441
2442     // Points to the most recent added align instruction. If there are multiple align instructions like in arm64 or
2443     // non-adaptive alignment on xarch, this points to the first align instruction of the series of align instructions.
2444     instrDescAlign* emitAlignLastGroup;
2445
2446     unsigned getLoopSize(insGroup* igLoopHeader,
2447                          unsigned maxLoopSize DEBUG_ARG(bool isAlignAdjusted) DEBUG_ARG(UNATIVE_OFFSET containingIGNum)
2448                              DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum)); // Get the smallest loop size
2449     void emitLoopAlignment(DEBUG_ARG1(bool isPlacedBehindJmp));
2450     bool emitEndsWithAlignInstr(); // Validate if newLabel is appropriate
2451     void emitSetLoopBackEdge(BasicBlock* loopTopBlock);
2452     void     emitLoopAlignAdjustments(); // Predict if loop alignment is needed and make appropriate adjustments
2453     unsigned emitCalculatePaddingForLoopAlignment(insGroup* ig,
2454                                                   size_t offset DEBUG_ARG(bool isAlignAdjusted)
2455                                                       DEBUG_ARG(UNATIVE_OFFSET containingIGNum)
2456                                                           DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum));
2457
2458     void emitLoopAlign(unsigned paddingBytes, bool isFirstAlign DEBUG_ARG(bool isPlacedBehindJmp));
2459     void emitLongLoopAlign(unsigned alignmentBoundary DEBUG_ARG(bool isPlacedBehindJmp));
2460     instrDescAlign* emitAlignInNextIG(instrDescAlign* alignInstr);
2461     void emitConnectAlignInstrWithCurIG();
2462
2463 #endif
2464
2465     void emitCheckFuncletBranch(instrDesc* jmp, insGroup* jmpIG); // Check for illegal branches between funclets
2466
2467     bool     emitFwdJumps;         // forward jumps present?
2468     unsigned emitNoGCRequestCount; // Count of number of nested "NO GC" region requests we have.
2469     bool     emitNoGCIG;           // Are we generating IGF_NOGCINTERRUPT insGroups (for prologs, epilogs, etc.)
2470     bool emitForceNewIG; // If we generate an instruction, and not another instruction group, force create a new emitAdd
2471                          // instruction group.
2472
2473     BYTE* emitCurIGfreeNext; // next available byte in buffer
2474     BYTE* emitCurIGfreeEndp; // one byte past the last available byte in buffer
2475     BYTE* emitCurIGfreeBase; // first byte address
2476
2477     unsigned       emitCurIGinsCnt;   // # of collected instr's in buffer
2478     unsigned       emitCurIGsize;     // estimated code size of current group in bytes
2479     UNATIVE_OFFSET emitCurCodeOffset; // current code offset within group
2480     UNATIVE_OFFSET emitTotalCodeSize; // bytes of code in entire method
2481
2482     insGroup* emitFirstColdIG; // first cold instruction group
2483
2484     void emitSetFirstColdIGCookie(void* bbEmitCookie)
2485     {
2486         emitFirstColdIG = (insGroup*)bbEmitCookie;
2487     }
2488
2489     int emitOffsAdj; // current code offset adjustment
2490
2491     instrDescJmp* emitCurIGjmpList; // list of jumps   in current IG
2492
2493     // emitPrev* and emitInit* are only used during code generation, not during
2494     // emission (issuing), to determine what GC values to store into an IG.
2495     // Note that only the Vars ones are actually used, apparently due to bugs
2496     // in that tracking. See emitSavIG(): the important use of ByrefRegs is commented
2497     // out, and GCrefRegs is always saved.
2498
2499     VARSET_TP emitPrevGCrefVars;
2500     regMaskTP emitPrevGCrefRegs;
2501     regMaskTP emitPrevByrefRegs;
2502
2503     VARSET_TP emitInitGCrefVars;
2504     regMaskTP emitInitGCrefRegs;
2505     regMaskTP emitInitByrefRegs;
2506
2507     // If this is set, we ignore comparing emitPrev* and emitInit* to determine
2508     // whether to save GC state (to save space in the IG), and always save it.
2509
2510     bool emitForceStoreGCState;
2511
2512     // emitThis* variables are used during emission, to track GC updates
2513     // on a per-instruction basis. During code generation, per-instruction
2514     // tracking is done with variables gcVarPtrSetCur, gcRegGCrefSetCur,
2515     // and gcRegByrefSetCur. However, these are also used for a slightly
2516     // different purpose during code generation: to try to minimize the
2517     // amount of GC data stored to an IG, by only storing deltas from what
2518     // we expect to see at an IG boundary. Also, only emitThisGCrefVars is
2519     // really the only one used; the others seem to be calculated, but not
2520     // used due to bugs.
2521
2522     VARSET_TP emitThisGCrefVars;
2523     regMaskTP emitThisGCrefRegs; // Current set of registers holding GC references
2524     regMaskTP emitThisByrefRegs; // Current set of registers holding BYREF references
2525
2526     bool emitThisGCrefVset; // Is "emitThisGCrefVars" up to date?
2527
2528     regNumber emitSyncThisObjReg; // where is "this" enregistered for synchronized methods?
2529
2530 #if MULTIREG_HAS_SECOND_GC_RET
2531     void emitSetSecondRetRegGCType(instrDescCGCA* id, emitAttr secondRetSize);
2532 #endif // MULTIREG_HAS_SECOND_GC_RET
2533
2534     static void emitEncodeCallGCregs(regMaskTP regs, instrDesc* id);
2535     static unsigned emitDecodeCallGCregs(instrDesc* id);
2536
2537     unsigned emitNxtIGnum;
2538
2539 #ifdef PSEUDORANDOM_NOP_INSERTION
2540
2541     // random nop insertion to break up nop sleds
2542     unsigned emitNextNop;
2543     bool     emitRandomNops;
2544
2545     void emitEnableRandomNops()
2546     {
2547         emitRandomNops = true;
2548     }
2549     void emitDisableRandomNops()
2550     {
2551         emitRandomNops = false;
2552     }
2553
2554 #endif // PSEUDORANDOM_NOP_INSERTION
2555
2556     insGroup* emitAllocAndLinkIG();
2557     insGroup* emitAllocIG();
2558     void emitInitIG(insGroup* ig);
2559     void emitInsertIGAfter(insGroup* insertAfterIG, insGroup* ig);
2560
2561     void emitNewIG();
2562
2563 #if !defined(JIT32_GCENCODER)
2564     void emitDisableGC();
2565     void emitEnableGC();
2566 #endif // !defined(JIT32_GCENCODER)
2567
2568 #if defined(TARGET_XARCH)
2569     static bool emitAlignInstHasNoCode(instrDesc* id);
2570     static bool emitInstHasNoCode(instrDesc* id);
2571     static bool emitJmpInstHasNoCode(instrDesc* id);
2572 #endif
2573
2574     void emitGenIG(insGroup* ig);
2575     insGroup* emitSavIG(bool emitAdd = false);
2576     void emitNxtIG(bool extend = false);
2577
2578 #ifdef TARGET_ARM64
2579     void emitRemoveLastInstruction();
2580 #endif
2581
2582     bool emitCurIGnonEmpty()
2583     {
2584         return (emitCurIG && emitCurIGfreeNext > emitCurIGfreeBase);
2585     }
2586
2587 #define EMIT_MAX_IG_INS_COUNT 256
2588
2589 #if EMIT_BACKWARDS_NAVIGATION
2590 #define EMIT_MAX_PEEPHOLE_INS_COUNT 32 // The max number of previous instructions to navigate through for peepholes.
2591 #endif                                 // EMIT_BACKWARDS_NAVIGATION
2592
2593     instrDesc* emitLastIns;
2594     insGroup*  emitLastInsIG;
2595
2596 #if EMIT_BACKWARDS_NAVIGATION
2597     unsigned emitLastInsFullSize;
2598 #endif // EMIT_BACKWARDS_NAVIGATION
2599
2600     // Check to see if the last instruction is available.
2601     inline bool emitHasLastIns() const
2602     {
2603         return (emitLastIns != nullptr);
2604     }
2605
2606     // Checks to see if we can cross between the two given IG boundaries.
2607     //
2608     // We have the following checks:
2609     // 1. Looking backwards across an IG boundary can only be done if we're in an extension IG.
2610     // 2. The IG of the previous instruction must have the same GC interrupt status as the current IG.
2611     inline bool isInsIGSafeForPeepholeOptimization(insGroup* prevInsIG, insGroup* curInsIG) const
2612     {
2613         if (prevInsIG == curInsIG)
2614         {
2615             return true;
2616         }
2617         else
2618         {
2619             return (curInsIG->igFlags & IGF_EXTEND) &&
2620                    ((prevInsIG->igFlags & IGF_NOGCINTERRUPT) == (curInsIG->igFlags & IGF_NOGCINTERRUPT));
2621         }
2622     }
2623
2624     // Check if a peephole optimization involving emitLastIns is safe.
2625     //
2626     // We have the following checks:
2627     // 1. There must be a non-null emitLastIns to consult (thus, we have a known "last" instruction).
2628     // 2. `emitForceNewIG` is not set: this prevents peepholes from crossing nogc boundaries where
2629     //    the next instruction is forced to create a new IG.
2630     bool emitCanPeepholeLastIns() const
2631     {
2632         assert(emitHasLastIns() == (emitLastInsIG != nullptr));
2633
2634         return emitHasLastIns() && // there is an emitLastInstr
2635                !emitForceNewIG &&  // and we're not about to start a new IG.
2636                isInsIGSafeForPeepholeOptimization(emitLastInsIG, emitCurIG);
2637     }
2638
2639     enum emitPeepholeResult
2640     {
2641         PEEPHOLE_CONTINUE,
2642         PEEPHOLE_ABORT
2643     };
2644
2645     // Visits the last emitted instructions.
2646     // Must be safe to do - use emitCanPeepholeLastIns for checking.
2647     // Action is a function type: instrDesc* -> emitPeepholeResult
2648     template <typename Action>
2649     void emitPeepholeIterateLastInstrs(Action action)
2650     {
2651         assert(emitCanPeepholeLastIns());
2652
2653 #if EMIT_BACKWARDS_NAVIGATION
2654         insGroup*  curInsIG;
2655         instrDesc* id;
2656
2657         if (!emitGetLastIns(&curInsIG, &id))
2658             return;
2659
2660         for (unsigned i = 0; i < EMIT_MAX_PEEPHOLE_INS_COUNT; i++)
2661         {
2662             assert(id != nullptr);
2663
2664             switch (action(id))
2665             {
2666                 case PEEPHOLE_ABORT:
2667                     return;
2668                 case PEEPHOLE_CONTINUE:
2669                 {
2670                     insGroup* savedInsIG = curInsIG;
2671                     if (emitPrevID(curInsIG, id))
2672                     {
2673                         if (isInsIGSafeForPeepholeOptimization(curInsIG, savedInsIG))
2674                         {
2675                             continue;
2676                         }
2677                         else
2678                         {
2679                             return;
2680                         }
2681                     }
2682                     return;
2683                 }
2684
2685                 default:
2686                     unreached();
2687             }
2688         }
2689 #else  // EMIT_BACKWARDS_NAVIGATION
2690         action(emitLastIns);
2691 #endif // !EMIT_BACKWARDS_NAVIGATION
2692     }
2693
2694 #ifdef TARGET_ARMARCH
2695     instrDesc* emitLastMemBarrier;
2696 #endif
2697
2698 #ifdef DEBUG
2699     void emitCheckIGList();
2700 #endif
2701
2702     // Terminates any in-progress instruction group, making the current IG a new empty one.
2703     // Mark this instruction group as having a label; return the new instruction group.
2704     // Sets the emitter's record of the currently live GC variables
2705     // and registers.  The "isFinallyTarget" parameter indicates that the current location is
2706     // the start of a basic block that is returned to after a finally clause in non-exceptional execution.
2707     void* emitAddLabel(VARSET_VALARG_TP GCvars,
2708                        regMaskTP        gcrefRegs,
2709                        regMaskTP        byrefRegs,
2710                        bool             isFinallyTarget = false DEBUG_ARG(BasicBlock* block = nullptr));
2711
2712     // Same as above, except the label is added and is conceptually "inline" in
2713     // the current block. Thus it extends the previous block and the emitter
2714     // continues to track GC info as if there was no label.
2715     void* emitAddInlineLabel();
2716
2717     void emitPrintLabel(const insGroup* ig) const;
2718     const char* emitLabelString(const insGroup* ig) const;
2719
2720 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
2721
2722     void emitGetInstrDescs(insGroup* ig, instrDesc** id, int* insCnt);
2723
2724     bool emitGetLocationInfo(emitLocation* emitLoc, insGroup** pig, instrDesc** pid, int* pinsRemaining = NULL);
2725
2726     bool emitNextID(insGroup*& ig, instrDesc*& id, int& insRemaining);
2727
2728     typedef void (*emitProcessInstrFunc_t)(instrDesc* id, void* context);
2729
2730     void emitWalkIDs(emitLocation* locFrom, emitProcessInstrFunc_t processFunc, void* context);
2731
2732     static void emitGenerateUnwindNop(instrDesc* id, void* context);
2733
2734 #endif // TARGET_ARMARCH || TARGET_LOONGARCH64
2735
2736 #if EMIT_BACKWARDS_NAVIGATION
2737     bool emitPrevID(insGroup*& ig, instrDesc*& id);
2738     bool emitGetLastIns(insGroup** pig, instrDesc** pid);
2739 #endif // EMIT_BACKWARDS_NAVIGATION
2740
2741 #ifdef TARGET_X86
2742     void emitMarkStackLvl(unsigned stackLevel);
2743 #endif
2744
2745 #if defined(FEATURE_SIMD)
2746     void emitStoreSimd12ToLclOffset(unsigned varNum, unsigned offset, regNumber dataReg, GenTree* tmpRegProvider);
2747 #endif // FEATURE_SIMD
2748
2749     int emitNextRandomNop();
2750
2751     //
2752     // Functions for allocating instrDescs.
2753     //
2754     // The emitAllocXXX functions are the base level that allocate memory, and do little else.
2755     // The emitters themselves use emitNewXXX, which might be thin wrappers over the emitAllocXXX functions.
2756     //
2757
2758     void* emitAllocAnyInstr(size_t sz, emitAttr attr);
2759
2760     instrDesc* emitAllocInstr(emitAttr attr)
2761     {
2762 #if EMITTER_STATS
2763         emitTotalIDescCnt++;
2764 #endif // EMITTER_STATS
2765         return (instrDesc*)emitAllocAnyInstr(sizeof(instrDesc), attr);
2766     }
2767
2768     instrDescJmp* emitAllocInstrJmp()
2769     {
2770 #if EMITTER_STATS
2771         emitTotalIDescJmpCnt++;
2772 #endif // EMITTER_STATS
2773         return (instrDescJmp*)emitAllocAnyInstr(sizeof(instrDescJmp), EA_1BYTE);
2774     }
2775
2776 #if !defined(TARGET_ARM64)
2777     instrDescLbl* emitAllocInstrLbl()
2778     {
2779 #if EMITTER_STATS
2780         emitTotalIDescLblCnt++;
2781 #endif // EMITTER_STATS
2782         return (instrDescLbl*)emitAllocAnyInstr(sizeof(instrDescLbl), EA_4BYTE);
2783     }
2784 #endif // TARGET_ARM64
2785
2786 #if defined(TARGET_ARM64)
2787     instrDescLclVarPair* emitAllocInstrLclVarPair(emitAttr attr)
2788     {
2789 #if EMITTER_STATS
2790         emitTotalIDescLclVarPairCnt++;
2791 #endif // EMITTER_STATS
2792         instrDescLclVarPair* result = (instrDescLclVarPair*)emitAllocAnyInstr(sizeof(instrDescLclVarPair), attr);
2793         result->idSetIsLclVarPair();
2794         return result;
2795     }
2796
2797     instrDescLclVarPairCns* emitAllocInstrLclVarPairCns(emitAttr attr, cnsval_size_t cns)
2798     {
2799 #if EMITTER_STATS
2800         emitTotalIDescLclVarPairCnsCnt++;
2801 #endif // EMITTER_STATS
2802         instrDescLclVarPairCns* result =
2803             (instrDescLclVarPairCns*)emitAllocAnyInstr(sizeof(instrDescLclVarPairCns), attr);
2804         result->idSetIsLargeCns();
2805         result->idSetIsLclVarPair();
2806         result->idcCnsVal = cns;
2807         return result;
2808     }
2809 #endif // TARGET_ARM64
2810
2811     instrDescCns* emitAllocInstrCns(emitAttr attr)
2812     {
2813 #if EMITTER_STATS
2814         emitTotalIDescCnsCnt++;
2815 #endif // EMITTER_STATS
2816         return (instrDescCns*)emitAllocAnyInstr(sizeof(instrDescCns), attr);
2817     }
2818
2819     instrDescCns* emitAllocInstrCns(emitAttr attr, cnsval_size_t cns)
2820     {
2821         instrDescCns* result = emitAllocInstrCns(attr);
2822         result->idSetIsLargeCns();
2823         result->idcCnsVal = cns;
2824         return result;
2825     }
2826
2827     instrDescDsp* emitAllocInstrDsp(emitAttr attr)
2828     {
2829 #if EMITTER_STATS
2830         emitTotalIDescDspCnt++;
2831 #endif // EMITTER_STATS
2832         return (instrDescDsp*)emitAllocAnyInstr(sizeof(instrDescDsp), attr);
2833     }
2834
2835     instrDescCnsDsp* emitAllocInstrCnsDsp(emitAttr attr)
2836     {
2837 #if EMITTER_STATS
2838         emitTotalIDescCnsDspCnt++;
2839 #endif // EMITTER_STATS
2840         return (instrDescCnsDsp*)emitAllocAnyInstr(sizeof(instrDescCnsDsp), attr);
2841     }
2842
2843 #ifdef TARGET_XARCH
2844
2845     instrDescAmd* emitAllocInstrAmd(emitAttr attr)
2846     {
2847 #if EMITTER_STATS
2848         emitTotalIDescAmdCnt++;
2849 #endif // EMITTER_STATS
2850         return (instrDescAmd*)emitAllocAnyInstr(sizeof(instrDescAmd), attr);
2851     }
2852
2853     instrDescCnsAmd* emitAllocInstrCnsAmd(emitAttr attr)
2854     {
2855 #if EMITTER_STATS
2856         emitTotalIDescCnsAmdCnt++;
2857 #endif // EMITTER_STATS
2858         return (instrDescCnsAmd*)emitAllocAnyInstr(sizeof(instrDescCnsAmd), attr);
2859     }
2860
2861 #endif // TARGET_XARCH
2862
2863     instrDescCGCA* emitAllocInstrCGCA(emitAttr attr)
2864     {
2865 #if EMITTER_STATS
2866         emitTotalIDescCGCACnt++;
2867 #endif // EMITTER_STATS
2868         return (instrDescCGCA*)emitAllocAnyInstr(sizeof(instrDescCGCA), attr);
2869     }
2870
2871 #if FEATURE_LOOP_ALIGN
2872     instrDescAlign* emitAllocInstrAlign()
2873     {
2874 #if EMITTER_STATS
2875         emitTotalIDescAlignCnt++;
2876 #endif // EMITTER_STATS
2877         return (instrDescAlign*)emitAllocAnyInstr(sizeof(instrDescAlign), EA_1BYTE);
2878     }
2879     instrDescAlign* emitNewInstrAlign();
2880 #endif
2881
2882     instrDesc* emitNewInstrSmall(emitAttr attr);
2883     instrDesc* emitNewInstr(emitAttr attr = EA_4BYTE);
2884     instrDesc* emitNewInstrSC(emitAttr attr, cnsval_ssize_t cns);
2885     instrDesc* emitNewInstrCns(emitAttr attr, cnsval_ssize_t cns);
2886     instrDesc* emitNewInstrDsp(emitAttr attr, target_ssize_t dsp);
2887     instrDesc* emitNewInstrCnsDsp(emitAttr attr, target_ssize_t cns, int dsp);
2888 #ifdef TARGET_ARM
2889     instrDesc* emitNewInstrReloc(emitAttr attr, BYTE* addr);
2890 #endif // TARGET_ARM
2891     instrDescJmp* emitNewInstrJmp();
2892
2893 #if !defined(TARGET_ARM64)
2894     instrDescLbl* emitNewInstrLbl();
2895 #else
2896     instrDesc* emitNewInstrLclVarPair(emitAttr attr, cnsval_ssize_t cns);
2897 #endif // !TARGET_ARM64
2898
2899     static const BYTE emitFmtToOps[];
2900
2901 #ifdef DEBUG
2902     static const unsigned emitFmtCount;
2903 #endif
2904
2905     bool emitIsSmallInsDsc(instrDesc* id) const;
2906
2907     size_t emitSizeOfInsDsc(instrDesc* id) const;
2908
2909     /************************************************************************/
2910     /*        The following keeps track of stack-based GC values            */
2911     /************************************************************************/
2912
2913     unsigned emitTrkVarCnt;
2914     int*     emitGCrFrameOffsTab; // Offsets of tracked stack ptr vars (varTrkIndex -> stkOffs)
2915
2916     unsigned    emitGCrFrameOffsCnt; // Number of       tracked stack ptr vars
2917     int         emitGCrFrameOffsMin; // Min offset of a tracked stack ptr var
2918     int         emitGCrFrameOffsMax; // Max offset of a tracked stack ptr var
2919     bool        emitContTrkPtrLcls;  // All lcl between emitGCrFrameOffsMin/Max are only tracked stack ptr vars
2920     varPtrDsc** emitGCrFrameLiveTab; // Cache of currently live varPtrs (stkOffs -> varPtrDsc)
2921
2922     int emitArgFrameOffsMin;
2923     int emitArgFrameOffsMax;
2924
2925     int emitLclFrameOffsMin;
2926     int emitLclFrameOffsMax;
2927
2928     int emitSyncThisObjOffs; // what is the offset of "this" for synchronized methods?
2929
2930 public:
2931     void emitSetFrameRangeGCRs(int offsLo, int offsHi);
2932     void emitSetFrameRangeLcls(int offsLo, int offsHi);
2933     void emitSetFrameRangeArgs(int offsLo, int offsHi);
2934
2935     bool emitIsWithinFrameRangeGCRs(int offs)
2936     {
2937         return (offs >= emitGCrFrameOffsMin) && (offs < emitGCrFrameOffsMax);
2938     }
2939
2940     static instruction emitJumpKindToIns(emitJumpKind jumpKind);
2941     static emitJumpKind emitInsToJumpKind(instruction ins);
2942     static emitJumpKind emitReverseJumpKind(emitJumpKind jumpKind);
2943
2944 #ifdef DEBUG
2945 #ifndef TARGET_LOONGARCH64
2946     void emitInsSanityCheck(instrDesc* id);
2947 #endif
2948 #endif
2949
2950 #ifdef TARGET_ARMARCH
2951     // Returns true if instruction "id->idIns()" writes to a register that might be used to contain a GC
2952     // pointer. This exempts the SP and PC registers, and floating point registers. Memory access
2953     // instructions that pre- or post-increment their memory address registers are *not* considered to write
2954     // to GC registers, even if that memory address is a by-ref: such an instruction cannot change the GC
2955     // status of that register, since it must be a byref before and remains one after.
2956     //
2957     // This may return false positives.
2958     bool emitInsMayWriteToGCReg(instrDesc* id);
2959
2960     // Returns "true" if instruction "id->idIns()" writes to a LclVar stack location.
2961     bool emitInsWritesToLclVarStackLoc(instrDesc* id);
2962
2963     // Returns true if the instruction may write to more than one register.
2964     bool emitInsMayWriteMultipleRegs(instrDesc* id);
2965
2966     // Returns "true" if instruction "id->idIns()" writes to a LclVar stack slot pair.
2967     bool emitInsWritesToLclVarStackLocPair(instrDesc* id);
2968 #elif defined(TARGET_LOONGARCH64)
2969     bool emitInsMayWriteToGCReg(instruction ins);
2970     bool emitInsWritesToLclVarStackLoc(instrDesc* id);
2971 #elif defined(TARGET_RISCV64)
2972     bool emitInsMayWriteToGCReg(instruction ins);
2973     bool emitInsWritesToLclVarStackLoc(instrDesc* id);
2974 #endif // TARGET_LOONGARCH64
2975
2976     /************************************************************************/
2977     /*    The following is used to distinguish helper vs non-helper calls   */
2978     /************************************************************************/
2979
2980     static bool emitNoGChelper(CorInfoHelpFunc helpFunc);
2981     static bool emitNoGChelper(CORINFO_METHOD_HANDLE methHnd);
2982
2983     /************************************************************************/
2984     /*         The following logic keeps track of live GC ref values        */
2985     /************************************************************************/
2986
2987     bool emitFullArgInfo; // full arg info (including non-ptr arg)?
2988     bool emitFullGCinfo;  // full GC pointer maps?
2989     bool emitFullyInt;    // fully interruptible code?
2990
2991     regMaskTP emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd);
2992
2993     // Gets a register mask that represent the kill set for a NoGC helper call.
2994     regMaskTP emitGetGCRegsKilledByNoGCCall(CorInfoHelpFunc helper);
2995
2996 #if EMIT_TRACK_STACK_DEPTH
2997     unsigned emitCntStackDepth; // 0 in prolog/epilog, One DWORD elsewhere
2998     unsigned emitMaxStackDepth; // actual computed max. stack depth
2999 #endif
3000
3001     /* Stack modelling wrt GC */
3002
3003     bool emitSimpleStkUsed; // using the "simple" stack table?
3004
3005     union {
3006         struct // if emitSimpleStkUsed==true
3007         {
3008 #define BITS_IN_BYTE (8)
3009 #define MAX_SIMPLE_STK_DEPTH (BITS_IN_BYTE * sizeof(unsigned))
3010
3011             unsigned emitSimpleStkMask;      // bit per pushed dword (if it fits. Lowest bit <==> last pushed arg)
3012             unsigned emitSimpleByrefStkMask; // byref qualifier for emitSimpleStkMask
3013         } u1;
3014
3015         struct // if emitSimpleStkUsed==false
3016         {
3017             BYTE   emitArgTrackLcl[16]; // small local table to avoid malloc
3018             BYTE*  emitArgTrackTab;     // base of the argument tracking stack
3019             BYTE*  emitArgTrackTop;     // top  of the argument tracking stack
3020             USHORT emitGcArgTrackCnt;   // count of pending arg records (stk-depth for frameless methods, gc ptrs on stk
3021                                         // for framed methods)
3022         } u2;
3023     };
3024
3025     unsigned emitCurStackLvl; // amount of bytes pushed on stack
3026
3027 #if EMIT_TRACK_STACK_DEPTH
3028     /* Functions for stack tracking */
3029
3030     void emitStackPush(BYTE* addr, GCtype gcType);
3031
3032     void emitStackPushN(BYTE* addr, unsigned count);
3033
3034     void emitStackPop(BYTE* addr, bool isCall, unsigned char callInstrSize, unsigned count = 1);
3035
3036     void emitStackKillArgs(BYTE* addr, unsigned count, unsigned char callInstrSize);
3037
3038     void emitRecordGCcall(BYTE* codePos, unsigned char callInstrSize);
3039
3040     // Helpers for the above
3041
3042     void emitStackPushLargeStk(BYTE* addr, GCtype gcType, unsigned count = 1);
3043     void emitStackPopLargeStk(BYTE* addr, bool isCall, unsigned char callInstrSize, unsigned count = 1);
3044 #endif // EMIT_TRACK_STACK_DEPTH
3045
3046     /* Liveness of stack variables, and registers */
3047
3048     void emitUpdateLiveGCvars(VARSET_VALARG_TP vars, BYTE* addr);
3049     void emitUpdateLiveGCregs(GCtype gcType, regMaskTP regs, BYTE* addr);
3050
3051 #ifdef DEBUG
3052     const char* emitGetFrameReg();
3053     void emitDispRegSet(regMaskTP regs);
3054     void emitDispVarSet();
3055 #endif
3056
3057     void emitGCregLiveUpd(GCtype gcType, regNumber reg, BYTE* addr);
3058     void emitGCregLiveSet(GCtype gcType, regMaskTP mask, BYTE* addr, bool isThis);
3059     void emitGCregDeadUpdMask(regMaskTP, BYTE* addr);
3060     void emitGCregDeadUpd(regNumber reg, BYTE* addr);
3061     void emitGCregDeadSet(GCtype gcType, regMaskTP mask, BYTE* addr);
3062
3063     void emitGCvarLiveUpd(int offs, int varNum, GCtype gcType, BYTE* addr DEBUG_ARG(unsigned actualVarNum));
3064     void emitGCvarLiveSet(int offs, GCtype gcType, BYTE* addr, ssize_t disp = -1);
3065     void emitGCvarDeadUpd(int offs, BYTE* addr DEBUG_ARG(unsigned varNum));
3066     void emitGCvarDeadSet(int offs, BYTE* addr, ssize_t disp = -1);
3067
3068     GCtype emitRegGCtype(regNumber reg);
3069
3070     // We have a mixture of code emission methods, some of which return the size of the emitted instruction,
3071     // requiring the caller to add this to the current code pointer (dst += <call to emit code>), others of which
3072     // return the updated code pointer (dst = <call to emit code>).  Sometimes we'd like to get the size of
3073     // the generated instruction for the latter style.  This method accomplishes that --
3074     // "emitCodeWithInstructionSize(dst, <call to emitCode>, &instrSize)" will do the call, and set
3075     // "*instrSize" to the after-before code pointer difference.  Returns the result of the call.  (And
3076     // asserts that the instruction size fits in an unsigned char.)
3077     static BYTE* emitCodeWithInstructionSize(BYTE* codePtrBefore, BYTE* newCodePointer, unsigned char* instrSize);
3078
3079     /************************************************************************/
3080     /*      The following logic keeps track of initialized data sections    */
3081     /************************************************************************/
3082
3083     /* One of these is allocated for every blob of initialized data */
3084
3085     struct dataSection
3086     {
3087         // Note to use alignments greater than 64 requires modification in the VM
3088         // to support larger alignments (see ICorJitInfo::allocMem)
3089         //
3090         const static unsigned MIN_DATA_ALIGN = 4;
3091         const static unsigned MAX_DATA_ALIGN = 64;
3092
3093         enum sectionType
3094         {
3095             data,
3096             blockAbsoluteAddr,
3097             blockRelative32
3098         };
3099
3100         dataSection*   dsNext;
3101         UNATIVE_OFFSET dsSize;
3102         sectionType    dsType;
3103         var_types      dsDataType;
3104
3105         // variable-sized array used to store the constant data
3106         // or BasicBlock* array in the block cases.
3107         BYTE dsCont[0];
3108     };
3109
3110     /* These describe the entire initialized/uninitialized data sections */
3111
3112     struct dataSecDsc
3113     {
3114         dataSection*   dsdList;
3115         dataSection*   dsdLast;
3116         UNATIVE_OFFSET dsdOffs;
3117         UNATIVE_OFFSET alignment; // in bytes, defaults to 4
3118
3119         dataSecDsc() : dsdList(nullptr), dsdLast(nullptr), dsdOffs(0), alignment(4)
3120         {
3121         }
3122     };
3123
3124     dataSecDsc emitConsDsc;
3125
3126     dataSection* emitDataSecCur;
3127
3128     void emitOutputDataSec(dataSecDsc* sec, BYTE* dst);
3129     void emitDispDataSec(dataSecDsc* section, BYTE* dst);
3130
3131     /************************************************************************/
3132     /*              Handles to the current class and method.                */
3133     /************************************************************************/
3134
3135     COMP_HANDLE emitCmpHandle;
3136
3137 /************************************************************************/
3138 /*               Helpers for interface to EE                            */
3139 /************************************************************************/
3140
3141 #ifdef DEBUG
3142
3143 #define emitRecordRelocation(location, target, fRelocType)                                                             \
3144     emitRecordRelocationHelp(location, target, fRelocType, #fRelocType)
3145
3146 #define emitRecordRelocationWithAddlDelta(location, target, fRelocType, addlDelta)                                     \
3147     emitRecordRelocationHelp(location, target, fRelocType, #fRelocType, addlDelta)
3148
3149     void emitRecordRelocationHelp(void*       location,       /* IN */
3150                                   void*       target,         /* IN */
3151                                   uint16_t    fRelocType,     /* IN */
3152                                   const char* relocTypeName,  /* IN */
3153                                   int32_t     addlDelta = 0); /* IN */
3154
3155 #else // !DEBUG
3156
3157     void emitRecordRelocationWithAddlDelta(void*    location,   /* IN */
3158                                            void*    target,     /* IN */
3159                                            uint16_t fRelocType, /* IN */
3160                                            int32_t  addlDelta)  /* IN */
3161     {
3162         emitRecordRelocation(location, target, fRelocType, addlDelta);
3163     }
3164
3165     void emitRecordRelocation(void*    location,       /* IN */
3166                               void*    target,         /* IN */
3167                               uint16_t fRelocType,     /* IN */
3168                               int32_t  addlDelta = 0); /* IN */
3169
3170 #endif // !DEBUG
3171
3172 #ifdef TARGET_ARM
3173     void emitHandlePCRelativeMov32(void* location, /* IN */
3174                                    void* target);  /* IN */
3175 #endif
3176
3177     void emitRecordCallSite(ULONG                 instrOffset,   /* IN */
3178                             CORINFO_SIG_INFO*     callSig,       /* IN */
3179                             CORINFO_METHOD_HANDLE methodHandle); /* IN */
3180
3181 #ifdef DEBUG
3182     // This is a scratch buffer used to minimize the number of sig info structs
3183     // we have to allocate for recordCallSite.
3184     CORINFO_SIG_INFO* emitScratchSigInfo;
3185 #endif // DEBUG
3186
3187 /************************************************************************/
3188 /*               Logic to collect and display statistics                */
3189 /************************************************************************/
3190
3191 #if EMITTER_STATS
3192
3193     friend void emitterStats(FILE* fout);
3194     friend void emitterStaticStats(FILE* fout);
3195
3196     static size_t emitSizeMethod;
3197
3198     static unsigned emitTotalInsCnt;
3199
3200     static unsigned emitCurPrologInsCnt; // current number of prolog instrDescs
3201     static size_t   emitCurPrologIGSize; // current size of prolog instrDescs
3202     static unsigned emitMaxPrologInsCnt; // maximum number of prolog instrDescs
3203     static size_t   emitMaxPrologIGSize; // maximum size of prolog instrDescs
3204
3205     static unsigned emitTotalIGcnt;   // total number of insGroup allocated
3206     static unsigned emitTotalPhIGcnt; // total number of insPlaceholderGroupData allocated
3207     static unsigned emitTotalIGicnt;
3208     static size_t   emitTotalIGsize;
3209     static unsigned emitTotalIGmcnt;   // total method count
3210     static unsigned emitTotalIGExtend; // total number of 'emitExtend' (typically overflow) groups
3211     static unsigned emitTotalIGjmps;
3212     static unsigned emitTotalIGptrs;
3213
3214     static unsigned emitTotalIDescSmallCnt;
3215     static unsigned emitTotalIDescCnt;
3216     static unsigned emitTotalIDescCnsCnt;
3217     static unsigned emitTotalIDescDspCnt;
3218 #ifdef TARGET_ARM64
3219     static unsigned emitTotalIDescLclVarPairCnt;
3220     static unsigned emitTotalIDescLclVarPairCnsCnt;
3221 #endif // TARGET_ARM64
3222 #ifdef TARGET_ARM
3223     static unsigned emitTotalIDescRelocCnt;
3224 #endif // TARGET_ARM
3225 #ifdef TARGET_XARCH
3226     static unsigned emitTotalIDescAmdCnt;
3227     static unsigned emitTotalIDescCnsAmdCnt;
3228 #endif // TARGET_XARCH
3229     static unsigned emitTotalIDescCnsDspCnt;
3230 #if FEATURE_LOOP_ALIGN
3231     static unsigned emitTotalIDescAlignCnt;
3232 #endif // FEATURE_LOOP_ALIGN
3233     static unsigned emitTotalIDescJmpCnt;
3234 #if !defined(TARGET_ARM64)
3235     static unsigned emitTotalIDescLblCnt;
3236 #endif // !defined(TARGET_ARM64)
3237     static unsigned emitTotalIDescCGCACnt;
3238
3239     static size_t emitTotMemAlloc;
3240
3241     static unsigned emitSmallDspCnt;
3242     static unsigned emitLargeDspCnt;
3243
3244 #define SMALL_CNS_TSZ 256
3245     static unsigned emitSmallCns[SMALL_CNS_TSZ];
3246     static unsigned emitSmallCnsCnt;
3247     static unsigned emitLargeCnsCnt;
3248     static unsigned emitInt8CnsCnt;
3249     static unsigned emitInt16CnsCnt;
3250     static unsigned emitInt32CnsCnt;
3251     static unsigned emitNegCnsCnt;
3252     static unsigned emitPow2CnsCnt;
3253
3254     static unsigned emitIFcounts[IF_COUNT];
3255
3256     void TrackCns(cnsval_ssize_t value)
3257     {
3258         if (value < 0)
3259         {
3260             emitNegCnsCnt++;
3261
3262             if (value >= INT8_MIN)
3263             {
3264                 emitInt8CnsCnt++;
3265             }
3266             else if (value >= INT16_MIN)
3267             {
3268                 emitInt16CnsCnt++;
3269             }
3270             else if (value >= INT32_MIN)
3271             {
3272                 emitInt32CnsCnt++;
3273             }
3274         }
3275         else if (value <= INT8_MAX)
3276         {
3277             emitInt8CnsCnt++;
3278         }
3279         else if (value <= INT16_MAX)
3280         {
3281             emitInt16CnsCnt++;
3282         }
3283         else if (value <= INT32_MAX)
3284         {
3285             emitInt32CnsCnt++;
3286         }
3287
3288         if (isPow2(value))
3289         {
3290             emitPow2CnsCnt++;
3291         }
3292     }
3293
3294     void TrackSmallCns(cnsval_ssize_t value)
3295     {
3296         // We only track a subset of the allowed small constants and
3297         // so we'll split the tracked range between positive/negative
3298         // aggregating those outside the tracked range into the min/max
3299         // instead.
3300
3301         assert(fitsInSmallCns(value));
3302         uint32_t index = 0;
3303
3304         if (value >= ((SMALL_CNS_TSZ / 2) - 1))
3305         {
3306             index = static_cast<uint32_t>(SMALL_CNS_TSZ - 1);
3307         }
3308         else if (value >= (0 - SMALL_CNS_TSZ / 2))
3309         {
3310             index = static_cast<uint32_t>(value + (SMALL_CNS_TSZ / 2));
3311         }
3312
3313         emitSmallCnsCnt++;
3314         emitSmallCns[index]++;
3315
3316         TrackCns(value);
3317     }
3318
3319     void TrackLargeCns(cnsval_ssize_t value)
3320     {
3321         emitLargeCnsCnt++;
3322         TrackCns(value);
3323     }
3324 #endif // EMITTER_STATS
3325
3326 /*************************************************************************
3327  *
3328  *  Define any target-dependent emitter members.
3329  */
3330
3331 #include "emitdef.h"
3332
3333     // It would be better if this were a constructor, but that would entail revamping the allocation
3334     // infrastructure of the entire JIT...
3335     void Init()
3336     {
3337         VarSetOps::AssignNoCopy(emitComp, emitPrevGCrefVars, VarSetOps::MakeEmpty(emitComp));
3338         VarSetOps::AssignNoCopy(emitComp, emitInitGCrefVars, VarSetOps::MakeEmpty(emitComp));
3339         VarSetOps::AssignNoCopy(emitComp, emitThisGCrefVars, VarSetOps::MakeEmpty(emitComp));
3340 #if defined(DEBUG)
3341         VarSetOps::AssignNoCopy(emitComp, debugPrevGCrefVars, VarSetOps::MakeEmpty(emitComp));
3342         VarSetOps::AssignNoCopy(emitComp, debugThisGCrefVars, VarSetOps::MakeEmpty(emitComp));
3343         debugPrevRegPtrDsc = nullptr;
3344         debugPrevGCrefRegs = RBM_NONE;
3345         debugPrevByrefRegs = RBM_NONE;
3346 #endif
3347     }
3348 };
3349
3350 /*****************************************************************************
3351  *
3352  *  Define any target-dependent inlines.
3353  */
3354
3355 #include "emitinl.h"
3356
3357 inline void emitter::instrDesc::checkSizes()
3358 {
3359     C_ASSERT(SMALL_IDSC_SIZE == offsetof(instrDesc, _idAddrUnion));
3360 }
3361
3362 /*****************************************************************************
3363  *
3364  *  Returns true if the given instruction descriptor is a "small
3365  *  constant" one (i.e. one of the descriptors that don't have all instrDesc
3366  *  fields allocated).
3367  */
3368
3369 inline bool emitter::emitIsSmallInsDsc(instrDesc* id) const
3370 {
3371     return id->idIsSmallDsc();
3372 }
3373
3374 /*****************************************************************************
3375  *
3376  *  Given an instruction, return its "update mode" (RD/WR/RW).
3377  */
3378
3379 inline insUpdateModes emitter::emitInsUpdateMode(instruction ins)
3380 {
3381 #ifdef DEBUG
3382     assert((unsigned)ins < emitInsModeFmtCnt);
3383 #endif
3384     return (insUpdateModes)emitInsModeFmtTab[ins];
3385 }
3386
3387 /*****************************************************************************
3388  *
3389  *  Return the number of epilog blocks generated so far.
3390  */
3391
3392 inline unsigned emitter::emitGetEpilogCnt()
3393 {
3394     return emitEpilogCnt;
3395 }
3396
3397 /*****************************************************************************
3398  *
3399  *  Return the current size of the specified data section.
3400  */
3401
3402 inline UNATIVE_OFFSET emitter::emitDataSize()
3403 {
3404     return emitConsDsc.dsdOffs;
3405 }
3406
3407 /*****************************************************************************
3408  *
3409  *  Return a handle to the current position in the output stream. This can
3410  *  be later converted to an actual code offset in bytes.
3411  */
3412
3413 inline void* emitter::emitCurBlock()
3414 {
3415     return emitCurIG;
3416 }
3417
3418 /*****************************************************************************
3419  *
3420  *  The emitCurOffset() method returns a cookie that identifies the current
3421  *  position in the instruction stream. Due to things like scheduling (and
3422  *  the fact that the final size of some instructions cannot be known until
3423  *  the end of code generation), we return a value with the instruction number
3424  *  and its estimated offset to the caller.
3425  */
3426
3427 inline unsigned emitGetInsNumFromCodePos(unsigned codePos)
3428 {
3429     return (codePos & 0xFFFF);
3430 }
3431
3432 inline unsigned emitGetInsOfsFromCodePos(unsigned codePos)
3433 {
3434     return (codePos >> 16);
3435 }
3436
3437 inline unsigned emitter::emitCurOffset()
3438 {
3439     return emitSpecifiedOffset(emitCurIGinsCnt, emitCurIGsize);
3440 }
3441
3442 inline unsigned emitter::emitSpecifiedOffset(unsigned insCount, unsigned igSize)
3443 {
3444     unsigned codePos = insCount + (igSize << 16);
3445
3446     assert(emitGetInsOfsFromCodePos(codePos) == igSize);
3447     assert(emitGetInsNumFromCodePos(codePos) == insCount);
3448
3449     return codePos;
3450 }
3451
3452 extern const unsigned short emitTypeSizes[TYP_COUNT];
3453
3454 template <class T>
3455 inline emitAttr emitTypeSize(T type)
3456 {
3457     assert(TypeGet(type) < TYP_COUNT);
3458     assert(emitTypeSizes[TypeGet(type)] > 0);
3459     return (emitAttr)emitTypeSizes[TypeGet(type)];
3460 }
3461
3462 extern const unsigned short emitTypeActSz[TYP_COUNT];
3463
3464 template <class T>
3465 inline emitAttr emitActualTypeSize(T type)
3466 {
3467     assert(TypeGet(type) < TYP_COUNT);
3468     assert(emitTypeActSz[TypeGet(type)] > 0);
3469     return (emitAttr)emitTypeActSz[TypeGet(type)];
3470 }
3471
3472 /*****************************************************************************
3473  *
3474  *  Convert between an operand size in bytes and a smaller encoding used for
3475  *  storage in instruction descriptors.
3476  */
3477
3478 /* static */ inline emitter::opSize emitter::emitEncodeSize(emitAttr size)
3479 {
3480     assert((size != EA_UNKNOWN) && ((size & EA_SIZE_MASK) == size));
3481     return static_cast<emitter::opSize>(genLog2(size));
3482 }
3483
3484 /* static */ inline emitAttr emitter::emitDecodeSize(emitter::opSize ensz)
3485 {
3486     assert(static_cast<unsigned>(ensz) < OPSZ_COUNT);
3487     return emitSizeDecode[ensz];
3488 }
3489
3490 /*****************************************************************************
3491  *
3492  *  Little helpers to allocate various flavors of instructions.
3493  */
3494
3495 inline emitter::instrDesc* emitter::emitNewInstrSmall(emitAttr attr)
3496 {
3497     instrDesc* id;
3498
3499     id = (instrDesc*)emitAllocAnyInstr(SMALL_IDSC_SIZE, attr);
3500     id->idSetIsSmallDsc();
3501
3502 #if EMITTER_STATS
3503     emitTotalIDescSmallCnt++;
3504 #endif // EMITTER_STATS
3505
3506     return id;
3507 }
3508
3509 inline emitter::instrDesc* emitter::emitNewInstr(emitAttr attr)
3510 {
3511     // This is larger than the Small Descr
3512     return emitAllocInstr(attr);
3513 }
3514
3515 inline emitter::instrDescJmp* emitter::emitNewInstrJmp()
3516 {
3517     return emitAllocInstrJmp();
3518 }
3519
3520 #if FEATURE_LOOP_ALIGN
3521 inline emitter::instrDescAlign* emitter::emitNewInstrAlign()
3522 {
3523     instrDescAlign* newInstr = emitAllocInstrAlign();
3524     newInstr->idIns(INS_align);
3525
3526 #ifdef TARGET_ARM64
3527     newInstr->idInsFmt(IF_SN_0A);
3528     newInstr->idInsOpt(INS_OPTS_ALIGN);
3529 #endif
3530     return newInstr;
3531 }
3532 #endif
3533
3534 #if !defined(TARGET_ARM64)
3535 inline emitter::instrDescLbl* emitter::emitNewInstrLbl()
3536 {
3537     return emitAllocInstrLbl();
3538 }
3539 #else
3540 inline emitter::instrDesc* emitter::emitNewInstrLclVarPair(emitAttr attr, cnsval_ssize_t cns)
3541 {
3542 #if EMITTER_STATS
3543     emitTotalIDescCnt++;
3544     emitTotalIDescCnsCnt++;
3545 #endif // EMITTER_STATS
3546
3547     if (instrDesc::fitsInSmallCns(cns))
3548     {
3549         instrDescLclVarPair* id = emitAllocInstrLclVarPair(attr);
3550         id->idSmallCns(cns);
3551
3552 #if EMITTER_STATS
3553         TrackSmallCns(cns);
3554 #endif
3555
3556         return id;
3557     }
3558     else
3559     {
3560         instrDescLclVarPairCns* id = emitAllocInstrLclVarPairCns(attr, cns);
3561
3562 #if EMITTER_STATS
3563         TrackLargeCns(cns);
3564 #endif
3565
3566         return id;
3567     }
3568 }
3569 #endif // !TARGET_ARM64
3570
3571 inline emitter::instrDesc* emitter::emitNewInstrDsp(emitAttr attr, target_ssize_t dsp)
3572 {
3573     if (dsp == 0)
3574     {
3575         instrDesc* id = emitAllocInstr(attr);
3576
3577 #if EMITTER_STATS
3578         emitSmallDspCnt++;
3579 #endif
3580
3581         return id;
3582     }
3583     else
3584     {
3585         instrDescDsp* id = emitAllocInstrDsp(attr);
3586
3587         id->idSetIsLargeDsp();
3588         id->iddDspVal = dsp;
3589
3590 #if EMITTER_STATS
3591         emitLargeDspCnt++;
3592 #endif
3593
3594         return id;
3595     }
3596 }
3597
3598 /*****************************************************************************
3599  *
3600  *  Allocate an instruction descriptor for an instruction with a constant operand.
3601  *  The instruction descriptor uses the idAddrUnion to save additional info
3602  *  so the smallest size that this can be is sizeof(instrDesc).
3603  *  Note that this very similar to emitter::emitNewInstrSC(), except it never
3604  *  allocates a small descriptor.
3605  */
3606 inline emitter::instrDesc* emitter::emitNewInstrCns(emitAttr attr, cnsval_ssize_t cns)
3607 {
3608     if (instrDesc::fitsInSmallCns(cns))
3609     {
3610         instrDesc* id = emitAllocInstr(attr);
3611         id->idSmallCns(cns);
3612
3613 #if EMITTER_STATS
3614         TrackSmallCns(cns);
3615 #endif
3616
3617         return id;
3618     }
3619     else
3620     {
3621         instrDescCns* id = emitAllocInstrCns(attr, cns);
3622
3623 #if EMITTER_STATS
3624         TrackLargeCns(cns);
3625 #endif
3626
3627         return id;
3628     }
3629 }
3630
3631 /*****************************************************************************
3632  *
3633  *  Get the instrDesc size, general purpose version
3634  *
3635  */
3636
3637 inline size_t emitter::emitGetInstrDescSize(const instrDesc* id)
3638 {
3639     if (id->idIsSmallDsc())
3640     {
3641         return SMALL_IDSC_SIZE;
3642     }
3643     else if (id->idIsLargeCns())
3644     {
3645 #ifdef TARGET_ARM64
3646         if (id->idIsLclVarPair())
3647         {
3648             return sizeof(instrDescLclVarPairCns);
3649         }
3650 #endif
3651         return sizeof(instrDescCns);
3652     }
3653     else
3654     {
3655 #ifdef TARGET_ARM64
3656         if (id->idIsLclVarPair())
3657         {
3658             return sizeof(instrDescLclVarPair);
3659         }
3660 #endif
3661         return sizeof(instrDesc);
3662     }
3663 }
3664
3665 /*****************************************************************************
3666  *
3667  *  Allocate an instruction descriptor for an instruction with a small integer
3668  *  constant operand. This is the same as emitNewInstrCns() except that here
3669  *  any constant that is small enough for instrDesc::fitsInSmallCns() only gets
3670  *  allocated SMALL_IDSC_SIZE bytes (and is thus a small descriptor, whereas
3671  *  emitNewInstrCns() always allocates at least sizeof(instrDesc)).
3672  */
3673
3674 inline emitter::instrDesc* emitter::emitNewInstrSC(emitAttr attr, cnsval_ssize_t cns)
3675 {
3676     if (instrDesc::fitsInSmallCns(cns))
3677     {
3678         instrDesc* id = emitNewInstrSmall(attr);
3679         id->idSmallCns(cns);
3680
3681 #if EMITTER_STATS
3682         TrackSmallCns(cns);
3683 #endif
3684
3685         return id;
3686     }
3687     else
3688     {
3689         instrDescCns* id = emitAllocInstrCns(attr, cns);
3690
3691 #if EMITTER_STATS
3692         TrackLargeCns(cns);
3693 #endif
3694
3695         return id;
3696     }
3697 }
3698
3699 #ifdef TARGET_ARM
3700
3701 inline emitter::instrDesc* emitter::emitNewInstrReloc(emitAttr attr, BYTE* addr)
3702 {
3703     assert(EA_IS_RELOC(attr));
3704
3705     instrDescReloc* id = (instrDescReloc*)emitAllocAnyInstr(sizeof(instrDescReloc), attr);
3706     assert(id->idIsReloc());
3707
3708     id->idrRelocVal = addr;
3709
3710 #if EMITTER_STATS
3711     emitTotalIDescRelocCnt++;
3712 #endif // EMITTER_STATS
3713
3714     return id;
3715 }
3716
3717 #endif // TARGET_ARM
3718
3719 #ifdef TARGET_XARCH
3720
3721 /*****************************************************************************
3722  *
3723  *  The following helpers should be used to access the various values that
3724  *  get stored in different places within the instruction descriptor.
3725  */
3726
3727 inline ssize_t emitter::emitGetInsCns(instrDesc* id)
3728 {
3729     return id->idIsLargeCns() ? ((instrDescCns*)id)->idcCnsVal : id->idSmallCns();
3730 }
3731
3732 inline ssize_t emitter::emitGetInsDsp(instrDesc* id)
3733 {
3734     if (id->idIsLargeDsp())
3735     {
3736         if (id->idIsLargeCns())
3737         {
3738             return ((instrDescCnsDsp*)id)->iddcDspVal;
3739         }
3740         return ((instrDescDsp*)id)->iddDspVal;
3741     }
3742     return 0;
3743 }
3744
3745 /*****************************************************************************
3746  *
3747  *  Get hold of the argument count for an indirect call.
3748  */
3749
3750 inline unsigned emitter::emitGetInsCIargs(instrDesc* id)
3751 {
3752     if (id->idIsLargeCall())
3753     {
3754         return ((instrDescCGCA*)id)->idcArgCnt;
3755     }
3756     else
3757     {
3758         assert(id->idIsLargeDsp() == false);
3759         assert(id->idIsLargeCns() == false);
3760
3761         ssize_t cns = emitGetInsCns(id);
3762         assert((unsigned)cns == (size_t)cns);
3763         return (unsigned)cns;
3764     }
3765 }
3766
3767 //-----------------------------------------------------------------------------
3768 // emitGetMemOpSize: Get the memory operand size of instrDesc.
3769 //
3770 //  Note: there are cases when embedded broadcast is enabled, so the memory operand
3771 //  size is different from the intrinsic simd size, we will check here if emitter is
3772 //  emiting a embedded broadcast enabled instruction.
3773
3774 //  Arguments:
3775 //       id - Instruction descriptor
3776 //
3777 emitAttr emitter::emitGetMemOpSize(instrDesc* id) const
3778 {
3779     if (id->idIsEvexbContext())
3780     {
3781         // should have the assumption that Evex.b now stands for the embedded broadcast context.
3782         // reference: Section 2.7.5 in Intel 64 and ia-32 architectures software developer's manual volume 2.
3783         ssize_t inputSize = GetInputSizeInBytes(id);
3784         switch (inputSize)
3785         {
3786             case 4:
3787                 return EA_4BYTE;
3788             case 8:
3789                 return EA_8BYTE;
3790
3791             default:
3792                 unreached();
3793         }
3794     }
3795     else
3796     {
3797         return emitGetBaseMemOpSize(id);
3798     }
3799 }
3800
3801 //-----------------------------------------------------------------------------
3802 // emitGetMemOpSize: Get the memory operand size of instrDesc.
3803 //
3804 // Note: vextractf128 has a 128-bit output (register or memory) but a 256-bit input (register).
3805 // vinsertf128 is the inverse with a 256-bit output (register), a 256-bit input(register),
3806 // and a 128-bit input (register or memory).
3807 // Similarly, vextractf64x4 has a 256-bit output and 128-bit input and vinsertf64x4 the inverse
3808 // This method is mainly used for such instructions to return the appropriate memory operand
3809 // size, otherwise returns the regular operand size of the instruction.
3810
3811 //  Arguments:
3812 //       id - Instruction descriptor
3813 //
3814 emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const
3815 {
3816
3817     emitAttr    defaultSize = id->idOpSize();
3818     instruction ins         = id->idIns();
3819
3820     switch (ins)
3821     {
3822         case INS_pextrb:
3823         case INS_pinsrb:
3824         case INS_vpbroadcastb:
3825         {
3826             return EA_1BYTE;
3827         }
3828
3829         case INS_pextrw:
3830         case INS_pextrw_sse41:
3831         case INS_pinsrw:
3832         case INS_pmovsxbq:
3833         case INS_pmovzxbq:
3834         case INS_vpbroadcastw:
3835         {
3836             return EA_2BYTE;
3837         }
3838
3839         case INS_addss:
3840         case INS_cmpss:
3841         case INS_comiss:
3842         case INS_cvtss2sd:
3843         case INS_cvtss2si:
3844         case INS_cvttss2si:
3845         case INS_divss:
3846         case INS_extractps:
3847         case INS_insertps:
3848         case INS_maxss:
3849         case INS_minss:
3850         case INS_movss:
3851         case INS_mulss:
3852         case INS_pextrd:
3853         case INS_pinsrd:
3854         case INS_pmovsxbd:
3855         case INS_pmovsxwq:
3856         case INS_pmovzxbd:
3857         case INS_pmovzxwq:
3858         case INS_rcpss:
3859         case INS_roundss:
3860         case INS_rsqrtss:
3861         case INS_sqrtss:
3862         case INS_subss:
3863         case INS_ucomiss:
3864         case INS_vbroadcastss:
3865         case INS_vfmadd132ss:
3866         case INS_vfmadd213ss:
3867         case INS_vfmadd231ss:
3868         case INS_vfmsub132ss:
3869         case INS_vfmsub213ss:
3870         case INS_vfmsub231ss:
3871         case INS_vfnmadd132ss:
3872         case INS_vfnmadd213ss:
3873         case INS_vfnmadd231ss:
3874         case INS_vfnmsub132ss:
3875         case INS_vfnmsub213ss:
3876         case INS_vfnmsub231ss:
3877         case INS_vpbroadcastd:
3878         {
3879             return EA_4BYTE;
3880         }
3881
3882         case INS_addsd:
3883         case INS_cmpsd:
3884         case INS_comisd:
3885         case INS_cvtsd2si:
3886         case INS_cvtsd2ss:
3887         case INS_cvttsd2si:
3888         case INS_divsd:
3889         case INS_maxsd:
3890         case INS_minsd:
3891         case INS_movhpd:
3892         case INS_movhps:
3893         case INS_movlpd:
3894         case INS_movlps:
3895         case INS_movq:
3896         case INS_movsd:
3897         case INS_mulsd:
3898         case INS_pextrq:
3899         case INS_pinsrq:
3900         case INS_pmovsxbw:
3901         case INS_pmovsxdq:
3902         case INS_pmovsxwd:
3903         case INS_pmovzxbw:
3904         case INS_pmovzxdq:
3905         case INS_pmovzxwd:
3906         case INS_roundsd:
3907         case INS_sqrtsd:
3908         case INS_subsd:
3909         case INS_ucomisd:
3910         case INS_vbroadcastsd:
3911         case INS_vfmadd132sd:
3912         case INS_vfmadd213sd:
3913         case INS_vfmadd231sd:
3914         case INS_vfmsub132sd:
3915         case INS_vfmsub213sd:
3916         case INS_vfmsub231sd:
3917         case INS_vfnmadd132sd:
3918         case INS_vfnmadd213sd:
3919         case INS_vfnmadd231sd:
3920         case INS_vfnmsub132sd:
3921         case INS_vfnmsub213sd:
3922         case INS_vfnmsub231sd:
3923         case INS_vpbroadcastq:
3924         {
3925             return EA_8BYTE;
3926         }
3927
3928         case INS_cvtdq2pd:
3929         case INS_cvtps2pd:
3930         {
3931             if (defaultSize == 64)
3932             {
3933                 return EA_32BYTE;
3934             }
3935             else if (defaultSize == 32)
3936             {
3937                 return EA_16BYTE;
3938             }
3939             else
3940             {
3941                 assert(defaultSize == 16);
3942                 return EA_8BYTE;
3943             }
3944         }
3945
3946         case INS_vpmovdb:
3947         case INS_vpmovdw:
3948         case INS_vpmovqb:
3949         case INS_vpmovqd:
3950         case INS_vpmovqw:
3951         case INS_vpmovwb:
3952         case INS_vpmovsdb:
3953         case INS_vpmovsdw:
3954         case INS_vpmovsqb:
3955         case INS_vpmovsqd:
3956         case INS_vpmovsqw:
3957         case INS_vpmovswb:
3958         case INS_vpmovusdb:
3959         case INS_vpmovusdw:
3960         case INS_vpmovusqb:
3961         case INS_vpmovusqd:
3962         case INS_vpmovusqw:
3963         case INS_vpmovuswb:
3964         {
3965             insTupleType tupleType = insTupleTypeInfo(ins);
3966             unsigned     memSize   = 0;
3967
3968             switch (tupleType)
3969             {
3970                 case INS_TT_HALF_MEM:
3971                 {
3972                     memSize = defaultSize / 2;
3973                     break;
3974                 }
3975
3976                 case INS_TT_QUARTER_MEM:
3977                 {
3978                     memSize = defaultSize / 4;
3979                     break;
3980                 }
3981
3982                 case INS_TT_EIGHTH_MEM:
3983                 {
3984                     memSize = defaultSize / 8;
3985                     break;
3986                 }
3987
3988                 default:
3989                 {
3990                     unreached();
3991                 }
3992             }
3993
3994             return EA_ATTR(memSize);
3995         }
3996
3997         case INS_vbroadcastf128:
3998         case INS_vbroadcasti128:
3999         case INS_vextractf128:
4000         case INS_vextracti128:
4001         case INS_vinsertf128:
4002         case INS_vinserti128:
4003         {
4004             return EA_16BYTE;
4005         }
4006
4007         case INS_vextractf32x8:
4008         case INS_vextracti32x8:
4009         case INS_vextractf64x4:
4010         case INS_vextracti64x4:
4011         case INS_vinsertf32x8:
4012         case INS_vinserti32x8:
4013         case INS_vinsertf64x4:
4014         case INS_vinserti64x4:
4015         {
4016             return EA_32BYTE;
4017         }
4018
4019         case INS_movddup:
4020         {
4021             if (defaultSize == 64)
4022             {
4023                 return EA_64BYTE;
4024             }
4025             else if (defaultSize == 32)
4026             {
4027                 return EA_32BYTE;
4028             }
4029             else
4030             {
4031                 assert(defaultSize == 16);
4032                 return EA_8BYTE;
4033             }
4034         }
4035
4036         default:
4037         {
4038             return defaultSize;
4039         }
4040     }
4041 }
4042
4043 #endif // TARGET_XARCH
4044
4045 /*****************************************************************************
4046  *
4047  *  Returns true if the given register contains a live GC ref.
4048  */
4049
4050 inline GCtype emitter::emitRegGCtype(regNumber reg)
4051 {
4052     assert(emitIssuing);
4053
4054     if ((emitThisGCrefRegs & genRegMask(reg)) != 0)
4055     {
4056         return GCT_GCREF;
4057     }
4058     else if ((emitThisByrefRegs & genRegMask(reg)) != 0)
4059     {
4060         return GCT_BYREF;
4061     }
4062     else
4063     {
4064         return GCT_NONE;
4065     }
4066 }
4067
4068 #ifdef DEBUG
4069
4070 #if EMIT_TRACK_STACK_DEPTH
4071 #define CHECK_STACK_DEPTH() assert((int)emitCurStackLvl >= 0)
4072 #else
4073 #define CHECK_STACK_DEPTH()
4074 #endif
4075
4076 #endif // DEBUG
4077
4078 /*****************************************************************************
4079  *
4080  *  Return true when a given code offset is properly aligned for the target
4081  */
4082
4083 inline bool IsCodeAligned(UNATIVE_OFFSET offset)
4084 {
4085     return ((offset & (CODE_ALIGN - 1)) == 0);
4086 }
4087
4088 // Static:
4089 inline BYTE* emitter::emitCodeWithInstructionSize(BYTE* codePtrBefore, BYTE* newCodePointer, unsigned char* instrSize)
4090 {
4091     // DLD: Perhaps this method should return the instruction size, and we should do dst += <that size>
4092     // as is done in other cases?
4093     assert(newCodePointer >= codePtrBefore);
4094     ClrSafeInt<unsigned char> callInstrSizeSafe = ClrSafeInt<unsigned char>(newCodePointer - codePtrBefore);
4095     assert(!callInstrSizeSafe.IsOverflow());
4096     *instrSize = callInstrSizeSafe.Value();
4097     return newCodePointer;
4098 }
4099
4100 /*****************************************************************************/
4101 #endif // _EMIT_H_
4102 /*****************************************************************************/