Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / instr.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                           Instruction                                     XX
9 XX                                                                           XX
10 XX          The interface to generate a machine-instruction.                 XX
11 XX                                                                           XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14 */
15
16 #include "jitpch.h"
17 #ifdef _MSC_VER
18 #pragma hdrstop
19 #endif
20
21 #include "codegen.h"
22 #include "instr.h"
23 #include "emit.h"
24
25 /*****************************************************************************/
26 #ifdef DEBUG
27
28 /*****************************************************************************
29  *
30  *  Returns the string representation of the given CPU instruction.
31  */
32
33 const char* CodeGen::genInsName(instruction ins)
34 {
35     // clang-format off
36     static
37     const char * const insNames[] =
38     {
39 #if defined(_TARGET_XARCH_)
40         #define INST0(id, nm, fp, um, rf, wf, mr                 ) nm,
41         #define INST1(id, nm, fp, um, rf, wf, mr                 ) nm,
42         #define INST2(id, nm, fp, um, rf, wf, mr, mi             ) nm,
43         #define INST3(id, nm, fp, um, rf, wf, mr, mi, rm         ) nm,
44         #define INST4(id, nm, fp, um, rf, wf, mr, mi, rm, a4     ) nm,
45         #define INST5(id, nm, fp, um, rf, wf, mr, mi, rm, a4, rr ) nm,
46         #include "instrs.h"
47
48 #elif defined(_TARGET_ARM_)
49         #define INST1(id, nm, fp, ldst, fmt, e1                                 ) nm,
50         #define INST2(id, nm, fp, ldst, fmt, e1, e2                             ) nm,
51         #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3                         ) nm,
52         #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4                     ) nm,
53         #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5                 ) nm,
54         #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6             ) nm,
55         #define INST8(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8     ) nm,
56         #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm,
57         #include "instrs.h"
58
59 #elif defined(_TARGET_ARM64_)
60         #define INST1(id, nm, fp, ldst, fmt, e1                                 ) nm,
61         #define INST2(id, nm, fp, ldst, fmt, e1, e2                             ) nm,
62         #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3                         ) nm,
63         #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4                     ) nm,
64         #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5                 ) nm,
65         #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6             ) nm,
66         #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm,
67         #include "instrs.h"
68
69 #else
70 #error "Unknown _TARGET_"
71 #endif
72     };
73     // clang-format on
74
75     assert((unsigned)ins < _countof(insNames));
76     assert(insNames[ins] != nullptr);
77
78     return insNames[ins];
79 }
80
81 void __cdecl CodeGen::instDisp(instruction ins, bool noNL, const char* fmt, ...)
82 {
83     if (compiler->opts.dspCode)
84     {
85         /* Display the instruction offset within the emit block */
86
87         //      printf("[%08X:%04X]", getEmitter().emitCodeCurBlock(), getEmitter().emitCodeOffsInBlock());
88
89         /* Display the FP stack depth (before the instruction is executed) */
90
91         //      printf("[FP=%02u] ", genGetFPstkLevel());
92
93         /* Display the instruction mnemonic */
94         printf("        ");
95
96         printf("            %-8s", genInsName(ins));
97
98         if (fmt)
99         {
100             va_list args;
101             va_start(args, fmt);
102             vprintf(fmt, args);
103             va_end(args);
104         }
105
106         if (!noNL)
107         {
108             printf("\n");
109         }
110     }
111 }
112
113 /*****************************************************************************/
114 #endif // DEBUG
115 /*****************************************************************************/
116
117 void CodeGen::instInit()
118 {
119 }
120
121 /*****************************************************************************
122  *
123  *  Return the size string (e.g. "word ptr") appropriate for the given size.
124  */
125
126 #ifdef DEBUG
127
128 const char* CodeGen::genSizeStr(emitAttr attr)
129 {
130     // clang-format off
131     static
132     const char * const sizes[] =
133     {
134         "",
135         "byte  ptr ",
136         "word  ptr ",
137         nullptr,
138         "dword ptr ",
139         nullptr,
140         nullptr,
141         nullptr,
142         "qword ptr ",
143         nullptr,
144         nullptr,
145         nullptr,
146         nullptr,
147         nullptr,
148         nullptr,
149         nullptr,
150         "xmmword ptr ",
151         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
152         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
153         "ymmword ptr"
154     };
155     // clang-format on
156
157     unsigned size = EA_SIZE(attr);
158
159     assert(size == 0 || size == 1 || size == 2 || size == 4 || size == 8 || size == 16 || size == 32);
160
161     if (EA_ATTR(size) == attr)
162     {
163         return sizes[size];
164     }
165     else if (attr == EA_GCREF)
166     {
167         return "gword ptr ";
168     }
169     else if (attr == EA_BYREF)
170     {
171         return "bword ptr ";
172     }
173     else if (EA_IS_DSP_RELOC(attr))
174     {
175         return "rword ptr ";
176     }
177     else
178     {
179         assert(!"Unexpected");
180         return "unknw ptr ";
181     }
182 }
183
184 #endif
185
186 /*****************************************************************************
187  *
188  *  Generate an instruction.
189  */
190
191 void CodeGen::instGen(instruction ins)
192 {
193
194     getEmitter()->emitIns(ins);
195
196 #ifdef _TARGET_XARCH_
197     // A workaround necessitated by limitations of emitter
198     // if we are scheduled to insert a nop here, we have to delay it
199     // hopefully we have not missed any other prefix instructions or places
200     // they could be inserted
201     if (ins == INS_lock && getEmitter()->emitNextNop == 0)
202     {
203         getEmitter()->emitNextNop = 1;
204     }
205 #endif
206 }
207
208 /*****************************************************************************
209  *
210  *  Returns non-zero if the given CPU instruction is a floating-point ins.
211  */
212
213 // static inline
214 bool CodeGenInterface::instIsFP(instruction ins)
215 {
216     assert((unsigned)ins < _countof(instInfo));
217
218     return (instInfo[ins] & INST_FP) != 0;
219 }
220
221 #ifdef _TARGET_XARCH_
222 /*****************************************************************************
223  *
224  *  Generate a multi-byte NOP instruction.
225  */
226
227 void CodeGen::instNop(unsigned size)
228 {
229     assert(size <= 15);
230     getEmitter()->emitIns_Nop(size);
231 }
232 #endif
233
234 /*****************************************************************************
235  *
236  *  Generate a jump instruction.
237  */
238
239 void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock)
240 {
241 #if !FEATURE_FIXED_OUT_ARGS
242     // On the x86 we are pushing (and changing the stack level), but on x64 and other archs we have
243     // a fixed outgoing args area that we store into and we never change the stack level when calling methods.
244     //
245     // Thus only on x86 do we need to assert that the stack level at the target block matches the current stack level.
246     //
247     CLANG_FORMAT_COMMENT_ANCHOR;
248
249 #ifdef UNIX_X86_ABI
250     // bbTgtStkDepth is a (pure) argument count (stack alignment padding should be excluded).
251     assert((tgtBlock->bbTgtStkDepth * sizeof(int) == (genStackLevel - curNestedAlignment)) || isFramePointerUsed());
252 #else
253     assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
254 #endif
255 #endif // !FEATURE_FIXED_OUT_ARGS
256
257     getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock);
258 }
259
260 /*****************************************************************************
261  *
262  *  Generate a set instruction.
263  */
264
265 void CodeGen::inst_SET(emitJumpKind condition, regNumber reg)
266 {
267 #ifdef _TARGET_XARCH_
268     instruction ins;
269
270     /* Convert the condition to an instruction opcode */
271
272     switch (condition)
273     {
274         case EJ_js:
275             ins = INS_sets;
276             break;
277         case EJ_jns:
278             ins = INS_setns;
279             break;
280         case EJ_je:
281             ins = INS_sete;
282             break;
283         case EJ_jne:
284             ins = INS_setne;
285             break;
286
287         case EJ_jl:
288             ins = INS_setl;
289             break;
290         case EJ_jle:
291             ins = INS_setle;
292             break;
293         case EJ_jge:
294             ins = INS_setge;
295             break;
296         case EJ_jg:
297             ins = INS_setg;
298             break;
299
300         case EJ_jb:
301             ins = INS_setb;
302             break;
303         case EJ_jbe:
304             ins = INS_setbe;
305             break;
306         case EJ_jae:
307             ins = INS_setae;
308             break;
309         case EJ_ja:
310             ins = INS_seta;
311             break;
312
313         case EJ_jpe:
314             ins = INS_setpe;
315             break;
316         case EJ_jpo:
317             ins = INS_setpo;
318             break;
319
320         default:
321             NO_WAY("unexpected condition type");
322             return;
323     }
324
325     assert(genRegMask(reg) & RBM_BYTE_REGS);
326
327     // These instructions only write the low byte of 'reg'
328     getEmitter()->emitIns_R(ins, EA_1BYTE, reg);
329 #elif defined(_TARGET_ARM64_)
330     insCond cond;
331     /* Convert the condition to an insCond value */
332     switch (condition)
333     {
334         case EJ_eq:
335             cond = INS_COND_EQ;
336             break;
337         case EJ_ne:
338             cond = INS_COND_NE;
339             break;
340         case EJ_hs:
341             cond = INS_COND_HS;
342             break;
343         case EJ_lo:
344             cond = INS_COND_LO;
345             break;
346
347         case EJ_mi:
348             cond = INS_COND_MI;
349             break;
350         case EJ_pl:
351             cond = INS_COND_PL;
352             break;
353         case EJ_vs:
354             cond = INS_COND_VS;
355             break;
356         case EJ_vc:
357             cond = INS_COND_VC;
358             break;
359
360         case EJ_hi:
361             cond = INS_COND_HI;
362             break;
363         case EJ_ls:
364             cond = INS_COND_LS;
365             break;
366         case EJ_ge:
367             cond = INS_COND_GE;
368             break;
369         case EJ_lt:
370             cond = INS_COND_LT;
371             break;
372
373         case EJ_gt:
374             cond = INS_COND_GT;
375             break;
376         case EJ_le:
377             cond = INS_COND_LE;
378             break;
379
380         default:
381             NO_WAY("unexpected condition type");
382             return;
383     }
384     getEmitter()->emitIns_R_COND(INS_cset, EA_8BYTE, reg, cond);
385 #else
386     NYI("inst_SET");
387 #endif
388 }
389
390 /*****************************************************************************
391  *
392  *  Generate a "op reg" instruction.
393  */
394
395 void CodeGen::inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size)
396 {
397     if (size == EA_UNKNOWN)
398     {
399         size = emitActualTypeSize(type);
400     }
401
402     getEmitter()->emitIns_R(ins, size, reg);
403 }
404
405 /*****************************************************************************
406  *
407  *  Generate a "op reg1, reg2" instruction.
408  */
409
410 void CodeGen::inst_RV_RV(instruction ins,
411                          regNumber   reg1,
412                          regNumber   reg2,
413                          var_types   type,
414                          emitAttr    size,
415                          insFlags    flags /* = INS_FLAGS_DONT_CARE */)
416 {
417     if (size == EA_UNKNOWN)
418     {
419         size = emitActualTypeSize(type);
420     }
421
422 #ifdef _TARGET_ARM_
423     getEmitter()->emitIns_R_R(ins, size, reg1, reg2, flags);
424 #else
425     getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
426 #endif
427 }
428
429 /*****************************************************************************
430  *
431  *  Generate a "op reg1, reg2, reg3" instruction.
432  */
433
434 void CodeGen::inst_RV_RV_RV(instruction ins,
435                             regNumber   reg1,
436                             regNumber   reg2,
437                             regNumber   reg3,
438                             emitAttr    size,
439                             insFlags    flags /* = INS_FLAGS_DONT_CARE */)
440 {
441 #ifdef _TARGET_ARM_
442     getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3, flags);
443 #elif defined(_TARGET_XARCH_)
444     getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3);
445 #else
446     NYI("inst_RV_RV_RV");
447 #endif
448 }
449 /*****************************************************************************
450  *
451  *  Generate a "op icon" instruction.
452  */
453
454 void CodeGen::inst_IV(instruction ins, int val)
455 {
456     getEmitter()->emitIns_I(ins, EA_PTRSIZE, val);
457 }
458
459 /*****************************************************************************
460  *
461  *  Generate a "op icon" instruction where icon is a handle of type specified
462  *  by 'flags'
463  */
464
465 void CodeGen::inst_IV_handle(instruction ins, int val)
466 {
467     getEmitter()->emitIns_I(ins, EA_HANDLE_CNS_RELOC, val);
468 }
469
470 #if FEATURE_STACK_FP_X87
471 /*****************************************************************************
472  *
473  *  Generate a "op ST(n), ST(0)" instruction.
474  */
475
476 void CodeGen::inst_FS(instruction ins, unsigned stk)
477 {
478     assert(stk < 8);
479
480 #ifdef DEBUG
481
482     switch (ins)
483     {
484         case INS_fcompp:
485             assert(stk == 1);
486             break; // Implicit operand of compp is ST(1)
487         case INS_fld:
488         case INS_fxch:
489             assert(!"don't do this. Do you want to use inst_FN() instead?");
490             break;
491         default:
492             break;
493     }
494
495 #endif
496
497     getEmitter()->emitIns_F_F0(ins, stk);
498 }
499
500 /*****************************************************************************
501  *
502  *  Generate a "op ST(0), ST(n)" instruction
503  */
504
505 void CodeGenInterface::inst_FN(instruction ins, unsigned stk)
506 {
507     assert(stk < 8);
508
509 #ifdef DEBUG
510
511     switch (ins)
512     {
513         case INS_fst:
514         case INS_fstp:
515         case INS_faddp:
516         case INS_fsubp:
517         case INS_fsubrp:
518         case INS_fmulp:
519         case INS_fdivp:
520         case INS_fdivrp:
521         case INS_fcompp:
522             assert(!"don't do this. Do you want to use inst_FS() instead?");
523             break;
524         default:
525             break;
526     }
527
528 #endif // DEBUG
529
530     getEmitter()->emitIns_F0_F(ins, stk);
531 }
532 #endif // FEATURE_STACK_FP_X87
533
534 /*****************************************************************************
535  *
536  *  Display a stack frame reference.
537  */
538
539 void CodeGen::inst_set_SV_var(GenTree* tree)
540 {
541 #ifdef DEBUG
542     assert(tree && (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_VAR_ADDR || tree->gtOper == GT_STORE_LCL_VAR));
543     assert(tree->gtLclVarCommon.gtLclNum < compiler->lvaCount);
544
545     getEmitter()->emitVarRefOffs = tree->gtLclVar.gtLclILoffs;
546
547 #endif // DEBUG
548 }
549
550 /*****************************************************************************
551  *
552  *  Generate a "op reg, icon" instruction.
553  */
554
555 void CodeGen::inst_RV_IV(
556     instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags /* = INS_FLAGS_DONT_CARE */)
557 {
558 #if !defined(_TARGET_64BIT_)
559     assert(size != EA_8BYTE);
560 #endif
561
562 #ifdef _TARGET_ARM_
563     if (arm_Valid_Imm_For_Instr(ins, val, flags))
564     {
565         getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
566     }
567     else if (ins == INS_mov)
568     {
569         instGen_Set_Reg_To_Imm(size, reg, val);
570     }
571     else
572     {
573 #ifndef LEGACY_BACKEND
574         // TODO-Cleanup: Add a comment about why this is unreached() for RyuJIT backend.
575         unreached();
576 #else  // LEGACY_BACKEND
577         regNumber tmpReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
578         instGen_Set_Reg_To_Imm(size, tmpReg, val);
579         getEmitter()->emitIns_R_R(ins, size, reg, tmpReg, flags);
580 #endif // LEGACY_BACKEND
581     }
582 #elif defined(_TARGET_ARM64_)
583     // TODO-Arm64-Bug: handle large constants!
584     // Probably need something like the ARM case above: if (arm_Valid_Imm_For_Instr(ins, val)) ...
585     assert(ins != INS_cmp);
586     assert(ins != INS_tst);
587     assert(ins != INS_mov);
588     getEmitter()->emitIns_R_R_I(ins, size, reg, reg, val);
589 #else // !_TARGET_ARM_
590 #ifdef _TARGET_AMD64_
591     // Instead of an 8-byte immediate load, a 4-byte immediate will do fine
592     // as the high 4 bytes will be zero anyway.
593     if (size == EA_8BYTE && ins == INS_mov && ((val & 0xFFFFFFFF00000000LL) == 0))
594     {
595         size = EA_4BYTE;
596         getEmitter()->emitIns_R_I(ins, size, reg, val);
597     }
598     else if (EA_SIZE(size) == EA_8BYTE && ins != INS_mov && (((int)val != val) || EA_IS_CNS_RELOC(size)))
599     {
600 #ifndef LEGACY_BACKEND
601         assert(!"Invalid immediate for inst_RV_IV");
602 #else  // LEGACY_BACKEND
603         // We can't fit the immediate into this instruction, so move it into
604         // a register first
605         regNumber tmpReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
606         instGen_Set_Reg_To_Imm(size, tmpReg, val);
607
608         // We might have to switch back from 3-operand imul to two operand form
609         if (instrIs3opImul(ins))
610         {
611             assert(getEmitter()->inst3opImulReg(ins) == reg);
612             ins = INS_imul;
613         }
614         getEmitter()->emitIns_R_R(ins, EA_TYPE(size), reg, tmpReg);
615 #endif // LEGACY_BACKEND
616     }
617     else
618 #endif // _TARGET_AMD64_
619     {
620         getEmitter()->emitIns_R_I(ins, size, reg, val);
621     }
622 #endif // !_TARGET_ARM_
623 }
624
625 #if defined(LEGACY_BACKEND)
626 /*****************************************************************************
627  *  Figure out the operands to address the tree.
628  *  'addr' can be one of (1) a pointer to be indirected
629  *                       (2) a calculation to be done with LEA_AVAILABLE
630  *                       (3) GT_ARR_ELEM
631  *
632  *  On return, *baseReg, *indScale, *indReg, and *cns are set.
633  */
634
635 void CodeGen::instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns)
636 {
637     if (addr->gtOper == GT_ARR_ELEM)
638     {
639         /* For GT_ARR_ELEM, the addressibility registers are marked on
640            gtArrObj and gtArrInds[0] */
641
642         assert(addr->gtArrElem.gtArrObj->InReg());
643         *baseReg = addr->gtArrElem.gtArrObj->gtRegNum;
644
645         assert(addr->gtArrElem.gtArrInds[0]->InReg());
646         *indReg = addr->gtArrElem.gtArrInds[0]->gtRegNum;
647
648         if (jitIsScaleIndexMul(addr->gtArrElem.gtArrElemSize))
649             *indScale = addr->gtArrElem.gtArrElemSize;
650         else
651             *indScale = 0;
652
653         *cns = compiler->eeGetMDArrayDataOffset(addr->gtArrElem.gtArrElemType, addr->gtArrElem.gtArrRank);
654     }
655     else if (addr->gtOper == GT_LEA)
656     {
657         GenTreeAddrMode* lea  = addr->AsAddrMode();
658         GenTree*         base = lea->Base();
659         assert(!base || (base->InReg()));
660         GenTree* index = lea->Index();
661         assert(!index || (index->InReg()));
662
663         *baseReg  = base ? base->gtRegNum : REG_NA;
664         *indReg   = index ? index->gtRegNum : REG_NA;
665         *indScale = lea->gtScale;
666         *cns      = lea->gtOffset;
667         return;
668     }
669     else
670     {
671         /* Figure out what complex address mode to use */
672
673         GenTree* rv1 = NULL;
674         GenTree* rv2 = NULL;
675         bool     rev = false;
676
677         INDEBUG(bool yes =)
678         genCreateAddrMode(addr, -1, true, RBM_NONE, &rev, &rv1, &rv2,
679 #if SCALED_ADDR_MODES
680                           indScale,
681 #endif
682                           cns);
683
684         assert(yes); // // since we have called genMakeAddressable() on addr
685         // Ensure that the base and index, if used, are in registers.
686         if (rv1 && ((rv1->gtFlags & GTF_REG_VAL) == 0))
687         {
688             if (rv1->gtFlags & GTF_SPILLED)
689             {
690                 genRecoverReg(rv1, RBM_ALLINT, RegSet::KEEP_REG);
691             }
692             else
693             {
694                 genCodeForTree(rv1, RBM_NONE);
695                 regSet.rsMarkRegUsed(rv1, addr);
696             }
697             assert(rv1->gtFlags & GTF_REG_VAL);
698         }
699         if (rv2 && !rv2->InReg())
700         {
701             if (rv2->gtFlags & GTF_SPILLED)
702             {
703                 genRecoverReg(rv2, ~genRegMask(rv1->gtRegNum), RegSet::KEEP_REG);
704             }
705             else
706             {
707                 genCodeForTree(rv2, RBM_NONE);
708                 regSet.rsMarkRegUsed(rv2, addr);
709             }
710             assert(rv2->InReg());
711         }
712         // If we did both, we might have spilled rv1.
713         if (rv1 && ((rv1->gtFlags & GTF_SPILLED) != 0))
714         {
715             regSet.rsLockUsedReg(genRegMask(rv2->gtRegNum));
716             genRecoverReg(rv1, ~genRegMask(rv2->gtRegNum), RegSet::KEEP_REG);
717             regSet.rsUnlockReg(genRegMask(rv2->gtRegNum));
718         }
719
720         *baseReg = rv1 ? rv1->gtRegNum : REG_NA;
721         *indReg  = rv2 ? rv2->gtRegNum : REG_NA;
722     }
723 }
724
725 #if CPU_LOAD_STORE_ARCH
726 /*****************************************************************************
727  *
728  *  Originally this was somewhat specific to the x86 instrution format.
729  *  For a Load/Store arch we generate the 1-8 instructions necessary to
730  *  implement the single addressing mode instruction used on x86.
731  *  We currently don't have an instruction scheduler enabled on any target.
732  *
733  *  [Schedule] an "ins reg, [r/m]" (rdst=true), or "ins [r/m], reg" (rdst=false)
734  *  instruction (the r/m operand given by a tree). We also allow instructions
735  *  of the form "ins [r/m], icon", these are signaled by setting 'cons' to
736  *  true.
737  *
738  *   The longest instruction sequence emitted on the ARM is as follows:
739  *
740  *       - the "addr" represents an array addressing mode,
741  *          with a baseReg, indReg with a shift and a large offset
742  *          (Note that typically array addressing modes do NOT have a large offset)
743  *       - "ins" is an ALU instruction,
744  *       - cons=true, and imm is a large constant that can not be directly encoded with "ins"
745  *       - We may need to grab upto four additional registers: regT, rtegVal, regOffs and regImm
746  *
747  *       add    regT, baseReg, indReg<<shift
748  *       movw   regOffs, offsLo
749  *       movt   regOffs, offsHi
750  *       ldr    regVal, [regT + regOffs]
751  *       movw   regImm, consLo
752  *       movt   regImm, consHi
753  *       "ins"  regVal, regImm
754  *       str    regVal, [regT + regOffs]
755  *
756  */
757
758 void CodeGen::sched_AM(instruction ins,
759                        emitAttr    size,
760                        regNumber   ireg,
761                        bool        rdst,
762                        GenTree*    addr,
763                        unsigned    offs,
764                        bool        cons,
765                        int         imm,
766                        insFlags    flags)
767 {
768     assert(addr);
769     assert(size != EA_UNKNOWN);
770
771     enum INS_TYPE
772     {
773         eIT_Lea,
774         eIT_Load,
775         eIT_Store,
776         eIT_Other
777     };
778     INS_TYPE insType = eIT_Other;
779
780     if (ins == INS_lea)
781     {
782         insType = eIT_Lea;
783         ins     = INS_add;
784     }
785     else if (getEmitter()->emitInsIsLoad(ins))
786     {
787         insType = eIT_Load;
788     }
789     else if (getEmitter()->emitInsIsStore(ins))
790     {
791         insType = eIT_Store;
792     }
793
794     regNumber baseReg  = REG_NA;
795     regNumber indReg   = REG_NA;
796     unsigned  indScale = 0;
797
798     regMaskTP avoidMask = RBM_NONE;
799
800     if (addr->InReg())
801     {
802         /* The address is "[reg+offs]" */
803         baseReg = addr->gtRegNum;
804     }
805     else if (addr->IsCnsIntOrI())
806     {
807         // Do we need relocations?
808         if (compiler->opts.compReloc && addr->IsIconHandle())
809         {
810             size = EA_SET_FLG(size, EA_DSP_RELOC_FLG);
811             // offs should be smaller than ZapperModule::FixupPlaceHolder
812             // so that we can uniquely identify the handle
813             assert(offs <= 4);
814         }
815         ssize_t disp = addr->gtIntCon.gtIconVal + offs;
816         if ((insType == eIT_Store) && (ireg != REG_NA))
817         {
818             // Can't use the ireg as the baseReg when we have a store instruction
819             avoidMask |= genRegMask(ireg);
820         }
821         baseReg = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
822
823         avoidMask |= genRegMask(baseReg);
824         instGen_Set_Reg_To_Imm(size, baseReg, disp);
825         offs = 0;
826     }
827     else
828     {
829         unsigned cns = 0;
830
831         instGetAddrMode(addr, &baseReg, &indScale, &indReg, &cns);
832
833         /* Add the constant offset value, if present */
834
835         offs += cns;
836
837 #if SCALED_ADDR_MODES
838         noway_assert((baseReg != REG_NA) || (indReg != REG_NA));
839         if (baseReg != REG_NA)
840 #endif
841         {
842             avoidMask |= genRegMask(baseReg);
843         }
844
845         // I don't think this is necessary even in the non-proto-jit case, but better to be
846         // conservative here.  It is only necessary to avoid using ireg if it is used as regT,
847         // in which case it will be added to avoidMask below.
848
849         if (ireg != REG_NA)
850         {
851             avoidMask |= genRegMask(ireg);
852         }
853
854         if (indReg != REG_NA)
855         {
856             avoidMask |= genRegMask(indReg);
857         }
858     }
859
860     unsigned shift = (indScale > 0) ? genLog2((unsigned)indScale) : 0;
861
862     regNumber regT    = REG_NA; // the register where the address is computed into
863     regNumber regOffs = REG_NA; // a temporary register to use for the offs when it can't be directly encoded
864     regNumber regImm  = REG_NA; // a temporary register to use for the imm when it can't be directly encoded
865     regNumber regVal  = REG_NA; // a temporary register to use when we have to do a load/modify/store operation
866
867     // Setup regT
868     if (indReg == REG_NA)
869     {
870         regT = baseReg; // We can use the baseReg, regT is read-only
871     }
872     else // We have an index register (indReg != REG_NA)
873     {
874         // Check for special case that we can encode using one instruction
875         if ((offs == 0) && (insType != eIT_Other) && !instIsFP(ins) && baseReg != REG_NA)
876         {
877             //  ins    ireg, [baseReg + indReg << shift]
878             getEmitter()->emitIns_R_R_R_I(ins, size, ireg, baseReg, indReg, shift, flags, INS_OPTS_LSL);
879             return;
880         }
881
882         // Otherwise setup regT, regT is written once here
883         //
884         if (insType == eIT_Lea || (insType == eIT_Load && !instIsFP(ins)))
885         {
886             assert(ireg != REG_NA);
887             // ireg will be written, so we can take it as our temporary register
888             regT = ireg;
889         }
890         else
891         {
892             // need a new temporary reg
893             regT = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
894             regTracker.rsTrackRegTrash(regT);
895         }
896
897 #if SCALED_ADDR_MODES
898         if (baseReg == REG_NA)
899         {
900             assert(shift > 0);
901             //  LSL    regT, indReg, shift.
902             getEmitter()->emitIns_R_R_I(INS_lsl, EA_PTRSIZE, regT, indReg, shift & ((TARGET_POINTER_SIZE * 8) - 1));
903         }
904         else
905 #endif // SCALED_ADDR_MODES
906         {
907             assert(baseReg != REG_NA);
908
909             //  add    regT, baseReg, indReg<<shift.
910             getEmitter()->emitIns_R_R_R_I(INS_add,
911                                           // The "add" operation will yield either a pointer or byref, depending on the
912                                           // type of "addr."
913                                           varTypeIsGC(addr->TypeGet()) ? EA_BYREF : EA_PTRSIZE, regT, baseReg, indReg,
914                                           shift, INS_FLAGS_NOT_SET, INS_OPTS_LSL);
915         }
916     }
917
918     // regT is the base register for a load/store or an operand for add when insType is eIT_Lea
919     //
920     assert(regT != REG_NA);
921     avoidMask |= genRegMask(regT);
922
923     if (insType != eIT_Other)
924     {
925         assert((flags != INS_FLAGS_SET) || (insType == eIT_Lea));
926         if ((insType == eIT_Lea) && (offs == 0))
927         {
928             // If we have the same register as src and dst and we do not need to set the flags
929             //   then we can skip emitting the instruction
930             if ((ireg != regT) || (flags == INS_FLAGS_SET))
931             {
932                 //  mov    ireg, regT
933                 getEmitter()->emitIns_R_R(INS_mov, size, ireg, regT, flags);
934             }
935         }
936         else if (arm_Valid_Imm_For_Instr(ins, offs, flags))
937         {
938             //  ins    ireg, [regT + offs]
939             getEmitter()->emitIns_R_R_I(ins, size, ireg, regT, offs, flags);
940         }
941         else
942         {
943             regOffs = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
944
945             // We cannot use [regT + regOffs] to load/store a floating register
946             if (emitter::isFloatReg(ireg))
947             {
948                 if (arm_Valid_Imm_For_Instr(INS_add, offs, flags))
949                 {
950                     //  add    regOffs, regT, offs
951                     getEmitter()->emitIns_R_R_I(INS_add, EA_4BYTE, regOffs, regT, offs, flags);
952                 }
953                 else
954                 {
955                     //  movw   regOffs, offs_lo16
956                     //  movt   regOffs, offs_hi16
957                     //  add    regOffs, regOffs, regT
958                     instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
959                     getEmitter()->emitIns_R_R_R(INS_add, EA_4BYTE, regOffs, regOffs, regT, flags);
960                 }
961                 //  ins    ireg, [regOffs]
962                 getEmitter()->emitIns_R_R_I(ins, size, ireg, regOffs, 0, flags);
963
964                 regTracker.rsTrackRegTrash(regOffs);
965             }
966             else
967             {
968                 //  mov    regOffs, offs
969                 //  ins    ireg, [regT + regOffs]
970                 instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
971                 getEmitter()->emitIns_R_R_R(ins, size, ireg, regT, regOffs, flags);
972             }
973         }
974     }
975     else // (insType == eIT_Other);
976     {
977         // Setup regVal
978         //
979
980         regVal = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
981         regTracker.rsTrackRegTrash(regVal);
982         avoidMask |= genRegMask(regVal);
983         var_types load_store_type;
984         switch (size)
985         {
986             case EA_4BYTE:
987                 load_store_type = TYP_INT;
988                 break;
989
990             case EA_2BYTE:
991                 load_store_type = TYP_SHORT;
992                 break;
993
994             case EA_1BYTE:
995                 load_store_type = TYP_BYTE;
996                 break;
997
998             default:
999                 assert(!"Unexpected size in sched_AM, eIT_Other");
1000                 load_store_type = TYP_INT;
1001                 break;
1002         }
1003
1004         // Load the content at addr into regVal using regT + offs
1005         if (arm_Valid_Disp_For_LdSt(offs, load_store_type))
1006         {
1007             //  ldrX   regVal, [regT + offs]
1008             getEmitter()->emitIns_R_R_I(ins_Load(load_store_type), size, regVal, regT, offs);
1009         }
1010         else
1011         {
1012             //  mov    regOffs, offs
1013             //  ldrX   regVal, [regT + regOffs]
1014             regOffs = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
1015             avoidMask |= genRegMask(regOffs);
1016             instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
1017             getEmitter()->emitIns_R_R_R(ins_Load(load_store_type), size, regVal, regT, regOffs);
1018         }
1019
1020         if (cons)
1021         {
1022             if (arm_Valid_Imm_For_Instr(ins, imm, flags))
1023             {
1024                 getEmitter()->emitIns_R_I(ins, size, regVal, imm, flags);
1025             }
1026             else
1027             {
1028                 assert(regOffs == REG_NA);
1029                 regImm = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
1030                 avoidMask |= genRegMask(regImm);
1031                 instGen_Set_Reg_To_Imm(size, regImm, imm);
1032                 getEmitter()->emitIns_R_R(ins, size, regVal, regImm, flags);
1033             }
1034         }
1035         else if (rdst)
1036         {
1037             getEmitter()->emitIns_R_R(ins, size, ireg, regVal, flags);
1038         }
1039         else
1040         {
1041             getEmitter()->emitIns_R_R(ins, size, regVal, ireg, flags);
1042         }
1043
1044         //  If we do not have a register destination we must perform the write-back store instruction
1045         //  (unless we have an instruction like INS_cmp that does not write a destination)
1046         //
1047         if (!rdst && ins_Writes_Dest(ins))
1048         {
1049             // Store regVal into [addr]
1050             if (regOffs == REG_NA)
1051             {
1052                 //  strX   regVal, [regT + offs]
1053                 getEmitter()->emitIns_R_R_I(ins_Store(load_store_type), size, regVal, regT, offs);
1054             }
1055             else
1056             {
1057                 //  strX   regVal, [regT + regOffs]
1058                 getEmitter()->emitIns_R_R_R(ins_Store(load_store_type), size, regVal, regT, regOffs);
1059             }
1060         }
1061     }
1062 }
1063
1064 #else // !CPU_LOAD_STORE_ARCH
1065
1066 /*****************************************************************************
1067  *
1068  *  This is somewhat specific to the x86 instrution format.
1069  *  We currently don't have an instruction scheduler enabled on any target.
1070  *
1071  *  [Schedule] an "ins reg, [r/m]" (rdst=true), or "ins [r/m], reg" (rdst=false)
1072  *  instruction (the r/m operand given by a tree). We also allow instructions
1073  *  of the form "ins [r/m], icon", these are signalled by setting 'cons' to
1074  *  true.
1075  */
1076
1077 void CodeGen::sched_AM(instruction ins,
1078                        emitAttr    size,
1079                        regNumber   ireg,
1080                        bool        rdst,
1081                        GenTree*    addr,
1082                        unsigned    offs,
1083                        bool        cons,
1084                        int         imm,
1085                        insFlags    flags)
1086 {
1087 #ifdef _TARGET_XARCH_
1088     /* Don't use this method for issuing calls. Use instEmit_xxxCall() */
1089     assert(ins != INS_call);
1090 #endif
1091
1092     assert(addr);
1093     assert(size != EA_UNKNOWN);
1094
1095     regNumber reg;
1096
1097     /* Has the address been conveniently loaded into a register,
1098        or is it an absolute value ? */
1099
1100     if ((addr->InReg()) || (addr->IsCnsIntOrI()))
1101     {
1102         if (addr->InReg())
1103         {
1104             /* The address is "[reg+offs]" */
1105
1106             reg = addr->gtRegNum;
1107
1108             if (cons)
1109                 getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs);
1110             else if (rdst)
1111                 getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs);
1112             else
1113                 getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs);
1114         }
1115         else
1116         {
1117             /* The address is an absolute value */
1118
1119             assert(addr->IsCnsIntOrI());
1120
1121             // Do we need relocations?
1122             if (compiler->opts.compReloc && addr->IsIconHandle())
1123             {
1124                 size = EA_SET_FLG(size, EA_DSP_RELOC_FLG);
1125                 // offs should be smaller than ZapperModule::FixupPlaceHolder
1126                 // so that we can uniquely identify the handle
1127                 assert(offs <= 4);
1128             }
1129
1130             reg          = REG_NA;
1131             ssize_t disp = addr->gtIntCon.gtIconVal + offs;
1132
1133             // Cross our fingers and hope the codegenerator did the right
1134             // thing and the constant address can be RIP-relative
1135
1136             if (cons)
1137                 getEmitter()->emitIns_I_AI(ins, size, imm, disp);
1138             else if (rdst)
1139                 getEmitter()->emitIns_R_AI(ins, size, ireg, disp);
1140             else
1141                 getEmitter()->emitIns_AI_R(ins, size, ireg, disp);
1142         }
1143
1144         return;
1145     }
1146
1147     /* Figure out what complex address mode to use */
1148
1149     regNumber baseReg, indReg;
1150     unsigned  indScale = 0, cns = 0;
1151
1152     instGetAddrMode(addr, &baseReg, &indScale, &indReg, &cns);
1153
1154     /* Add the constant offset value, if present */
1155
1156     offs += cns;
1157
1158     /* Is there an index reg operand? */
1159
1160     if (indReg != REG_NA)
1161     {
1162         /* Is the index reg operand scaled? */
1163
1164         if (indScale)
1165         {
1166             /* Is there a base address operand? */
1167
1168             if (baseReg != REG_NA)
1169             {
1170                 reg = baseReg;
1171
1172                 /* The address is "[reg + {2/4/8} * indReg + offs]" */
1173
1174                 if (cons)
1175                     getEmitter()->emitIns_I_ARX(ins, size, imm, reg, indReg, indScale, offs);
1176                 else if (rdst)
1177                     getEmitter()->emitIns_R_ARX(ins, size, ireg, reg, indReg, indScale, offs);
1178                 else
1179                     getEmitter()->emitIns_ARX_R(ins, size, ireg, reg, indReg, indScale, offs);
1180             }
1181             else
1182             {
1183                 /* The address is "[{2/4/8} * indReg + offs]" */
1184
1185                 if (cons)
1186                     getEmitter()->emitIns_I_AX(ins, size, imm, indReg, indScale, offs);
1187                 else if (rdst)
1188                     getEmitter()->emitIns_R_AX(ins, size, ireg, indReg, indScale, offs);
1189                 else
1190                     getEmitter()->emitIns_AX_R(ins, size, ireg, indReg, indScale, offs);
1191             }
1192         }
1193         else
1194         {
1195             assert(baseReg != REG_NA);
1196             reg = baseReg;
1197
1198             /* The address is "[reg + indReg + offs]" */
1199             if (cons)
1200                 getEmitter()->emitIns_I_ARR(ins, size, imm, reg, indReg, offs);
1201             else if (rdst)
1202                 getEmitter()->emitIns_R_ARR(ins, size, ireg, reg, indReg, offs);
1203             else
1204                 getEmitter()->emitIns_ARR_R(ins, size, ireg, reg, indReg, offs);
1205         }
1206     }
1207     else
1208     {
1209         unsigned             cpx = 0;
1210         CORINFO_CLASS_HANDLE cls = 0;
1211
1212         /* No second operand: the address is "[reg  + icon]" */
1213
1214         assert(baseReg != REG_NA);
1215         reg = baseReg;
1216
1217         if (cons)
1218         {
1219             getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs);
1220         }
1221         else if (rdst)
1222         {
1223             getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs);
1224         }
1225         else
1226         {
1227             getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs);
1228         }
1229     }
1230 }
1231
1232 #endif // !CPU_LOAD_STORE_ARCH
1233
1234 /*****************************************************************************
1235  *
1236  *  Emit a "call [r/m]" instruction (the r/m operand given by a tree).
1237  */
1238
1239 // clang-format off
1240 void CodeGen::instEmit_indCall(GenTreeCall* call,
1241                                size_t     argSize,
1242                                emitAttr   retSize
1243                                MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize))
1244 // clang-format on
1245 {
1246     GenTree* addr;
1247
1248     emitter::EmitCallType emitCallType;
1249
1250     regNumber brg = REG_NA;
1251     regNumber xrg = REG_NA;
1252     unsigned  mul = 0;
1253     unsigned  cns = 0;
1254
1255     CORINFO_SIG_INFO* sigInfo = nullptr;
1256
1257     /* Get hold of the function address */
1258
1259     assert(call->gtCallType == CT_INDIRECT);
1260     addr = call->gtCallAddr;
1261     assert(addr);
1262
1263 #ifdef DEBUG
1264     // Pass the call signature information from the GenTree node so the emitter can associate
1265     // native call sites with the signatures they were generated from.
1266     sigInfo = call->callSig;
1267 #endif // DEBUG
1268
1269 #if CPU_LOAD_STORE_ARCH
1270
1271     emitCallType = emitter::EC_INDIR_R;
1272
1273     if (!addr->OperIsIndir())
1274     {
1275         if (!(addr->InReg()) && (addr->OperGet() == GT_CNS_INT))
1276         {
1277             ssize_t funcPtr = addr->gtIntCon.gtIconVal;
1278
1279             // clang-format off
1280             getEmitter()->emitIns_Call(emitter::EC_FUNC_ADDR,
1281                                        NULL, // methHnd
1282                                        INDEBUG_LDISASM_COMMA(sigInfo)
1283                                        (void*) funcPtr,
1284                                        argSize,
1285                                        retSize
1286                                        MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1287                                        gcInfo.gcVarPtrSetCur,
1288                                        gcInfo.gcRegGCrefSetCur,
1289                                        gcInfo.gcRegByrefSetCur);
1290             // clang-format on
1291
1292             return;
1293         }
1294     }
1295     else
1296     {
1297         /* Get hold of the address of the function pointer */
1298
1299         addr = addr->gtOp.gtOp1;
1300     }
1301
1302     if (addr->InReg())
1303     {
1304         /* The address is "reg" */
1305
1306         brg = addr->gtRegNum;
1307     }
1308     else
1309     {
1310         // Force the address into a register
1311         CLANG_FORMAT_COMMENT_ANCHOR;
1312
1313 #ifdef LEGACY_BACKEND
1314         genCodeForTree(addr, RBM_NONE);
1315 #endif // LEGACY_BACKEND
1316         assert(addr->InReg());
1317         brg = addr->gtRegNum;
1318     }
1319
1320 #else // CPU_LOAD_STORE_ARCH
1321
1322     /* Is there an indirection? */
1323
1324     if (!addr->OperIsIndir())
1325     {
1326         if (addr->InReg())
1327         {
1328             emitCallType = emitter::EC_INDIR_R;
1329             brg          = addr->gtRegNum;
1330         }
1331         else
1332         {
1333             if (addr->OperGet() != GT_CNS_INT)
1334             {
1335                 assert(addr->OperGet() == GT_LCL_VAR);
1336
1337                 emitCallType = emitter::EC_INDIR_SR;
1338                 cns          = addr->gtLclVarCommon.gtLclNum;
1339             }
1340             else
1341             {
1342                 ssize_t funcPtr = addr->gtIntCon.gtIconVal;
1343
1344                 // clang-format off
1345                 getEmitter()->emitIns_Call(emitter::EC_FUNC_ADDR,
1346                                            nullptr, // methHnd
1347                                            INDEBUG_LDISASM_COMMA(sigInfo)
1348                                            (void*) funcPtr,
1349                                            argSize,
1350                                            retSize
1351                                            MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1352                                            gcInfo.gcVarPtrSetCur,
1353                                            gcInfo.gcRegGCrefSetCur,
1354                                            gcInfo.gcRegByrefSetCur);
1355                 // clang-format on
1356
1357                 return;
1358             }
1359         }
1360     }
1361     else
1362     {
1363         /* This is an indirect call */
1364
1365         emitCallType = emitter::EC_INDIR_ARD;
1366
1367         /* Get hold of the address of the function pointer */
1368
1369         addr = addr->gtOp.gtOp1;
1370
1371         /* Has the address been conveniently loaded into a register? */
1372
1373         if (addr->InReg())
1374         {
1375             /* The address is "reg" */
1376
1377             brg = addr->gtRegNum;
1378         }
1379         else
1380         {
1381             bool rev = false;
1382
1383             GenTree* rv1 = nullptr;
1384             GenTree* rv2 = nullptr;
1385
1386             /* Figure out what complex address mode to use */
1387
1388             INDEBUG(bool yes =)
1389             genCreateAddrMode(addr, -1, true, RBM_NONE, &rev, &rv1, &rv2, &mul, &cns);
1390
1391             INDEBUG(PREFIX_ASSUME(yes)); // since we have called genMakeAddressable() on call->gtCallAddr
1392
1393             /* Get the additional operands if any */
1394
1395             if (rv1)
1396             {
1397                 assert(rv1->InReg());
1398                 brg = rv1->gtRegNum;
1399             }
1400
1401             if (rv2)
1402             {
1403                 assert(rv2->InReg());
1404                 xrg = rv2->gtRegNum;
1405             }
1406         }
1407     }
1408
1409     assert(emitCallType == emitter::EC_INDIR_R || emitCallType == emitter::EC_INDIR_SR ||
1410            emitCallType == emitter::EC_INDIR_C || emitCallType == emitter::EC_INDIR_ARD);
1411
1412 #endif // CPU_LOAD_STORE_ARCH
1413
1414     // clang-format off
1415     getEmitter()->emitIns_Call(emitCallType,
1416                                nullptr,                                // methHnd
1417                                INDEBUG_LDISASM_COMMA(sigInfo)
1418                                nullptr, // addr
1419                                argSize,
1420                                retSize
1421                                MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1422                                gcInfo.gcVarPtrSetCur,
1423                                gcInfo.gcRegGCrefSetCur,
1424                                gcInfo.gcRegByrefSetCur,
1425                                BAD_IL_OFFSET, // ilOffset
1426                                brg,
1427                                xrg,
1428                                mul,
1429                                cns); // addressing mode values
1430     // clang-format on
1431 }
1432
1433 /*****************************************************************************
1434  *
1435  *  Emit an "op [r/m]" instruction (the r/m operand given by a tree).
1436  */
1437
1438 void CodeGen::instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs)
1439 {
1440     emitAttr size;
1441
1442     if (!instIsFP(ins))
1443         size = emitTypeSize(tree->TypeGet());
1444     else
1445         size = EA_ATTR(genTypeSize(tree->TypeGet()));
1446
1447     sched_AM(ins, size, REG_NA, false, addr, offs);
1448 }
1449
1450 /*****************************************************************************
1451  *
1452  *  Emit an "op [r/m], reg" instruction (the r/m operand given by a tree).
1453  */
1454
1455 void CodeGen::instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs)
1456 {
1457 #ifdef _TARGET_XARCH_
1458     assert(instIsFP(ins) == 0);
1459 #endif
1460     sched_AM(ins, size, reg, false, tree, offs);
1461 }
1462 #endif // LEGACY_BACKEND
1463
1464 /*****************************************************************************
1465  *
1466  *  Generate an instruction that has one operand given by a tree (which has
1467  *  been made addressable).
1468  */
1469
1470 void CodeGen::inst_TT(instruction ins, GenTree* tree, unsigned offs, int shfv, emitAttr size)
1471 {
1472     bool sizeInferred = false;
1473
1474     if (size == EA_UNKNOWN)
1475     {
1476         sizeInferred = true;
1477         if (instIsFP(ins))
1478         {
1479             size = EA_ATTR(genTypeSize(tree->TypeGet()));
1480         }
1481         else
1482         {
1483             size = emitTypeSize(tree->TypeGet());
1484         }
1485     }
1486
1487 AGAIN:
1488
1489 #ifdef LEGACY_BACKEND
1490     /* Is the value sitting in a register? */
1491
1492     if (tree->InReg())
1493     {
1494         regNumber reg;
1495
1496 #ifndef _TARGET_64BIT_
1497     LONGREG_TT:
1498 #endif
1499
1500 #if FEATURE_STACK_FP_X87
1501
1502         /* Is this a floating-point instruction? */
1503
1504         if (isFloatRegType(tree->gtType))
1505         {
1506             reg = tree->gtRegNum;
1507
1508             assert(instIsFP(ins) && ins != INS_fst && ins != INS_fstp);
1509             assert(shfv == 0);
1510
1511             inst_FS(ins, reg + genGetFPstkLevel());
1512             return;
1513         }
1514 #endif // FEATURE_STACK_FP_X87
1515
1516         assert(!instIsFP(ins));
1517
1518 #if CPU_LONG_USES_REGPAIR
1519         if (tree->gtType == TYP_LONG)
1520         {
1521             if (offs)
1522             {
1523                 assert(offs == sizeof(int));
1524                 reg = genRegPairHi(tree->gtRegPair);
1525             }
1526             else
1527             {
1528                 reg = genRegPairLo(tree->gtRegPair);
1529             }
1530         }
1531         else
1532 #endif // CPU_LONG_USES_REGPAIR
1533         {
1534             reg = tree->gtRegNum;
1535         }
1536
1537         /* Make sure it is not the "stack-half" of an enregistered long */
1538
1539         if (reg != REG_STK)
1540         {
1541             // For short types, indicate that the value is promoted to 4 bytes.
1542             // For longs, we are only emitting half of it so again set it to 4 bytes.
1543             // but leave the GC tracking information alone
1544             if (sizeInferred && EA_SIZE(size) < EA_4BYTE)
1545             {
1546                 size = EA_SET_SIZE(size, 4);
1547             }
1548
1549             if (shfv)
1550             {
1551                 getEmitter()->emitIns_R_I(ins, size, reg, shfv);
1552             }
1553             else
1554             {
1555                 inst_RV(ins, reg, tree->TypeGet(), size);
1556             }
1557
1558             return;
1559         }
1560     }
1561 #endif // LEGACY_BACKEND
1562
1563     /* Is this a spilled value? */
1564
1565     if (tree->gtFlags & GTF_SPILLED)
1566     {
1567         assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
1568     }
1569
1570     switch (tree->gtOper)
1571     {
1572         unsigned varNum;
1573
1574         case GT_LCL_VAR:
1575
1576 #ifdef LEGACY_BACKEND
1577             /* Is this an enregistered long ? */
1578
1579             if (tree->gtType == TYP_LONG && !(tree->InReg()))
1580             {
1581                 /* Avoid infinite loop */
1582
1583                 if (genMarkLclVar(tree))
1584                     goto LONGREG_TT;
1585             }
1586 #endif // LEGACY_BACKEND
1587
1588             inst_set_SV_var(tree);
1589             goto LCL;
1590
1591         case GT_LCL_FLD:
1592
1593             offs += tree->gtLclFld.gtLclOffs;
1594             goto LCL;
1595
1596         LCL:
1597             varNum = tree->gtLclVarCommon.gtLclNum;
1598             assert(varNum < compiler->lvaCount);
1599
1600             if (shfv)
1601             {
1602                 getEmitter()->emitIns_S_I(ins, size, varNum, offs, shfv);
1603             }
1604             else
1605             {
1606                 getEmitter()->emitIns_S(ins, size, varNum, offs);
1607             }
1608
1609             return;
1610
1611         case GT_CLS_VAR:
1612             // Make sure FP instruction size matches the operand size
1613             // (We optimized constant doubles to floats when we can, just want to
1614             // make sure that we don't mistakenly use 8 bytes when the
1615             // constant.
1616             assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
1617
1618             if (shfv)
1619             {
1620                 getEmitter()->emitIns_C_I(ins, size, tree->gtClsVar.gtClsVarHnd, offs, shfv);
1621             }
1622             else
1623             {
1624                 getEmitter()->emitIns_C(ins, size, tree->gtClsVar.gtClsVarHnd, offs);
1625             }
1626             return;
1627
1628         case GT_IND:
1629         case GT_NULLCHECK:
1630         case GT_ARR_ELEM:
1631         {
1632 #ifndef LEGACY_BACKEND
1633             assert(!"inst_TT not supported for GT_IND, GT_NULLCHECK or GT_ARR_ELEM in !LEGACY_BACKEND");
1634 #else  // LEGACY_BACKEND
1635             GenTree* addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
1636             if (shfv)
1637                 sched_AM(ins, size, REG_NA, false, addr, offs, true, shfv);
1638             else
1639                 instEmit_RM(ins, tree, addr, offs);
1640 #endif // LEGACY_BACKEND
1641         }
1642         break;
1643
1644 #ifdef _TARGET_X86_
1645         case GT_CNS_INT:
1646             // We will get here for GT_MKREFANY from CodeGen::genPushArgList
1647             assert(offs == 0);
1648             assert(!shfv);
1649             if (tree->IsIconHandle())
1650                 inst_IV_handle(ins, tree->gtIntCon.gtIconVal);
1651             else
1652                 inst_IV(ins, tree->gtIntCon.gtIconVal);
1653             break;
1654 #endif
1655
1656         case GT_COMMA:
1657             //     tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
1658             tree = tree->gtOp.gtOp2;
1659             goto AGAIN;
1660
1661         default:
1662             assert(!"invalid address");
1663     }
1664 }
1665
1666 /*****************************************************************************
1667  *
1668  *  Generate an instruction that has one operand given by a tree (which has
1669  *  been made addressable) and another that is a register.
1670  */
1671
1672 void CodeGen::inst_TT_RV(instruction ins, GenTree* tree, regNumber reg, unsigned offs, emitAttr size, insFlags flags)
1673 {
1674     assert(reg != REG_STK);
1675
1676 AGAIN:
1677
1678 #ifdef LEGACY_BACKEND
1679     /* Is the value sitting in a register? */
1680
1681     if (tree->InReg())
1682     {
1683         regNumber rg2;
1684
1685 #ifdef _TARGET_64BIT_
1686         assert(!instIsFP(ins));
1687
1688         rg2 = tree->gtRegNum;
1689
1690         assert(offs == 0);
1691         assert(rg2 != REG_STK);
1692
1693         if (ins != INS_mov || rg2 != reg)
1694         {
1695             inst_RV_RV(ins, rg2, reg, tree->TypeGet());
1696         }
1697         return;
1698
1699 #else // !_TARGET_64BIT_
1700
1701 #ifdef LEGACY_BACKEND
1702     LONGREG_TT_RV:
1703 #endif // LEGACY_BACKEND
1704
1705 #ifdef _TARGET_XARCH_
1706         assert(!instIsFP(ins));
1707 #endif
1708
1709 #if CPU_LONG_USES_REGPAIR
1710         if (tree->gtType == TYP_LONG)
1711         {
1712             if (offs)
1713             {
1714                 assert(offs == sizeof(int));
1715                 rg2 = genRegPairHi(tree->gtRegPair);
1716             }
1717             else
1718             {
1719                 rg2 = genRegPairLo(tree->gtRegPair);
1720             }
1721         }
1722         else
1723 #endif // CPU_LONG_USES_REGPAIR
1724         {
1725             rg2 = tree->gtRegNum;
1726         }
1727
1728         if (rg2 != REG_STK)
1729         {
1730             if (ins != INS_mov || rg2 != reg)
1731                 inst_RV_RV(ins, rg2, reg, tree->TypeGet(), size, flags);
1732             return;
1733         }
1734
1735 #endif // _TARGET_64BIT_
1736     }
1737 #endif // LEGACY_BACKEND
1738
1739     /* Is this a spilled value? */
1740
1741     if (tree->gtFlags & GTF_SPILLED)
1742     {
1743         assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
1744     }
1745
1746     if (size == EA_UNKNOWN)
1747     {
1748         if (instIsFP(ins))
1749         {
1750             size = EA_ATTR(genTypeSize(tree->TypeGet()));
1751         }
1752         else
1753         {
1754             size = emitTypeSize(tree->TypeGet());
1755         }
1756     }
1757
1758     switch (tree->gtOper)
1759     {
1760         unsigned varNum;
1761
1762         case GT_LCL_VAR:
1763
1764 #ifdef LEGACY_BACKEND
1765             if (tree->gtType == TYP_LONG && !(tree->InReg()))
1766             {
1767                 /* Avoid infinite loop */
1768
1769                 if (genMarkLclVar(tree))
1770                     goto LONGREG_TT_RV;
1771             }
1772 #endif // LEGACY_BACKEND
1773
1774             inst_set_SV_var(tree);
1775             goto LCL;
1776
1777         case GT_LCL_FLD:
1778         case GT_STORE_LCL_FLD:
1779             offs += tree->gtLclFld.gtLclOffs;
1780             goto LCL;
1781
1782         LCL:
1783
1784             varNum = tree->gtLclVarCommon.gtLclNum;
1785             assert(varNum < compiler->lvaCount);
1786
1787 #if CPU_LOAD_STORE_ARCH
1788             if (!getEmitter()->emitInsIsStore(ins))
1789             {
1790 #ifndef LEGACY_BACKEND
1791                 // TODO-LdStArch-Bug: Should regTmp be a dst on the node or an internal reg?
1792                 // Either way, it is not currently being handled by Lowering.
1793                 regNumber regTmp = tree->gtRegNum;
1794                 assert(regTmp != REG_NA);
1795 #else  // LEGACY_BACKEND
1796                 regNumber regTmp      = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
1797 #endif // LEGACY_BACKEND
1798                 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
1799                 getEmitter()->emitIns_R_R(ins, size, regTmp, reg, flags);
1800                 getEmitter()->emitIns_S_R(ins_Store(tree->TypeGet()), size, regTmp, varNum, offs);
1801
1802                 regTracker.rsTrackRegTrash(regTmp);
1803             }
1804             else
1805 #endif
1806             {
1807                 // ins is a Store instruction
1808                 //
1809                 getEmitter()->emitIns_S_R(ins, size, reg, varNum, offs);
1810 #ifdef _TARGET_ARM_
1811                 // If we need to set the flags then add an extra movs reg,reg instruction
1812                 if (flags == INS_FLAGS_SET)
1813                     getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
1814 #endif
1815             }
1816             return;
1817
1818         case GT_CLS_VAR:
1819             // Make sure FP instruction size matches the operand size
1820             // (We optimized constant doubles to floats when we can, just want to
1821             // make sure that we don't mistakenly use 8 bytes when the
1822             // constant).
1823             assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
1824
1825 #if CPU_LOAD_STORE_ARCH
1826             if (!getEmitter()->emitInsIsStore(ins))
1827             {
1828 #ifndef LEGACY_BACKEND
1829                 NYI("Store of GT_CLS_VAR not supported for ARM RyuJIT Backend");
1830 #else  // LEGACY_BACKEND
1831                 regNumber regTmpAddr  = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
1832                 regNumber regTmpArith = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg) & ~genRegMask(regTmpAddr));
1833
1834                 getEmitter()->emitIns_R_C(INS_lea, EA_PTRSIZE, regTmpAddr, tree->gtClsVar.gtClsVarHnd, offs);
1835                 getEmitter()->emitIns_R_R(ins_Load(tree->TypeGet()), size, regTmpArith, regTmpAddr);
1836                 getEmitter()->emitIns_R_R(ins, size, regTmpArith, reg, flags);
1837                 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpArith, regTmpAddr);
1838
1839                 regTracker.rsTrackRegTrash(regTmpAddr);
1840                 regTracker.rsTrackRegTrash(regTmpArith);
1841 #endif // LEGACY_BACKEND
1842             }
1843             else
1844 #endif // CPU_LOAD_STORE_ARCH
1845             {
1846                 getEmitter()->emitIns_C_R(ins, size, tree->gtClsVar.gtClsVarHnd, reg, offs);
1847             }
1848             return;
1849
1850         case GT_IND:
1851         case GT_NULLCHECK:
1852         case GT_ARR_ELEM:
1853         {
1854 #ifndef LEGACY_BACKEND
1855             assert(!"inst_TT_RV not supported for GT_IND, GT_NULLCHECK or GT_ARR_ELEM in RyuJIT Backend");
1856 #else  // LEGACY_BACKEND
1857             GenTree* addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
1858             sched_AM(ins, size, reg, false, addr, offs, false, 0, flags);
1859 #endif // LEGACY_BACKEND
1860         }
1861         break;
1862
1863         case GT_COMMA:
1864             //     tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
1865             tree = tree->gtOp.gtOp2;
1866             goto AGAIN;
1867
1868         default:
1869             assert(!"invalid address");
1870     }
1871 }
1872
1873 #ifdef LEGACY_BACKEND
1874 regNumber CodeGen::genGetZeroRegister()
1875 {
1876     // Is the constant already in some register?
1877
1878     regNumber zeroReg = regTracker.rsIconIsInReg(0);
1879
1880     if (zeroReg == REG_NA)
1881     {
1882         regMaskTP freeMask = regSet.rsRegMaskFree();
1883
1884         if ((freeMask != 0) && (compiler->compCodeOpt() != Compiler::FAST_CODE))
1885         {
1886             // For SMALL_CODE and BLENDED_CODE,
1887             // we try to generate:
1888             //
1889             //  xor   reg,  reg
1890             //  mov   dest, reg
1891             //
1892             // When selecting a register to xor we try to avoid REG_TMP_0
1893             // when we have another CALLEE_TRASH register available.
1894             // This will often let us reuse the zeroed register in
1895             // several back-to-back assignments
1896             //
1897             if ((freeMask & RBM_CALLEE_TRASH) != RBM_TMP_0)
1898                 freeMask &= ~RBM_TMP_0;
1899             zeroReg = regSet.rsGrabReg(freeMask); // PickReg in stress will pick 'random' registers
1900                                                   // We want one in the freeMask set, so just use GrabReg
1901             genSetRegToIcon(zeroReg, 0, TYP_INT);
1902         }
1903     }
1904
1905     return zeroReg;
1906 }
1907
1908 /*****************************************************************************
1909  *
1910  *  Generate an instruction that has one operand given by a tree (which has
1911  *  been made addressable) and another that is an integer constant.
1912  */
1913 void CodeGen::inst_TT_IV(instruction ins, GenTree* tree, ssize_t val, unsigned offs, emitAttr size, insFlags flags)
1914 {
1915     bool sizeInferred = false;
1916
1917     if (size == EA_UNKNOWN)
1918     {
1919         sizeInferred = true;
1920         if (instIsFP(ins))
1921             size = EA_ATTR(genTypeSize(tree->TypeGet()));
1922         else
1923             size = emitTypeSize(tree->TypeGet());
1924     }
1925
1926 AGAIN:
1927
1928     /* Is the value sitting in a register? */
1929
1930     if (tree->InReg())
1931     {
1932 #ifndef _TARGET_64BIT_
1933     LONGREG_TT_IV:
1934 #endif
1935         regNumber reg;
1936
1937         assert(instIsFP(ins) == 0);
1938
1939 #if CPU_LONG_USES_REGPAIR
1940         if (tree->gtType == TYP_LONG)
1941         {
1942             if (offs == 0)
1943             {
1944                 reg = genRegPairLo(tree->gtRegPair);
1945             }
1946             else // offs == 4
1947             {
1948                 assert(offs == sizeof(int));
1949                 reg = genRegPairHi(tree->gtRegPair);
1950             }
1951 #if CPU_LOAD_STORE_ARCH
1952             if (reg == REG_STK && !getEmitter()->emitInsIsLoadOrStore(ins))
1953             {
1954                 reg = regSet.rsPickFreeReg();
1955                 inst_RV_TT(INS_mov, reg, tree, offs, EA_4BYTE, flags);
1956                 regTracker.rsTrackRegTrash(reg);
1957             }
1958 #endif
1959         }
1960         else
1961 #endif // CPU_LONG_USES_REGPAIR
1962         {
1963             reg = tree->gtRegNum;
1964         }
1965
1966         if (reg != REG_STK)
1967         {
1968             // We always widen as part of enregistering,
1969             // so a smaller tree in a register can be
1970             // treated as 4 bytes
1971             if (sizeInferred && (size < EA_4BYTE))
1972             {
1973                 size = EA_SET_SIZE(size, EA_4BYTE);
1974             }
1975
1976             if ((ins == INS_mov) && !EA_IS_CNS_RELOC(size))
1977             {
1978                 genSetRegToIcon(reg, val, tree->TypeGet(), flags);
1979             }
1980             else
1981             {
1982 #if defined(_TARGET_XARCH_)
1983                 inst_RV_IV(ins, reg, val, size);
1984 #elif defined(_TARGET_ARM_)
1985                 if (!EA_IS_CNS_RELOC(size) && arm_Valid_Imm_For_Instr(ins, val, flags))
1986                 {
1987                     getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
1988                 }
1989                 else // We need a scratch register
1990                 {
1991                     // Load imm into a register
1992                     regMaskTP usedMask;
1993                     if (tree->gtType == TYP_LONG)
1994                     {
1995                         usedMask = genRegPairMask(tree->gtRegPair);
1996 #if CPU_LOAD_STORE_ARCH
1997                         // In gtRegPair, this part of the long may have been on the stack
1998                         // in which case, the code above would have loaded it into 'reg'
1999                         // and so we need to also include 'reg' in the set of registers
2000                         // that are already in use.
2001                         usedMask |= genRegMask(reg);
2002 #endif // CPU_LOAD_STORE_ARCH
2003                     }
2004                     else
2005                     {
2006                         usedMask = genRegMask(tree->gtRegNum);
2007                     }
2008                     regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~usedMask);
2009                     noway_assert(reg != immReg);
2010                     instGen_Set_Reg_To_Imm(size, immReg, val);
2011                     if (getEmitter()->emitInsIsStore(ins))
2012                         ins = INS_mov;
2013                     getEmitter()->emitIns_R_R(ins, size, reg, immReg, flags);
2014                 }
2015 #else
2016                 NYI("inst_TT_IV - unknown target");
2017 #endif
2018             }
2019             return;
2020         }
2021     }
2022
2023 #ifdef _TARGET_XARCH_
2024     /* Are we storing a zero? */
2025
2026     if ((ins == INS_mov) && (val == 0) &&
2027         ((genTypeSize(tree->gtType) == sizeof(int)) || (genTypeSize(tree->gtType) == REGSIZE_BYTES)))
2028     {
2029         regNumber zeroReg;
2030
2031         zeroReg = genGetZeroRegister();
2032
2033         if (zeroReg != REG_NA)
2034         {
2035             inst_TT_RV(INS_mov, tree, zeroReg, offs);
2036             return;
2037         }
2038     }
2039 #endif
2040
2041 #if CPU_LOAD_STORE_ARCH
2042     /* Are we storing/comparing with a constant? */
2043
2044     if (getEmitter()->emitInsIsStore(ins) || getEmitter()->emitInsIsCompare(ins))
2045     {
2046         // Load val into a register
2047
2048         regNumber valReg;
2049         valReg = regSet.rsGrabReg(RBM_ALLINT);
2050         instGen_Set_Reg_To_Imm(EA_PTRSIZE, valReg, val);
2051         inst_TT_RV(ins, tree, valReg, offs, size, flags);
2052         return;
2053     }
2054     else if (ins == INS_mov)
2055     {
2056         assert(!"Please call ins_Store(type) to get the store instruction");
2057     }
2058     assert(!getEmitter()->emitInsIsLoad(ins));
2059 #endif // CPU_LOAD_STORE_ARCH
2060
2061     /* Is this a spilled value? */
2062
2063     if (tree->gtFlags & GTF_SPILLED)
2064     {
2065         assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill], icon'");
2066     }
2067
2068 #ifdef _TARGET_AMD64_
2069     if ((EA_SIZE(size) == EA_8BYTE) && (((int)val != (ssize_t)val) || EA_IS_CNS_RELOC(size)))
2070     {
2071         // Load imm into a register
2072         regNumber immReg = regSet.rsGrabReg(RBM_ALLINT);
2073         instGen_Set_Reg_To_Imm(size, immReg, val);
2074         inst_TT_RV(ins, tree, immReg, offs);
2075         return;
2076     }
2077 #endif // _TARGET_AMD64_
2078
2079     int ival = (int)val;
2080
2081     switch (tree->gtOper)
2082     {
2083         unsigned   varNum;
2084         LclVarDsc* varDsc;
2085
2086         case GT_LCL_FLD:
2087
2088             varNum = tree->gtLclVarCommon.gtLclNum;
2089             assert(varNum < compiler->lvaCount);
2090             offs += tree->gtLclFld.gtLclOffs;
2091
2092             goto LCL;
2093
2094         case GT_LCL_VAR:
2095
2096 #ifndef _TARGET_64BIT_
2097             /* Is this an enregistered long ? */
2098             CLANG_FORMAT_COMMENT_ANCHOR;
2099 #ifdef LEGACY_BACKEND
2100             if (tree->gtType == TYP_LONG && !(tree->InReg()))
2101 #else  // !LEGACY_BACKEND
2102             if (tree->gtType == TYP_LONG)
2103 #endif // !LEGACY_BACKEND
2104             {
2105                 /* Avoid infinite loop */
2106
2107                 if (genMarkLclVar(tree))
2108                     goto LONGREG_TT_IV;
2109             }
2110 #endif // !_TARGET_64BIT_
2111
2112             inst_set_SV_var(tree);
2113
2114             varNum = tree->gtLclVarCommon.gtLclNum;
2115             assert(varNum < compiler->lvaCount);
2116             varDsc = &compiler->lvaTable[varNum];
2117
2118             // Fix the immediate by sign extending if needed
2119             if (size < EA_4BYTE && !varTypeIsUnsigned(varDsc->TypeGet()))
2120             {
2121                 if (size == EA_1BYTE)
2122                 {
2123                     if ((ival & 0x7f) != ival)
2124                         ival = ival | 0xffffff00;
2125                 }
2126                 else
2127                 {
2128                     assert(size == EA_2BYTE);
2129                     if ((ival & 0x7fff) != ival)
2130                         ival = ival | 0xffff0000;
2131                 }
2132             }
2133
2134             // A local stack slot is at least 4 bytes in size, regardles of
2135             // what the local var is typed as, so auto-promote it here
2136             // unless the codegenerator told us a size, or it is a field
2137             // of a promoted struct
2138             if (sizeInferred && (size < EA_4BYTE) && !varDsc->lvIsStructField)
2139             {
2140                 size = EA_SET_SIZE(size, EA_4BYTE);
2141             }
2142
2143         LCL:
2144
2145             /* Integer instructions never operate on more than EA_PTRSIZE */
2146
2147             assert(instIsFP(ins) == false);
2148
2149 #if CPU_LOAD_STORE_ARCH
2150             if (!getEmitter()->emitInsIsStore(ins))
2151             {
2152                 regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT);
2153                 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
2154                 regTracker.rsTrackRegTrash(regTmp);
2155
2156                 if (arm_Valid_Imm_For_Instr(ins, val, flags))
2157                 {
2158                     getEmitter()->emitIns_R_I(ins, size, regTmp, ival, flags);
2159                 }
2160                 else // We need a scratch register
2161                 {
2162                     // Load imm into a register
2163                     regNumber regImm = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regTmp));
2164
2165                     instGen_Set_Reg_To_Imm(size, regImm, val);
2166                     getEmitter()->emitIns_R_R(ins, size, regTmp, regImm, flags);
2167                 }
2168                 getEmitter()->emitIns_S_R(ins_Store(tree->TypeGet()), size, regTmp, varNum, offs);
2169             }
2170             else
2171 #endif
2172             {
2173                 getEmitter()->emitIns_S_I(ins, size, varNum, offs, ival);
2174             }
2175             return;
2176
2177         case GT_CLS_VAR:
2178             // Make sure FP instruction size matches the operand size
2179             // (We optimize constant doubles to floats when we can)
2180             // We just want to make sure that we don't mistakenly
2181             // use 8 bytes when the constant is smaller.
2182             //
2183             assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
2184
2185 #if CPU_LOAD_STORE_ARCH
2186             regNumber regTmpAddr;
2187             regTmpAddr = regSet.rsPickFreeReg(RBM_ALLINT);
2188
2189             getEmitter()->emitIns_R_C(INS_lea, EA_PTRSIZE, regTmpAddr, tree->gtClsVar.gtClsVarHnd, offs);
2190             regTracker.rsTrackRegTrash(regTmpAddr);
2191
2192             if (!getEmitter()->emitInsIsStore(ins))
2193             {
2194                 regNumber regTmpArith = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr));
2195
2196                 getEmitter()->emitIns_R_R(ins_Load(tree->TypeGet()), size, regTmpArith, regTmpAddr);
2197
2198                 if (arm_Valid_Imm_For_Instr(ins, ival, flags))
2199                 {
2200                     getEmitter()->emitIns_R_R_I(ins, size, regTmpArith, regTmpArith, ival, flags);
2201                 }
2202                 else
2203                 {
2204                     regNumber regTmpImm =
2205                         regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr) & ~genRegMask(regTmpArith));
2206                     instGen_Set_Reg_To_Imm(EA_4BYTE, regTmpImm, (ssize_t)ival);
2207                     getEmitter()->emitIns_R_R(ins, size, regTmpArith, regTmpImm, flags);
2208                 }
2209                 regTracker.rsTrackRegTrash(regTmpArith);
2210
2211                 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpArith, regTmpAddr);
2212             }
2213             else
2214             {
2215                 regNumber regTmpImm = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr));
2216
2217                 instGen_Set_Reg_To_Imm(EA_4BYTE, regTmpImm, (ssize_t)ival, flags);
2218                 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpImm, regTmpAddr);
2219             }
2220 #else // !CPU_LOAD_STORE_ARCH
2221             getEmitter()->emitIns_C_I(ins, size, tree->gtClsVar.gtClsVarHnd, offs, ival);
2222 #endif
2223             return;
2224
2225         case GT_IND:
2226         case GT_NULLCHECK:
2227         case GT_ARR_ELEM:
2228         {
2229             GenTree* addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
2230             sched_AM(ins, size, REG_NA, false, addr, offs, true, ival, flags);
2231         }
2232             return;
2233
2234         case GT_COMMA:
2235             //     tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
2236             tree = tree->gtOp.gtOp2;
2237             goto AGAIN;
2238
2239         default:
2240             assert(!"invalid address");
2241     }
2242 }
2243
2244 /*****************************************************************************
2245  *
2246  *  Generate an instruction that has one operand given by a register and the
2247  *  other one by an indirection tree (which has been made addressable).
2248  */
2249
2250 void CodeGen::inst_RV_AT(
2251     instruction ins, emitAttr size, var_types type, regNumber reg, GenTree* tree, unsigned offs, insFlags flags)
2252 {
2253 #ifdef _TARGET_XARCH_
2254 #ifdef DEBUG
2255     // If it is a GC type and the result is not, then either
2256     // 1) it is an LEA
2257     // 2) optOptimizeBools() optimized if (ref != 0 && ref != 0) to if (ref & ref)
2258     // 3) optOptimizeBools() optimized if (ref == 0 || ref == 0) to if (ref | ref)
2259     // 4) byref - byref = int
2260     if (type == TYP_REF && !EA_IS_GCREF(size))
2261         assert((EA_IS_BYREF(size) && ins == INS_add) || (ins == INS_lea || ins == INS_and || ins == INS_or));
2262     if (type == TYP_BYREF && !EA_IS_BYREF(size))
2263         assert(ins == INS_lea || ins == INS_and || ins == INS_or || ins == INS_sub);
2264     assert(!instIsFP(ins));
2265 #endif
2266 #endif
2267
2268     // Integer instructions never operate on more than EA_PTRSIZE.
2269     if (EA_SIZE(size) > EA_PTRSIZE && !instIsFP(ins))
2270         EA_SET_SIZE(size, EA_PTRSIZE);
2271
2272     GenTree* addr = tree;
2273     sched_AM(ins, size, reg, true, addr, offs, false, 0, flags);
2274 }
2275
2276 /*****************************************************************************
2277  *
2278  *  Generate an instruction that has one operand given by an indirection tree
2279  *  (which has been made addressable) and an integer constant.
2280  */
2281
2282 void CodeGen::inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs)
2283 {
2284     sched_AM(ins, size, REG_NA, false, baseTree, offs, true, icon);
2285 }
2286 #endif // LEGACY_BACKEND
2287
2288 /*****************************************************************************
2289  *
2290  *  Generate an instruction that has one operand given by a register and the
2291  *  other one by a tree (which has been made addressable).
2292  */
2293
2294 void CodeGen::inst_RV_TT(instruction ins,
2295                          regNumber   reg,
2296                          GenTree*    tree,
2297                          unsigned    offs,
2298                          emitAttr    size,
2299                          insFlags    flags /* = INS_FLAGS_DONT_CARE */)
2300 {
2301     assert(reg != REG_STK);
2302
2303     if (size == EA_UNKNOWN)
2304     {
2305         if (!instIsFP(ins))
2306         {
2307             size = emitTypeSize(tree->TypeGet());
2308         }
2309         else
2310         {
2311             size = EA_ATTR(genTypeSize(tree->TypeGet()));
2312         }
2313     }
2314
2315 #ifdef _TARGET_XARCH_
2316 #ifdef DEBUG
2317     // If it is a GC type and the result is not, then either
2318     // 1) it is an LEA
2319     // 2) optOptimizeBools() optimized if (ref != 0 && ref != 0) to if (ref & ref)
2320     // 3) optOptimizeBools() optimized if (ref == 0 || ref == 0) to if (ref | ref)
2321     // 4) byref - byref = int
2322     if (tree->gtType == TYP_REF && !EA_IS_GCREF(size))
2323     {
2324         assert((EA_IS_BYREF(size) && ins == INS_add) || (ins == INS_lea || ins == INS_and || ins == INS_or));
2325     }
2326     if (tree->gtType == TYP_BYREF && !EA_IS_BYREF(size))
2327     {
2328         assert(ins == INS_lea || ins == INS_and || ins == INS_or || ins == INS_sub);
2329     }
2330 #endif
2331 #endif
2332
2333 #if CPU_LOAD_STORE_ARCH
2334     if (ins == INS_mov)
2335     {
2336 #if defined(_TARGET_ARM_) && CPU_LONG_USES_REGPAIR
2337         if (tree->TypeGet() != TYP_LONG)
2338         {
2339             ins = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2340         }
2341         else if (offs == 0)
2342         {
2343             ins = ins_Move_Extend(TYP_INT, tree->InReg() && genRegPairLo(tree->gtRegPair) != REG_STK);
2344         }
2345         else
2346         {
2347             ins = ins_Move_Extend(TYP_INT, tree->InReg() && genRegPairHi(tree->gtRegPair) != REG_STK);
2348         }
2349 #elif defined(_TARGET_ARM64_) || defined(_TARGET_ARM64_)
2350         ins = ins_Move_Extend(tree->TypeGet(), false);
2351 #else
2352         NYI("CodeGen::inst_RV_TT with INS_mov");
2353 #endif
2354     }
2355 #endif // CPU_LOAD_STORE_ARCH
2356
2357 AGAIN:
2358
2359 #ifdef LEGACY_BACKEND
2360     /* Is the value sitting in a register? */
2361
2362     if (tree->InReg())
2363     {
2364 #ifdef _TARGET_64BIT_
2365         assert(instIsFP(ins) == 0);
2366
2367         regNumber rg2 = tree->gtRegNum;
2368
2369         assert(offs == 0);
2370         assert(rg2 != REG_STK);
2371
2372         if ((ins != INS_mov) || (rg2 != reg))
2373         {
2374             inst_RV_RV(ins, reg, rg2, tree->TypeGet(), size);
2375         }
2376         return;
2377
2378 #else // !_TARGET_64BIT_
2379
2380 #ifdef LEGACY_BACKEND
2381     LONGREG_RVTT:
2382 #endif // LEGACY_BACKEND
2383
2384 #ifdef _TARGET_XARCH_
2385         assert(instIsFP(ins) == 0);
2386 #endif
2387
2388         regNumber rg2;
2389
2390 #if CPU_LONG_USES_REGPAIR
2391         if (tree->gtType == TYP_LONG)
2392         {
2393             if (offs)
2394             {
2395                 assert(offs == sizeof(int));
2396
2397                 rg2 = genRegPairHi(tree->gtRegPair);
2398             }
2399             else
2400             {
2401                 rg2 = genRegPairLo(tree->gtRegPair);
2402             }
2403         }
2404         else
2405 #endif // LEGACY_BACKEND
2406         {
2407             rg2 = tree->gtRegNum;
2408         }
2409
2410         if (rg2 != REG_STK)
2411         {
2412 #ifdef _TARGET_ARM_
2413             if (getEmitter()->emitInsIsLoad(ins) || (ins == INS_lea))
2414             {
2415                 ins = ins_Copy(tree->TypeGet());
2416             }
2417 #endif
2418
2419             bool isMoveIns = (ins == INS_mov);
2420 #ifdef _TARGET_ARM_
2421             if (ins == INS_vmov)
2422                 isMoveIns = true;
2423 #endif
2424             if (!isMoveIns || (rg2 != reg))
2425             {
2426                 inst_RV_RV(ins, reg, rg2, tree->TypeGet(), size, flags);
2427             }
2428             return;
2429         }
2430
2431 #endif // _TARGET_64BIT_
2432     }
2433 #endif // LEGACY_BACKEND
2434
2435     /* Is this a spilled value? */
2436
2437     if (tree->gtFlags & GTF_SPILLED)
2438     {
2439         assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
2440     }
2441
2442     switch (tree->gtOper)
2443     {
2444         unsigned varNum;
2445
2446         case GT_LCL_VAR:
2447         case GT_LCL_VAR_ADDR:
2448
2449 #ifdef LEGACY_BACKEND
2450             /* Is this an enregistered long ? */
2451
2452             if (tree->gtType == TYP_LONG && !(tree->InReg()))
2453             {
2454
2455                 /* Avoid infinite loop */
2456
2457                 if (genMarkLclVar(tree))
2458                     goto LONGREG_RVTT;
2459             }
2460 #endif // LEGACY_BACKEND
2461
2462             inst_set_SV_var(tree);
2463             goto LCL;
2464
2465         case GT_LCL_FLD_ADDR:
2466         case GT_LCL_FLD:
2467             offs += tree->gtLclFld.gtLclOffs;
2468             goto LCL;
2469
2470         LCL:
2471             varNum = tree->gtLclVarCommon.gtLclNum;
2472             assert(varNum < compiler->lvaCount);
2473
2474 #ifdef _TARGET_ARM_
2475             switch (ins)
2476             {
2477                 case INS_mov:
2478                     ins = ins_Load(tree->TypeGet());
2479                     __fallthrough;
2480
2481                 case INS_lea:
2482                 case INS_ldr:
2483                 case INS_ldrh:
2484                 case INS_ldrb:
2485                 case INS_ldrsh:
2486                 case INS_ldrsb:
2487                 case INS_vldr:
2488                     assert(flags != INS_FLAGS_SET);
2489                     getEmitter()->emitIns_R_S(ins, size, reg, varNum, offs);
2490                     return;
2491
2492                 default:
2493                     regNumber regTmp;
2494 #ifndef LEGACY_BACKEND
2495 #if CPU_LONG_USES_REGPAIR
2496                     if (tree->TypeGet() == TYP_LONG)
2497                         regTmp = (offs == 0) ? genRegPairLo(tree->gtRegPair) : genRegPairHi(tree->gtRegPair);
2498                     else
2499 #endif // CPU_LONG_USES_REGPAIR
2500                         regTmp = tree->gtRegNum;
2501 #else  // LEGACY_BACKEND
2502                     if (varTypeIsFloating(tree))
2503                     {
2504                         regTmp = regSet.PickRegFloat(tree->TypeGet());
2505                     }
2506                     else
2507                     {
2508                         // Lock the destination register to ensure that rsPickReg does not choose it.
2509                         const regMaskTP regMask = genRegMask(reg);
2510                         if ((regMask & regSet.rsMaskUsed) == 0)
2511                         {
2512                             regSet.rsLockReg(regMask);
2513                             regTmp = regSet.rsPickReg(RBM_ALLINT);
2514                             regSet.rsUnlockReg(regMask);
2515                         }
2516                         else if ((regMask & regSet.rsMaskLock) == 0)
2517                         {
2518                             regSet.rsLockUsedReg(regMask);
2519                             regTmp = regSet.rsPickReg(RBM_ALLINT);
2520                             regSet.rsUnlockUsedReg(regMask);
2521                         }
2522                         else
2523                         {
2524                             regTmp = regSet.rsPickReg(RBM_ALLINT);
2525                         }
2526                     }
2527 #endif // LEGACY_BACKEND
2528
2529                     getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
2530                     getEmitter()->emitIns_R_R(ins, size, reg, regTmp, flags);
2531
2532                     regTracker.rsTrackRegTrash(regTmp);
2533                     return;
2534             }
2535 #else  // !_TARGET_ARM_
2536             getEmitter()->emitIns_R_S(ins, size, reg, varNum, offs);
2537             return;
2538 #endif // !_TARGET_ARM_
2539
2540         case GT_CLS_VAR:
2541             // Make sure FP instruction size matches the operand size
2542             // (We optimized constant doubles to floats when we can, just want to
2543             // make sure that we don't mistakenly use 8 bytes when the
2544             // constant.
2545             assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
2546
2547 #if CPU_LOAD_STORE_ARCH
2548 #ifndef LEGACY_BACKEND
2549             assert(!"GT_CLS_VAR not supported in ARM RyuJIT backend");
2550 #else  // LEGACY_BACKEND
2551             switch (ins)
2552             {
2553                 case INS_mov:
2554                     ins = ins_Load(tree->TypeGet());
2555
2556                     __fallthrough;
2557
2558                 case INS_lea:
2559                 case INS_ldr:
2560                 case INS_ldrh:
2561                 case INS_ldrb:
2562                 case INS_ldrsh:
2563                 case INS_ldrsb:
2564                 case INS_vldr:
2565                     assert(flags != INS_FLAGS_SET);
2566                     getEmitter()->emitIns_R_C(ins, size, reg, tree->gtClsVar.gtClsVarHnd, offs);
2567                     return;
2568
2569                 default:
2570                     regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2571                     getEmitter()->emitIns_R_C(ins_Load(tree->TypeGet()), size, regTmp, tree->gtClsVar.gtClsVarHnd,
2572                                               offs);
2573                     getEmitter()->emitIns_R_R(ins, size, reg, regTmp, flags);
2574                     regTracker.rsTrackRegTrash(regTmp);
2575                     return;
2576             }
2577 #endif // LEGACY_BACKEND
2578 #else  // CPU_LOAD_STORE_ARCH
2579             getEmitter()->emitIns_R_C(ins, size, reg, tree->gtClsVar.gtClsVarHnd, offs);
2580 #endif // CPU_LOAD_STORE_ARCH
2581             return;
2582
2583         case GT_IND:
2584         case GT_NULLCHECK:
2585         case GT_ARR_ELEM:
2586         case GT_LEA:
2587         {
2588 #ifndef LEGACY_BACKEND
2589             assert(!"inst_RV_TT not supported for GT_IND, GT_NULLCHECK, GT_ARR_ELEM or GT_LEA in !LEGACY_BACKEND");
2590 #else  // LEGACY_BACKEND
2591             GenTree* addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
2592             inst_RV_AT(ins, size, tree->TypeGet(), reg, addr, offs, flags);
2593 #endif // LEGACY_BACKEND
2594         }
2595         break;
2596
2597         case GT_CNS_INT:
2598
2599             assert(offs == 0);
2600
2601             inst_RV_IV(ins, reg, tree->gtIntCon.gtIconVal, emitActualTypeSize(tree->TypeGet()), flags);
2602             break;
2603
2604         case GT_CNS_LNG:
2605
2606             assert(size == EA_4BYTE || size == EA_8BYTE);
2607
2608 #ifdef _TARGET_AMD64_
2609             assert(offs == 0);
2610 #endif // _TARGET_AMD64_
2611
2612             ssize_t  constVal;
2613             emitAttr size;
2614             if (offs == 0)
2615             {
2616                 constVal = (ssize_t)(tree->gtLngCon.gtLconVal);
2617                 size     = EA_PTRSIZE;
2618             }
2619             else
2620             {
2621                 constVal = (ssize_t)(tree->gtLngCon.gtLconVal >> 32);
2622                 size     = EA_4BYTE;
2623             }
2624
2625             inst_RV_IV(ins, reg, constVal, size, flags);
2626             break;
2627
2628         case GT_COMMA:
2629             tree = tree->gtOp.gtOp2;
2630             goto AGAIN;
2631
2632         default:
2633             assert(!"invalid address");
2634     }
2635 }
2636
2637 /*****************************************************************************
2638  *
2639  *  Generate the 3-operand imul instruction "imul reg, [tree], icon"
2640  *  which is reg=[tree]*icon
2641  */
2642 #ifdef LEGACY_BACKEND
2643 void CodeGen::inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val)
2644 {
2645     assert(tree->gtType <= TYP_I_IMPL);
2646
2647 #ifdef _TARGET_XARCH_
2648     /* Only 'imul' uses this instruction format. Since we don't represent
2649        three operands for an instruction, we encode the target register as
2650        an implicit operand */
2651
2652     assert(ins == INS_imul);
2653     ins = getEmitter()->inst3opImulForReg(reg);
2654
2655     genUpdateLife(tree);
2656     inst_TT_IV(ins, tree, val);
2657 #else
2658     NYI("inst_RV_TT_IV - unknown target");
2659 #endif
2660 }
2661 #endif // LEGACY_BACKEND
2662
2663 /*****************************************************************************
2664  *
2665  *  Generate a "shift reg, icon" instruction.
2666  */
2667
2668 void CodeGen::inst_RV_SH(
2669     instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags /* = INS_FLAGS_DONT_CARE */)
2670 {
2671 #if defined(_TARGET_ARM_)
2672
2673     if (val >= 32)
2674         val &= 0x1f;
2675
2676     getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
2677
2678 #elif defined(_TARGET_XARCH_)
2679
2680 #ifdef _TARGET_AMD64_
2681     // X64 JB BE insures only encodable values make it here.
2682     // x86 can encode 8 bits, though it masks down to 5 or 6
2683     // depending on 32-bit or 64-bit registers are used.
2684     // Here we will allow anything that is encodable.
2685     assert(val < 256);
2686 #endif
2687
2688     ins = genMapShiftInsToShiftByConstantIns(ins, val);
2689
2690     if (val == 1)
2691     {
2692         getEmitter()->emitIns_R(ins, size, reg);
2693     }
2694     else
2695     {
2696         getEmitter()->emitIns_R_I(ins, size, reg, val);
2697     }
2698
2699 #else
2700     NYI("inst_RV_SH - unknown target");
2701 #endif // _TARGET_*
2702 }
2703
2704 /*****************************************************************************
2705  *
2706  *  Generate a "shift [r/m], icon" instruction.
2707  */
2708
2709 void CodeGen::inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs)
2710 {
2711 #ifdef _TARGET_XARCH_
2712     if (val == 0)
2713     {
2714         // Shift by 0 - why are you wasting our precious time????
2715         return;
2716     }
2717
2718     ins = genMapShiftInsToShiftByConstantIns(ins, val);
2719     if (val == 1)
2720     {
2721         inst_TT(ins, tree, offs, 0, emitTypeSize(tree->TypeGet()));
2722     }
2723     else
2724     {
2725         inst_TT(ins, tree, offs, val, emitTypeSize(tree->TypeGet()));
2726     }
2727 #endif // _TARGET_XARCH_
2728
2729 #ifdef _TARGET_ARM_
2730     inst_TT(ins, tree, offs, val, emitTypeSize(tree->TypeGet()));
2731 #endif
2732 }
2733
2734 /*****************************************************************************
2735  *
2736  *  Generate a "shift [addr], cl" instruction.
2737  */
2738
2739 void CodeGen::inst_TT_CL(instruction ins, GenTree* tree, unsigned offs)
2740 {
2741     inst_TT(ins, tree, offs, 0, emitTypeSize(tree->TypeGet()));
2742 }
2743
2744 /*****************************************************************************
2745  *
2746  *  Generate an instruction of the form "op reg1, reg2, icon".
2747  */
2748
2749 #if defined(_TARGET_XARCH_)
2750 void CodeGen::inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival)
2751 {
2752 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
2753     assert(ins == INS_shld || ins == INS_shrd || ins == INS_shufps || ins == INS_shufpd || ins == INS_pshufd ||
2754            ins == INS_cmpps || ins == INS_cmppd || ins == INS_dppd || ins == INS_dpps || ins == INS_insertps ||
2755            ins == INS_roundps || ins == INS_roundss || ins == INS_roundpd || ins == INS_roundsd);
2756 #else  // !_TARGET_XARCH_
2757     assert(ins == INS_shld || ins == INS_shrd);
2758 #endif // !_TARGET_XARCH_
2759
2760     getEmitter()->emitIns_R_R_I(ins, size, reg1, reg2, ival);
2761 }
2762 #endif
2763
2764 /*****************************************************************************
2765  *
2766  *  Generate an instruction with two registers, the second one being a byte
2767  *  or word register (i.e. this is something like "movzx eax, cl").
2768  */
2769
2770 void CodeGen::inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2)
2771 {
2772     assert(size == EA_1BYTE || size == EA_2BYTE);
2773 #ifdef _TARGET_XARCH_
2774     assert(ins == INS_movsx || ins == INS_movzx);
2775     assert(size != EA_1BYTE || (genRegMask(reg2) & RBM_BYTE_REGS));
2776 #endif
2777
2778     getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
2779 }
2780
2781 /*****************************************************************************
2782  *
2783  *  The following should all end up inline in compiler.hpp at some point.
2784  */
2785
2786 void CodeGen::inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type)
2787 {
2788     getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, tmp->tdTempNum(), ofs);
2789 }
2790
2791 void CodeGen::inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type)
2792 {
2793     getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), tmp->tdTempNum(), ofs, val);
2794 }
2795
2796 #if FEATURE_FIXED_OUT_ARGS
2797 /*****************************************************************************
2798  *
2799  *  Generate an instruction that references the outgoing argument space
2800  *  like "str r3, [sp+0x04]"
2801  */
2802
2803 void CodeGen::inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type)
2804 {
2805     assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2806
2807     getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, compiler->lvaOutgoingArgSpaceVar, ofs);
2808 }
2809
2810 void CodeGen::inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type)
2811 {
2812     assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2813
2814     getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), compiler->lvaOutgoingArgSpaceVar, ofs, val);
2815 }
2816 #endif // FEATURE_FIXED_OUT_ARGS
2817
2818 /*****************************************************************************
2819  *
2820  *  Generate an instruction with one register and one operand that is byte
2821  *  or short (e.g. something like "movzx eax, byte ptr [edx]").
2822  */
2823
2824 void CodeGen::inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree)
2825 {
2826     assert(size == EA_1BYTE || size == EA_2BYTE);
2827
2828 #ifdef LEGACY_BACKEND
2829     if (tree->InReg())
2830     {
2831         /* "movsx erx, rl" must be handled as a special case */
2832         inst_RV_RR(ins, size, reg, tree->gtRegNum);
2833     }
2834     else
2835 #endif // LEGACY_BACKEND
2836     {
2837         inst_RV_TT(ins, reg, tree, 0, size);
2838     }
2839 }
2840
2841 void CodeGen::inst_RV_ST(instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size)
2842 {
2843     if (size == EA_UNKNOWN)
2844     {
2845         size = emitActualTypeSize(type);
2846     }
2847
2848 #ifdef _TARGET_ARM_
2849     switch (ins)
2850     {
2851         case INS_mov:
2852             assert(!"Please call ins_Load(type) to get the load instruction");
2853             break;
2854
2855         case INS_add:
2856         case INS_ldr:
2857         case INS_ldrh:
2858         case INS_ldrb:
2859         case INS_ldrsh:
2860         case INS_ldrsb:
2861         case INS_lea:
2862         case INS_vldr:
2863             getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2864             break;
2865
2866         default:
2867 #ifndef LEGACY_BACKEND
2868             assert(!"Default inst_RV_ST case not supported for Arm !LEGACY_BACKEND");
2869 #else  // LEGACY_BACKEND
2870             regNumber regTmp;
2871             if (varTypeIsFloating(type))
2872             {
2873                 regTmp = regSet.PickRegFloat(type);
2874             }
2875             else
2876             {
2877                 regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2878             }
2879             getEmitter()->emitIns_R_S(ins_Load(type), size, regTmp, tmp->tdTempNum(), ofs);
2880             regTracker.rsTrackRegTrash(regTmp);
2881             getEmitter()->emitIns_R_R(ins, size, reg, regTmp);
2882 #endif // LEGACY_BACKEND
2883             break;
2884     }
2885 #else  // !_TARGET_ARM_
2886     getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2887 #endif // !_TARGET_ARM_
2888 }
2889
2890 void CodeGen::inst_mov_RV_ST(regNumber reg, GenTree* tree)
2891 {
2892     /* Figure out the size of the value being loaded */
2893
2894     emitAttr size = EA_ATTR(genTypeSize(tree->gtType));
2895 #ifdef LEGACY_BACKEND
2896     instruction loadIns = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2897 #else  // !LEGACY_BACKEND
2898     instruction loadIns = ins_Move_Extend(tree->TypeGet(), false);
2899 #endif // !LEGACY_BACKEND
2900
2901     if (size < EA_4BYTE)
2902     {
2903 #if CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2904         if ((tree->gtFlags & GTF_SMALL_OK) && (size == EA_1BYTE) && (genRegMask(reg) & RBM_BYTE_REGS))
2905         {
2906             /* We only need to load the actual size */
2907
2908             inst_RV_TT(INS_mov, reg, tree, 0, EA_1BYTE);
2909         }
2910         else
2911 #endif // CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2912         {
2913             /* Generate the "movsx/movzx" opcode */
2914
2915             inst_RV_ST(loadIns, size, reg, tree);
2916         }
2917     }
2918     else
2919     {
2920         /* Compute op1 into the target register */
2921
2922         inst_RV_TT(loadIns, reg, tree);
2923     }
2924 }
2925 #ifdef _TARGET_XARCH_
2926 void CodeGen::inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs)
2927 {
2928     getEmitter()->emitIns_S(ins, size, tmp->tdTempNum(), ofs);
2929 }
2930 #endif
2931
2932 #ifdef _TARGET_ARM_
2933 bool CodeGenInterface::validImmForInstr(instruction ins, ssize_t imm, insFlags flags)
2934 {
2935     if (getEmitter()->emitInsIsLoadOrStore(ins) && !instIsFP(ins))
2936     {
2937         return validDispForLdSt(imm, TYP_INT);
2938     }
2939
2940     bool result = false;
2941     switch (ins)
2942     {
2943         case INS_cmp:
2944         case INS_cmn:
2945             if (validImmForAlu(imm) || validImmForAlu(-imm))
2946                 result = true;
2947             break;
2948
2949         case INS_and:
2950         case INS_bic:
2951         case INS_orr:
2952         case INS_orn:
2953         case INS_mvn:
2954             if (validImmForAlu(imm) || validImmForAlu(~imm))
2955                 result = true;
2956             break;
2957
2958         case INS_mov:
2959             if (validImmForMov(imm))
2960                 result = true;
2961             break;
2962
2963         case INS_addw:
2964         case INS_subw:
2965             if ((unsigned_abs(imm) <= 0x00000fff) && (flags != INS_FLAGS_SET)) // 12-bit immediate
2966                 result = true;
2967             break;
2968
2969         case INS_add:
2970         case INS_sub:
2971             if (validImmForAdd(imm, flags))
2972                 result = true;
2973             break;
2974
2975         case INS_tst:
2976         case INS_eor:
2977         case INS_teq:
2978         case INS_adc:
2979         case INS_sbc:
2980         case INS_rsb:
2981             if (validImmForAlu(imm))
2982                 result = true;
2983             break;
2984
2985         case INS_asr:
2986         case INS_lsl:
2987         case INS_lsr:
2988         case INS_ror:
2989             if (imm > 0 && imm <= 32)
2990                 result = true;
2991             break;
2992
2993         case INS_vstr:
2994         case INS_vldr:
2995             if ((imm & 0x3FC) == imm)
2996                 result = true;
2997             break;
2998
2999         default:
3000             break;
3001     }
3002     return result;
3003 }
3004 bool CodeGen::arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags)
3005 {
3006     return validImmForInstr(ins, imm, flags);
3007 }
3008
3009 bool CodeGenInterface::validDispForLdSt(ssize_t disp, var_types type)
3010 {
3011     if (varTypeIsFloating(type))
3012     {
3013         if ((disp & 0x3FC) == disp)
3014             return true;
3015         else
3016             return false;
3017     }
3018     else
3019     {
3020         if ((disp >= -0x00ff) && (disp <= 0x0fff))
3021             return true;
3022         else
3023             return false;
3024     }
3025 }
3026 bool CodeGen::arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type)
3027 {
3028     return validDispForLdSt(disp, type);
3029 }
3030
3031 bool CodeGenInterface::validImmForAlu(ssize_t imm)
3032 {
3033     return emitter::emitIns_valid_imm_for_alu(imm);
3034 }
3035 bool CodeGen::arm_Valid_Imm_For_Alu(ssize_t imm)
3036 {
3037     return validImmForAlu(imm);
3038 }
3039
3040 bool CodeGenInterface::validImmForMov(ssize_t imm)
3041 {
3042     return emitter::emitIns_valid_imm_for_mov(imm);
3043 }
3044 bool CodeGen::arm_Valid_Imm_For_Mov(ssize_t imm)
3045 {
3046     return validImmForMov(imm);
3047 }
3048
3049 bool CodeGen::arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags)
3050 {
3051     return emitter::emitIns_valid_imm_for_small_mov(reg, imm, flags);
3052 }
3053
3054 bool CodeGenInterface::validImmForAdd(ssize_t imm, insFlags flags)
3055 {
3056     return emitter::emitIns_valid_imm_for_add(imm, flags);
3057 }
3058 bool CodeGen::arm_Valid_Imm_For_Add(ssize_t imm, insFlags flags)
3059 {
3060     return emitter::emitIns_valid_imm_for_add(imm, flags);
3061 }
3062
3063 // Check "add Rd,SP,i10"
3064 bool CodeGen::arm_Valid_Imm_For_Add_SP(ssize_t imm)
3065 {
3066     return emitter::emitIns_valid_imm_for_add_sp(imm);
3067 }
3068
3069 bool CodeGenInterface::validImmForBL(ssize_t addr)
3070 {
3071     return
3072         // If we are running the altjit for NGEN, then assume we can use the "BL" instruction.
3073         // This matches the usual behavior for NGEN, since we normally do generate "BL".
3074         (!compiler->info.compMatchedVM && compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) ||
3075         (compiler->eeGetRelocTypeHint((void*)addr) == IMAGE_REL_BASED_THUMB_BRANCH24);
3076 }
3077 bool CodeGen::arm_Valid_Imm_For_BL(ssize_t addr)
3078 {
3079     return validImmForBL(addr);
3080 }
3081
3082 // Returns true if this instruction writes to a destination register
3083 //
3084 bool CodeGen::ins_Writes_Dest(instruction ins)
3085 {
3086     switch (ins)
3087     {
3088
3089         case INS_cmp:
3090         case INS_cmn:
3091         case INS_tst:
3092         case INS_teq:
3093             return false;
3094
3095         default:
3096             return true;
3097     }
3098 }
3099 #endif // _TARGET_ARM_
3100
3101 /*****************************************************************************
3102  *
3103  *  Get the machine dependent instruction for performing sign/zero extension.
3104  *
3105  *  Parameters
3106  *      srcType   - source type
3107  *      srcInReg  - whether source is in a register
3108  */
3109 instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
3110 {
3111     instruction ins = INS_invalid;
3112
3113     if (varTypeIsSIMD(srcType))
3114     {
3115 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3116         // SSE2/AVX requires destination to be a reg always.
3117         // If src is in reg means, it is a reg-reg move.
3118         //
3119         // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3120         // former doesn't require 66h prefix and one byte smaller than the
3121         // latter.
3122         //
3123         // TODO-CQ: based on whether src type is aligned use movaps instead
3124
3125         return (srcInReg) ? INS_movaps : INS_movups;
3126 #elif defined(_TARGET_ARM64_)
3127         return (srcInReg) ? INS_mov : ins_Load(srcType);
3128 #else  // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3129         assert(!"unhandled SIMD type");
3130 #endif // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3131     }
3132
3133 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3134     if (varTypeIsFloating(srcType))
3135     {
3136         if (srcType == TYP_DOUBLE)
3137         {
3138             return (srcInReg) ? INS_movaps : INS_movsdsse2;
3139         }
3140         else if (srcType == TYP_FLOAT)
3141         {
3142             return (srcInReg) ? INS_movaps : INS_movss;
3143         }
3144         else
3145         {
3146             assert(!"unhandled floating type");
3147         }
3148     }
3149 #elif defined(_TARGET_ARM_)
3150     if (varTypeIsFloating(srcType))
3151         return INS_vmov;
3152 #else
3153     assert(!varTypeIsFloating(srcType));
3154 #endif
3155
3156 #if defined(_TARGET_XARCH_)
3157     if (!varTypeIsSmall(srcType))
3158     {
3159         ins = INS_mov;
3160     }
3161     else if (varTypeIsUnsigned(srcType))
3162     {
3163         ins = INS_movzx;
3164     }
3165     else
3166     {
3167         ins = INS_movsx;
3168     }
3169 #elif defined(_TARGET_ARM_)
3170     //
3171     // Register to Register zero/sign extend operation
3172     //
3173     if (srcInReg)
3174     {
3175         if (!varTypeIsSmall(srcType))
3176         {
3177             ins = INS_mov;
3178         }
3179         else if (varTypeIsUnsigned(srcType))
3180         {
3181             if (varTypeIsByte(srcType))
3182                 ins = INS_uxtb;
3183             else
3184                 ins = INS_uxth;
3185         }
3186         else
3187         {
3188             if (varTypeIsByte(srcType))
3189                 ins = INS_sxtb;
3190             else
3191                 ins = INS_sxth;
3192         }
3193     }
3194     else
3195     {
3196         ins = ins_Load(srcType);
3197     }
3198 #elif defined(_TARGET_ARM64_)
3199     //
3200     // Register to Register zero/sign extend operation
3201     //
3202     if (srcInReg)
3203     {
3204         if (varTypeIsUnsigned(srcType))
3205         {
3206             if (varTypeIsByte(srcType))
3207             {
3208                 ins = INS_uxtb;
3209             }
3210             else if (varTypeIsShort(srcType))
3211             {
3212                 ins = INS_uxth;
3213             }
3214             else
3215             {
3216                 // A mov Rd, Rm instruction performs the zero extend
3217                 // for the upper 32 bits when the size is EA_4BYTE
3218
3219                 ins = INS_mov;
3220             }
3221         }
3222         else
3223         {
3224             if (varTypeIsByte(srcType))
3225             {
3226                 ins = INS_sxtb;
3227             }
3228             else if (varTypeIsShort(srcType))
3229             {
3230                 ins = INS_sxth;
3231             }
3232             else
3233             {
3234                 if (srcType == TYP_INT)
3235                 {
3236                     ins = INS_sxtw;
3237                 }
3238                 else
3239                 {
3240                     ins = INS_mov;
3241                 }
3242             }
3243         }
3244     }
3245     else
3246     {
3247         ins = ins_Load(srcType);
3248     }
3249 #else
3250     NYI("ins_Move_Extend");
3251 #endif
3252     assert(ins != INS_invalid);
3253     return ins;
3254 }
3255
3256 /*****************************************************************************
3257  *
3258  *  Get the machine dependent instruction for performing a load for srcType
3259  *
3260  *  Parameters
3261  *      srcType   - source type
3262  *      aligned   - whether source is properly aligned if srcType is a SIMD type
3263  */
3264 instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false*/)
3265 {
3266     instruction ins = INS_invalid;
3267
3268     if (varTypeIsSIMD(srcType))
3269     {
3270 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3271 #ifdef FEATURE_SIMD
3272         if (srcType == TYP_SIMD8)
3273         {
3274             return INS_movsdsse2;
3275         }
3276         else
3277 #endif // FEATURE_SIMD
3278             if (compiler->canUseVexEncoding())
3279         {
3280             return (aligned) ? INS_movapd : INS_movupd;
3281         }
3282         else
3283         {
3284             // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3285             // former doesn't require 66h prefix and one byte smaller than the
3286             // latter.
3287             return (aligned) ? INS_movaps : INS_movups;
3288         }
3289 #elif defined(_TARGET_ARM64_)
3290         return INS_ldr;
3291 #else
3292         assert(!"ins_Load with SIMD type");
3293 #endif
3294     }
3295
3296     if (varTypeIsFloating(srcType))
3297     {
3298 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3299         if (srcType == TYP_DOUBLE)
3300         {
3301             return INS_movsdsse2;
3302         }
3303         else if (srcType == TYP_FLOAT)
3304         {
3305             return INS_movss;
3306         }
3307         else
3308         {
3309             assert(!"unhandled floating type");
3310         }
3311 #elif defined(_TARGET_ARM64_)
3312         return INS_ldr;
3313 #elif defined(_TARGET_ARM_)
3314         return INS_vldr;
3315 #else
3316         assert(!varTypeIsFloating(srcType));
3317 #endif
3318     }
3319
3320 #if defined(_TARGET_XARCH_)
3321     if (!varTypeIsSmall(srcType))
3322     {
3323         ins = INS_mov;
3324     }
3325     else if (varTypeIsUnsigned(srcType))
3326     {
3327         ins = INS_movzx;
3328     }
3329     else
3330     {
3331         ins = INS_movsx;
3332     }
3333
3334 #elif defined(_TARGET_ARMARCH_)
3335     if (!varTypeIsSmall(srcType))
3336     {
3337 #if defined(_TARGET_ARM64_)
3338         if (!varTypeIsI(srcType) && !varTypeIsUnsigned(srcType))
3339         {
3340             ins = INS_ldrsw;
3341         }
3342         else
3343 #endif // defined(_TARGET_ARM64_)
3344         {
3345             ins = INS_ldr;
3346         }
3347     }
3348     else if (varTypeIsByte(srcType))
3349     {
3350         if (varTypeIsUnsigned(srcType))
3351             ins = INS_ldrb;
3352         else
3353             ins = INS_ldrsb;
3354     }
3355     else if (varTypeIsShort(srcType))
3356     {
3357         if (varTypeIsUnsigned(srcType))
3358             ins = INS_ldrh;
3359         else
3360             ins = INS_ldrsh;
3361     }
3362 #else
3363     NYI("ins_Load");
3364 #endif
3365
3366     assert(ins != INS_invalid);
3367     return ins;
3368 }
3369
3370 /*****************************************************************************
3371  *
3372  *  Get the machine dependent instruction for performing a reg-reg copy for dstType
3373  *
3374  *  Parameters
3375  *      dstType   - destination type
3376  */
3377 instruction CodeGen::ins_Copy(var_types dstType)
3378 {
3379 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3380     if (varTypeIsSIMD(dstType))
3381     {
3382         return INS_movaps;
3383     }
3384     else if (varTypeIsFloating(dstType))
3385     {
3386         // Both float and double copy can use movaps
3387         return INS_movaps;
3388     }
3389     else
3390     {
3391         return INS_mov;
3392     }
3393 #elif defined(_TARGET_ARM64_)
3394     if (varTypeIsFloating(dstType))
3395     {
3396         return INS_fmov;
3397     }
3398     else
3399     {
3400         return INS_mov;
3401     }
3402 #elif defined(_TARGET_ARM_)
3403     assert(!varTypeIsSIMD(dstType));
3404     if (varTypeIsFloating(dstType))
3405     {
3406         return INS_vmov;
3407     }
3408     else
3409     {
3410         return INS_mov;
3411     }
3412 #elif defined(_TARGET_X86_)
3413     assert(!varTypeIsSIMD(dstType));
3414     assert(!varTypeIsFloating(dstType));
3415     return INS_mov;
3416 #else // _TARGET_*
3417 #error "Unknown _TARGET_"
3418 #endif
3419 }
3420
3421 /*****************************************************************************
3422  *
3423  *  Get the machine dependent instruction for performing a store for dstType
3424  *
3425  *  Parameters
3426  *      dstType   - destination type
3427  *      aligned   - whether destination is properly aligned if dstType is a SIMD type
3428  */
3429 instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false*/)
3430 {
3431     instruction ins = INS_invalid;
3432
3433 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3434     if (varTypeIsSIMD(dstType))
3435     {
3436 #ifdef FEATURE_SIMD
3437         if (dstType == TYP_SIMD8)
3438         {
3439             return INS_movsdsse2;
3440         }
3441         else
3442 #endif // FEATURE_SIMD
3443             if (compiler->canUseVexEncoding())
3444         {
3445             return (aligned) ? INS_movapd : INS_movupd;
3446         }
3447         else
3448         {
3449             // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3450             // former doesn't require 66h prefix and one byte smaller than the
3451             // latter.
3452             return (aligned) ? INS_movaps : INS_movups;
3453         }
3454     }
3455     else if (varTypeIsFloating(dstType))
3456     {
3457         if (dstType == TYP_DOUBLE)
3458         {
3459             return INS_movsdsse2;
3460         }
3461         else if (dstType == TYP_FLOAT)
3462         {
3463             return INS_movss;
3464         }
3465         else
3466         {
3467             assert(!"unhandled floating type");
3468         }
3469     }
3470 #elif defined(_TARGET_ARM64_)
3471     if (varTypeIsSIMD(dstType) || varTypeIsFloating(dstType))
3472     {
3473         // All sizes of SIMD and FP instructions use INS_str
3474         return INS_str;
3475     }
3476 #elif defined(_TARGET_ARM_)
3477     assert(!varTypeIsSIMD(dstType));
3478     if (varTypeIsFloating(dstType))
3479     {
3480         return INS_vstr;
3481     }
3482 #else
3483     assert(!varTypeIsSIMD(dstType));
3484     assert(!varTypeIsFloating(dstType));
3485 #endif
3486
3487 #if defined(_TARGET_XARCH_)
3488     ins = INS_mov;
3489 #elif defined(_TARGET_ARMARCH_)
3490     if (!varTypeIsSmall(dstType))
3491         ins = INS_str;
3492     else if (varTypeIsByte(dstType))
3493         ins = INS_strb;
3494     else if (varTypeIsShort(dstType))
3495         ins = INS_strh;
3496 #else
3497     NYI("ins_Store");
3498 #endif
3499
3500     assert(ins != INS_invalid);
3501     return ins;
3502 }
3503
3504 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3505
3506 bool CodeGen::isMoveIns(instruction ins)
3507 {
3508     return (ins == INS_mov);
3509 }
3510
3511 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3512 {
3513     // Do Not use this routine in RyuJIT backend. Instead use ins_Load()/ins_Store()
3514     unreached();
3515 }
3516
3517 // everything is just an addressing mode variation on x64
3518 instruction CodeGen::ins_FloatStore(var_types type)
3519 {
3520     // Do Not use this routine in RyuJIT backend. Instead use ins_Store()
3521     unreached();
3522 }
3523
3524 instruction CodeGen::ins_FloatCopy(var_types type)
3525 {
3526     // Do Not use this routine in RyuJIT backend. Instead use ins_Load().
3527     unreached();
3528 }
3529
3530 instruction CodeGen::ins_FloatCompare(var_types type)
3531 {
3532     return (type == TYP_FLOAT) ? INS_ucomiss : INS_ucomisd;
3533 }
3534
3535 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3536 {
3537     // On SSE2/AVX - the same instruction is used for moving double/quad word to XMM/YMM register.
3538     assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3539
3540 #if !defined(_TARGET_64BIT_)
3541     // No 64-bit registers on x86.
3542     assert((srcType != TYP_LONG) && (srcType != TYP_ULONG));
3543 #endif // !defined(_TARGET_64BIT_)
3544
3545     return INS_mov_i2xmm;
3546 }
3547
3548 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3549 {
3550     // On SSE2/AVX - the same instruction is used for moving double/quad word of XMM/YMM to an integer register.
3551     assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3552
3553 #if !defined(_TARGET_64BIT_)
3554     // No 64-bit registers on x86.
3555     assert((dstType != TYP_LONG) && (dstType != TYP_ULONG));
3556 #endif // !defined(_TARGET_64BIT_)
3557
3558     return INS_mov_xmm2i;
3559 }
3560
3561 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3562 {
3563     switch (oper)
3564     {
3565         case GT_ADD:
3566 #ifdef LEGACY_BACKEND
3567         case GT_ASG_ADD:
3568 #endif
3569             return type == TYP_DOUBLE ? INS_addsd : INS_addss;
3570         case GT_SUB:
3571 #ifdef LEGACY_BACKEND
3572         case GT_ASG_SUB:
3573 #endif
3574             return type == TYP_DOUBLE ? INS_subsd : INS_subss;
3575         case GT_MUL:
3576 #ifdef LEGACY_BACKEND
3577         case GT_ASG_MUL:
3578 #endif
3579             return type == TYP_DOUBLE ? INS_mulsd : INS_mulss;
3580         case GT_DIV:
3581 #ifdef LEGACY_BACKEND
3582         case GT_ASG_DIV:
3583 #endif
3584             return type == TYP_DOUBLE ? INS_divsd : INS_divss;
3585         case GT_AND:
3586             return type == TYP_DOUBLE ? INS_andpd : INS_andps;
3587         case GT_OR:
3588             return type == TYP_DOUBLE ? INS_orpd : INS_orps;
3589         case GT_XOR:
3590             return type == TYP_DOUBLE ? INS_xorpd : INS_xorps;
3591         default:
3592             unreached();
3593     }
3594 }
3595
3596 instruction CodeGen::ins_FloatSqrt(var_types type)
3597 {
3598     instruction ins = INS_invalid;
3599
3600     if (type == TYP_DOUBLE)
3601     {
3602         ins = INS_sqrtsd;
3603     }
3604     else if (type == TYP_FLOAT)
3605     {
3606         ins = INS_sqrtss;
3607     }
3608     else
3609     {
3610         assert(!"ins_FloatSqrt: Unsupported type");
3611         unreached();
3612     }
3613
3614     return ins;
3615 }
3616
3617 // Conversions to or from floating point values
3618 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3619 {
3620     // AVX: For now we support only conversion from Int/Long -> float
3621
3622     switch (from)
3623     {
3624         // int/long -> float/double use the same instruction but type size would be different.
3625         case TYP_INT:
3626         case TYP_LONG:
3627             switch (to)
3628             {
3629                 case TYP_FLOAT:
3630                     return INS_cvtsi2ss;
3631                 case TYP_DOUBLE:
3632                     return INS_cvtsi2sd;
3633                 default:
3634                     unreached();
3635             }
3636             break;
3637
3638         case TYP_FLOAT:
3639             switch (to)
3640             {
3641                 case TYP_INT:
3642                     return INS_cvttss2si;
3643                 case TYP_LONG:
3644                     return INS_cvttss2si;
3645                 case TYP_FLOAT:
3646                     return ins_Move_Extend(TYP_FLOAT, false);
3647                 case TYP_DOUBLE:
3648                     return INS_cvtss2sd;
3649                 default:
3650                     unreached();
3651             }
3652             break;
3653
3654         case TYP_DOUBLE:
3655             switch (to)
3656             {
3657                 case TYP_INT:
3658                     return INS_cvttsd2si;
3659                 case TYP_LONG:
3660                     return INS_cvttsd2si;
3661                 case TYP_FLOAT:
3662                     return INS_cvtsd2ss;
3663                 case TYP_DOUBLE:
3664                     return ins_Move_Extend(TYP_DOUBLE, false);
3665                 default:
3666                     unreached();
3667             }
3668             break;
3669
3670         default:
3671             unreached();
3672     }
3673 }
3674
3675 #elif defined(_TARGET_ARM_)
3676
3677 bool CodeGen::isMoveIns(instruction ins)
3678 {
3679     return (ins == INS_vmov) || (ins == INS_mov);
3680 }
3681
3682 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3683 {
3684     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3685     return INS_vldr;
3686 }
3687 instruction CodeGen::ins_FloatStore(var_types type)
3688 {
3689     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3690     return INS_vstr;
3691 }
3692 instruction CodeGen::ins_FloatCopy(var_types type)
3693 {
3694     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3695     return INS_vmov;
3696 }
3697
3698 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3699 {
3700     assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
3701     assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3702
3703     if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
3704     {
3705         return INS_vmov_i2d;
3706     }
3707     else
3708     {
3709         return INS_vmov_i2f;
3710     }
3711 }
3712
3713 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3714 {
3715     assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
3716     assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3717
3718     if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
3719     {
3720         return INS_vmov_d2i;
3721     }
3722     else
3723     {
3724         return INS_vmov_f2i;
3725     }
3726 }
3727
3728 instruction CodeGen::ins_FloatCompare(var_types type)
3729 {
3730     // Not used and not implemented
3731     unreached();
3732 }
3733
3734 instruction CodeGen::ins_FloatSqrt(var_types type)
3735 {
3736     // Not used and not implemented
3737     unreached();
3738 }
3739
3740 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3741 {
3742     switch (oper)
3743     {
3744         case GT_ADD:
3745 #ifdef LEGACY_BACKEND
3746         case GT_ASG_ADD:
3747 #endif
3748             return INS_vadd;
3749         case GT_SUB:
3750 #ifdef LEGACY_BACKEND
3751         case GT_ASG_SUB:
3752 #endif
3753             return INS_vsub;
3754         case GT_MUL:
3755 #ifdef LEGACY_BACKEND
3756         case GT_ASG_MUL:
3757 #endif
3758             return INS_vmul;
3759             break;
3760         case GT_DIV:
3761 #ifdef LEGACY_BACKEND
3762         case GT_ASG_DIV:
3763 #endif
3764             return INS_vdiv;
3765         case GT_NEG:
3766             return INS_vneg;
3767         default:
3768             unreached();
3769     }
3770 }
3771
3772 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3773 {
3774     switch (from)
3775     {
3776         case TYP_INT:
3777             switch (to)
3778             {
3779                 case TYP_FLOAT:
3780                     return INS_vcvt_i2f;
3781                 case TYP_DOUBLE:
3782                     return INS_vcvt_i2d;
3783                 default:
3784                     unreached();
3785             }
3786             break;
3787         case TYP_UINT:
3788             switch (to)
3789             {
3790                 case TYP_FLOAT:
3791                     return INS_vcvt_u2f;
3792                 case TYP_DOUBLE:
3793                     return INS_vcvt_u2d;
3794                 default:
3795                     unreached();
3796             }
3797             break;
3798         case TYP_LONG:
3799             switch (to)
3800             {
3801                 case TYP_FLOAT:
3802                     NYI("long to float");
3803                 case TYP_DOUBLE:
3804                     NYI("long to double");
3805                 default:
3806                     unreached();
3807             }
3808             break;
3809         case TYP_FLOAT:
3810             switch (to)
3811             {
3812                 case TYP_INT:
3813                     return INS_vcvt_f2i;
3814                 case TYP_UINT:
3815                     return INS_vcvt_f2u;
3816                 case TYP_LONG:
3817                     NYI("float to long");
3818                 case TYP_DOUBLE:
3819                     return INS_vcvt_f2d;
3820                 case TYP_FLOAT:
3821                     return INS_vmov;
3822                 default:
3823                     unreached();
3824             }
3825             break;
3826         case TYP_DOUBLE:
3827             switch (to)
3828             {
3829                 case TYP_INT:
3830                     return INS_vcvt_d2i;
3831                 case TYP_UINT:
3832                     return INS_vcvt_d2u;
3833                 case TYP_LONG:
3834                     NYI("double to long");
3835                 case TYP_FLOAT:
3836                     return INS_vcvt_d2f;
3837                 case TYP_DOUBLE:
3838                     return INS_vmov;
3839                 default:
3840                     unreached();
3841             }
3842             break;
3843         default:
3844             unreached();
3845     }
3846 }
3847
3848 #endif // #elif defined(_TARGET_ARM_)
3849
3850 /*****************************************************************************
3851  *
3852  *  Machine independent way to return
3853  */
3854 void CodeGen::instGen_Return(unsigned stkArgSize)
3855 {
3856 #if defined(_TARGET_XARCH_)
3857     if (stkArgSize == 0)
3858     {
3859         instGen(INS_ret);
3860     }
3861     else
3862     {
3863         inst_IV(INS_ret, stkArgSize);
3864     }
3865 #elif defined(_TARGET_ARM_)
3866 //
3867 // The return on ARM is folded into the pop multiple instruction
3868 // and as we do not know the exact set of registers that we will
3869 // need to restore (pop) when we first call instGen_Return we will
3870 // instead just not emit anything for this method on the ARM
3871 // The return will be part of the pop multiple and that will be
3872 // part of the epilog that is generated by genFnEpilog()
3873 #elif defined(_TARGET_ARM64_)
3874     // This function shouldn't be used on ARM64.
3875     unreached();
3876 #else
3877     NYI("instGen_Return");
3878 #endif
3879 }
3880
3881 /*****************************************************************************
3882  *
3883  *  Emit a MemoryBarrier instruction
3884  *
3885  *     Note: all MemoryBarriers instructions can be removed by
3886  *           SET COMPlus_JitNoMemoryBarriers=1
3887  */
3888 #ifdef _TARGET_ARM64_
3889 void CodeGen::instGen_MemoryBarrier(insBarrier barrierType)
3890 #else
3891 void CodeGen::instGen_MemoryBarrier()
3892 #endif
3893 {
3894 #ifdef DEBUG
3895     if (JitConfig.JitNoMemoryBarriers() == 1)
3896     {
3897         return;
3898     }
3899 #endif // DEBUG
3900
3901 #if defined(_TARGET_XARCH_)
3902     instGen(INS_lock);
3903     getEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
3904 #elif defined(_TARGET_ARM_)
3905     getEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf);
3906 #elif defined(_TARGET_ARM64_)
3907     getEmitter()->emitIns_BARR(INS_dmb, barrierType);
3908 #else
3909 #error "Unknown _TARGET_"
3910 #endif
3911 }
3912
3913 /*****************************************************************************
3914  *
3915  *  Machine independent way to move a Zero value into a register
3916  */
3917 void CodeGen::instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags)
3918 {
3919 #if defined(_TARGET_XARCH_)
3920     getEmitter()->emitIns_R_R(INS_xor, size, reg, reg);
3921 #elif defined(_TARGET_ARMARCH_)
3922     getEmitter()->emitIns_R_I(INS_mov, size, reg, 0 ARM_ARG(flags));
3923 #else
3924 #error "Unknown _TARGET_"
3925 #endif
3926     regTracker.rsTrackRegIntCns(reg, 0);
3927 }
3928
3929 #ifdef LEGACY_BACKEND
3930 /*****************************************************************************
3931  *
3932  *  Machine independent way to move an immediate value into a register
3933  */
3934 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
3935 {
3936     if (!compiler->opts.compReloc)
3937     {
3938         size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
3939     }
3940
3941     if ((imm == 0) && !EA_IS_RELOC(size))
3942     {
3943         instGen_Set_Reg_To_Zero(size, reg, flags);
3944     }
3945     else
3946     {
3947 #if defined(_TARGET_XARCH_)
3948         getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
3949 #elif defined(_TARGET_ARM_)
3950
3951         if (EA_IS_RELOC(size))
3952         {
3953             genMov32RelocatableImmediate(size, imm, reg);
3954         }
3955         else if (arm_Valid_Imm_For_Mov(imm))
3956         {
3957             getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
3958         }
3959         else // We have to use a movw/movt pair of instructions
3960         {
3961             ssize_t imm_lo16 = (imm & 0xffff);
3962             ssize_t imm_hi16 = (imm >> 16) & 0xffff;
3963
3964             assert(arm_Valid_Imm_For_Mov(imm_lo16));
3965             assert(imm_hi16 != 0);
3966
3967             getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
3968
3969             // If we've got a low register, the high word is all bits set,
3970             // and the high bit of the low word is set, we can sign extend
3971             // halfword and save two bytes of encoding. This can happen for
3972             // small magnitude negative numbers 'n' for -32768 <= n <= -1.
3973
3974             if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
3975             {
3976                 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
3977             }
3978             else
3979             {
3980                 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
3981             }
3982
3983             if (flags == INS_FLAGS_SET)
3984                 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
3985         }
3986 #elif defined(_TARGET_ARM64_)
3987         NYI_ARM64("instGen_Set_Reg_To_Imm");
3988 #else
3989 #error "Unknown _TARGET_"
3990 #endif
3991     }
3992     regTracker.rsTrackRegIntCns(reg, imm);
3993 }
3994 #endif // LEGACY_BACKEND
3995
3996 /*****************************************************************************
3997  *
3998  *  Machine independent way to set the flags based on
3999  *   comparing a register with zero
4000  */
4001 void CodeGen::instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg)
4002 {
4003 #if defined(_TARGET_XARCH_)
4004     getEmitter()->emitIns_R_R(INS_test, size, reg, reg);
4005 #elif defined(_TARGET_ARMARCH_)
4006     getEmitter()->emitIns_R_I(INS_cmp, size, reg, 0);
4007 #else
4008 #error "Unknown _TARGET_"
4009 #endif
4010 }
4011
4012 /*****************************************************************************
4013  *
4014  *  Machine independent way to set the flags based upon
4015  *   comparing a register with another register
4016  */
4017 void CodeGen::instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2)
4018 {
4019 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARMARCH_)
4020     getEmitter()->emitIns_R_R(INS_cmp, size, reg1, reg2);
4021 #else
4022 #error "Unknown _TARGET_"
4023 #endif
4024 }
4025
4026 /*****************************************************************************
4027  *
4028  *  Machine independent way to set the flags based upon
4029  *   comparing a register with an immediate
4030  */
4031 void CodeGen::instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm)
4032 {
4033     if (imm == 0)
4034     {
4035         instGen_Compare_Reg_To_Zero(size, reg);
4036     }
4037     else
4038     {
4039 #if defined(_TARGET_XARCH_)
4040 #if defined(_TARGET_AMD64_)
4041         if ((EA_SIZE(size) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(size)))
4042         {
4043 #ifndef LEGACY_BACKEND
4044             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4045 #else  // LEGACY_BACKEND
4046             // Load imm into a register
4047             regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4048             instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4049             getEmitter()->emitIns_R_R(INS_cmp, EA_TYPE(size), reg, immReg);
4050 #endif // LEGACY_BACKEND
4051         }
4052         else
4053 #endif // _TARGET_AMD64_
4054         {
4055             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4056         }
4057 #elif defined(_TARGET_ARM_)
4058         if (arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4059         {
4060             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4061         }
4062         else // We need a scratch register
4063         {
4064 #ifndef LEGACY_BACKEND
4065             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4066 #else  // LEGACY_BACKEND
4067             // Load imm into a register
4068             regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4069             instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4070             getEmitter()->emitIns_R_R(INS_cmp, size, reg, immReg);
4071 #endif // !LEGACY_BACKEND
4072         }
4073 #elif defined(_TARGET_ARM64_)
4074         if (true) // TODO-ARM64-NYI: arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4075         {
4076             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4077         }
4078         else // We need a scratch register
4079         {
4080             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4081         }
4082 #else
4083 #error "Unknown _TARGET_"
4084 #endif
4085     }
4086 }
4087
4088 /*****************************************************************************
4089  *
4090  *  Machine independent way to move a stack based local variable into a register
4091  */
4092 void CodeGen::instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs)
4093 {
4094     emitAttr size = emitTypeSize(srcType);
4095
4096     getEmitter()->emitIns_R_S(ins_Load(srcType), size, dstReg, varNum, offs);
4097 }
4098
4099 /*****************************************************************************
4100  *
4101  *  Machine independent way to move a register into a stack based local variable
4102  */
4103 void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs)
4104 {
4105     emitAttr size = emitTypeSize(dstType);
4106
4107     getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs);
4108 }
4109
4110 /*****************************************************************************
4111  *
4112  *  Machine independent way to move an immediate into a stack based local variable
4113  */
4114 void CodeGen::instGen_Store_Imm_Into_Lcl(
4115     var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse)
4116 {
4117 #ifdef _TARGET_XARCH_
4118 #ifdef _TARGET_AMD64_
4119     if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr)))
4120     {
4121         assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl");
4122     }
4123     else
4124 #endif // _TARGET_AMD64_
4125     {
4126         getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm);
4127     }
4128 #elif defined(_TARGET_ARMARCH_)
4129     // Load imm into a register
4130     CLANG_FORMAT_COMMENT_ANCHOR;
4131
4132 #ifndef LEGACY_BACKEND
4133     regNumber immReg = regToUse;
4134     assert(regToUse != REG_NA);
4135 #else  // LEGACY_BACKEND
4136     regNumber immReg = (regToUse == REG_NA) ? regSet.rsGrabReg(RBM_ALLINT) : regToUse;
4137 #endif // LEGACY_BACKEND
4138     instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm);
4139     instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs);
4140     if (EA_IS_RELOC(sizeAttr))
4141     {
4142         regTracker.rsTrackRegTrash(immReg);
4143     }
4144 #else  // _TARGET_*
4145 #error "Unknown _TARGET_"
4146 #endif // _TARGET_*
4147 }
4148
4149 /*****************************************************************************/
4150 /*****************************************************************************/
4151 /*****************************************************************************/