Merge pull request #14946 from MichalStrehovsky/master-merge
[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 < sizeof(insNames) / sizeof(insNames[0]));
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 < sizeof(instInfo) / sizeof(instInfo[0]));
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(GenTreePtr 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(GenTreePtr 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         GenTreePtr       base = lea->Base();
659         assert(!base || (base->InReg()));
660         GenTreePtr 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         GenTreePtr rv1 = NULL;
674         GenTreePtr 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                        GenTreePtr  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                        GenTreePtr  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     GenTreePtr 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             GenTreePtr rv1 = nullptr;
1384             GenTreePtr 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, GenTreePtr tree, GenTreePtr 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, GenTreePtr 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, GenTreePtr 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             GenTreePtr 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, GenTreePtr 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             GenTreePtr 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, GenTreePtr 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             GenTreePtr 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, GenTreePtr 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     GenTreePtr 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, GenTreePtr 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                          GenTreePtr  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             GenTreePtr 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, GenTreePtr 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, GenTreePtr 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, GenTreePtr 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 #else  // !_TARGET_XARCH_
2756     assert(ins == INS_shld || ins == INS_shrd);
2757 #endif // !_TARGET_XARCH_
2758
2759     getEmitter()->emitIns_R_R_I(ins, size, reg1, reg2, ival);
2760 }
2761 #endif
2762
2763 /*****************************************************************************
2764  *
2765  *  Generate an instruction with two registers, the second one being a byte
2766  *  or word register (i.e. this is something like "movzx eax, cl").
2767  */
2768
2769 void CodeGen::inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2)
2770 {
2771     assert(size == EA_1BYTE || size == EA_2BYTE);
2772 #ifdef _TARGET_XARCH_
2773     assert(ins == INS_movsx || ins == INS_movzx);
2774     assert(size != EA_1BYTE || (genRegMask(reg2) & RBM_BYTE_REGS));
2775 #endif
2776
2777     getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
2778 }
2779
2780 /*****************************************************************************
2781  *
2782  *  The following should all end up inline in compiler.hpp at some point.
2783  */
2784
2785 void CodeGen::inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type)
2786 {
2787     getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, tmp->tdTempNum(), ofs);
2788 }
2789
2790 void CodeGen::inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type)
2791 {
2792     getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), tmp->tdTempNum(), ofs, val);
2793 }
2794
2795 #if FEATURE_FIXED_OUT_ARGS
2796 /*****************************************************************************
2797  *
2798  *  Generate an instruction that references the outgoing argument space
2799  *  like "str r3, [sp+0x04]"
2800  */
2801
2802 void CodeGen::inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type)
2803 {
2804     assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2805
2806     getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, compiler->lvaOutgoingArgSpaceVar, ofs);
2807 }
2808
2809 void CodeGen::inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type)
2810 {
2811     assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2812
2813     getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), compiler->lvaOutgoingArgSpaceVar, ofs, val);
2814 }
2815 #endif // FEATURE_FIXED_OUT_ARGS
2816
2817 /*****************************************************************************
2818  *
2819  *  Generate an instruction with one register and one operand that is byte
2820  *  or short (e.g. something like "movzx eax, byte ptr [edx]").
2821  */
2822
2823 void CodeGen::inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree)
2824 {
2825     assert(size == EA_1BYTE || size == EA_2BYTE);
2826
2827 #ifdef LEGACY_BACKEND
2828     if (tree->InReg())
2829     {
2830         /* "movsx erx, rl" must be handled as a special case */
2831         inst_RV_RR(ins, size, reg, tree->gtRegNum);
2832     }
2833     else
2834 #endif // LEGACY_BACKEND
2835     {
2836         inst_RV_TT(ins, reg, tree, 0, size);
2837     }
2838 }
2839
2840 void CodeGen::inst_RV_ST(instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size)
2841 {
2842     if (size == EA_UNKNOWN)
2843     {
2844         size = emitActualTypeSize(type);
2845     }
2846
2847 #ifdef _TARGET_ARM_
2848     switch (ins)
2849     {
2850         case INS_mov:
2851             assert(!"Please call ins_Load(type) to get the load instruction");
2852             break;
2853
2854         case INS_add:
2855         case INS_ldr:
2856         case INS_ldrh:
2857         case INS_ldrb:
2858         case INS_ldrsh:
2859         case INS_ldrsb:
2860         case INS_lea:
2861         case INS_vldr:
2862             getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2863             break;
2864
2865         default:
2866 #ifndef LEGACY_BACKEND
2867             assert(!"Default inst_RV_ST case not supported for Arm !LEGACY_BACKEND");
2868 #else  // LEGACY_BACKEND
2869             regNumber regTmp;
2870             if (varTypeIsFloating(type))
2871             {
2872                 regTmp = regSet.PickRegFloat(type);
2873             }
2874             else
2875             {
2876                 regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2877             }
2878             getEmitter()->emitIns_R_S(ins_Load(type), size, regTmp, tmp->tdTempNum(), ofs);
2879             regTracker.rsTrackRegTrash(regTmp);
2880             getEmitter()->emitIns_R_R(ins, size, reg, regTmp);
2881 #endif // LEGACY_BACKEND
2882             break;
2883     }
2884 #else  // !_TARGET_ARM_
2885     getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2886 #endif // !_TARGET_ARM_
2887 }
2888
2889 void CodeGen::inst_mov_RV_ST(regNumber reg, GenTreePtr tree)
2890 {
2891     /* Figure out the size of the value being loaded */
2892
2893     emitAttr size = EA_ATTR(genTypeSize(tree->gtType));
2894 #ifdef LEGACY_BACKEND
2895     instruction loadIns = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2896 #else  // !LEGACY_BACKEND
2897     instruction loadIns = ins_Move_Extend(tree->TypeGet(), false);
2898 #endif // !LEGACY_BACKEND
2899
2900     if (size < EA_4BYTE)
2901     {
2902 #if CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2903         if ((tree->gtFlags & GTF_SMALL_OK) && (size == EA_1BYTE) && (genRegMask(reg) & RBM_BYTE_REGS))
2904         {
2905             /* We only need to load the actual size */
2906
2907             inst_RV_TT(INS_mov, reg, tree, 0, EA_1BYTE);
2908         }
2909         else
2910 #endif // CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2911         {
2912             /* Generate the "movsx/movzx" opcode */
2913
2914             inst_RV_ST(loadIns, size, reg, tree);
2915         }
2916     }
2917     else
2918     {
2919         /* Compute op1 into the target register */
2920
2921         inst_RV_TT(loadIns, reg, tree);
2922     }
2923 }
2924 #ifdef _TARGET_XARCH_
2925 void CodeGen::inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs)
2926 {
2927     getEmitter()->emitIns_S(ins, size, tmp->tdTempNum(), ofs);
2928 }
2929 #endif
2930
2931 #ifdef _TARGET_ARM_
2932 bool CodeGenInterface::validImmForInstr(instruction ins, ssize_t imm, insFlags flags)
2933 {
2934     if (getEmitter()->emitInsIsLoadOrStore(ins) && !instIsFP(ins))
2935     {
2936         return validDispForLdSt(imm, TYP_INT);
2937     }
2938
2939     bool result = false;
2940     switch (ins)
2941     {
2942         case INS_cmp:
2943         case INS_cmn:
2944             if (validImmForAlu(imm) || validImmForAlu(-imm))
2945                 result = true;
2946             break;
2947
2948         case INS_and:
2949         case INS_bic:
2950         case INS_orr:
2951         case INS_orn:
2952         case INS_mvn:
2953             if (validImmForAlu(imm) || validImmForAlu(~imm))
2954                 result = true;
2955             break;
2956
2957         case INS_mov:
2958             if (validImmForMov(imm))
2959                 result = true;
2960             break;
2961
2962         case INS_addw:
2963         case INS_subw:
2964             if ((unsigned_abs(imm) <= 0x00000fff) && (flags != INS_FLAGS_SET)) // 12-bit immediate
2965                 result = true;
2966             break;
2967
2968         case INS_add:
2969         case INS_sub:
2970             if (validImmForAdd(imm, flags))
2971                 result = true;
2972             break;
2973
2974         case INS_tst:
2975         case INS_eor:
2976         case INS_teq:
2977         case INS_adc:
2978         case INS_sbc:
2979         case INS_rsb:
2980             if (validImmForAlu(imm))
2981                 result = true;
2982             break;
2983
2984         case INS_asr:
2985         case INS_lsl:
2986         case INS_lsr:
2987         case INS_ror:
2988             if (imm > 0 && imm <= 32)
2989                 result = true;
2990             break;
2991
2992         case INS_vstr:
2993         case INS_vldr:
2994             if ((imm & 0x3FC) == imm)
2995                 result = true;
2996             break;
2997
2998         default:
2999             break;
3000     }
3001     return result;
3002 }
3003 bool CodeGen::arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags)
3004 {
3005     return validImmForInstr(ins, imm, flags);
3006 }
3007
3008 bool CodeGenInterface::validDispForLdSt(ssize_t disp, var_types type)
3009 {
3010     if (varTypeIsFloating(type))
3011     {
3012         if ((disp & 0x3FC) == disp)
3013             return true;
3014         else
3015             return false;
3016     }
3017     else
3018     {
3019         if ((disp >= -0x00ff) && (disp <= 0x0fff))
3020             return true;
3021         else
3022             return false;
3023     }
3024 }
3025 bool CodeGen::arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type)
3026 {
3027     return validDispForLdSt(disp, type);
3028 }
3029
3030 bool CodeGenInterface::validImmForAlu(ssize_t imm)
3031 {
3032     return emitter::emitIns_valid_imm_for_alu(imm);
3033 }
3034 bool CodeGen::arm_Valid_Imm_For_Alu(ssize_t imm)
3035 {
3036     return validImmForAlu(imm);
3037 }
3038
3039 bool CodeGenInterface::validImmForMov(ssize_t imm)
3040 {
3041     return emitter::emitIns_valid_imm_for_mov(imm);
3042 }
3043 bool CodeGen::arm_Valid_Imm_For_Mov(ssize_t imm)
3044 {
3045     return validImmForMov(imm);
3046 }
3047
3048 bool CodeGen::arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags)
3049 {
3050     return emitter::emitIns_valid_imm_for_small_mov(reg, imm, flags);
3051 }
3052
3053 bool CodeGenInterface::validImmForAdd(ssize_t imm, insFlags flags)
3054 {
3055     return emitter::emitIns_valid_imm_for_add(imm, flags);
3056 }
3057 bool CodeGen::arm_Valid_Imm_For_Add(ssize_t imm, insFlags flags)
3058 {
3059     return emitter::emitIns_valid_imm_for_add(imm, flags);
3060 }
3061
3062 // Check "add Rd,SP,i10"
3063 bool CodeGen::arm_Valid_Imm_For_Add_SP(ssize_t imm)
3064 {
3065     return emitter::emitIns_valid_imm_for_add_sp(imm);
3066 }
3067
3068 bool CodeGenInterface::validImmForBL(ssize_t addr)
3069 {
3070     return
3071         // If we are running the altjit for NGEN, then assume we can use the "BL" instruction.
3072         // This matches the usual behavior for NGEN, since we normally do generate "BL".
3073         (!compiler->info.compMatchedVM && compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) ||
3074         (compiler->eeGetRelocTypeHint((void*)addr) == IMAGE_REL_BASED_THUMB_BRANCH24);
3075 }
3076 bool CodeGen::arm_Valid_Imm_For_BL(ssize_t addr)
3077 {
3078     return validImmForBL(addr);
3079 }
3080
3081 // Returns true if this instruction writes to a destination register
3082 //
3083 bool CodeGen::ins_Writes_Dest(instruction ins)
3084 {
3085     switch (ins)
3086     {
3087
3088         case INS_cmp:
3089         case INS_cmn:
3090         case INS_tst:
3091         case INS_teq:
3092             return false;
3093
3094         default:
3095             return true;
3096     }
3097 }
3098 #endif // _TARGET_ARM_
3099
3100 /*****************************************************************************
3101  *
3102  *  Get the machine dependent instruction for performing sign/zero extension.
3103  *
3104  *  Parameters
3105  *      srcType   - source type
3106  *      srcInReg  - whether source is in a register
3107  */
3108 instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
3109 {
3110     instruction ins = INS_invalid;
3111
3112     if (varTypeIsSIMD(srcType))
3113     {
3114 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3115         // SSE2/AVX requires destination to be a reg always.
3116         // If src is in reg means, it is a reg-reg move.
3117         //
3118         // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3119         // former doesn't require 66h prefix and one byte smaller than the
3120         // latter.
3121         //
3122         // TODO-CQ: based on whether src type is aligned use movaps instead
3123
3124         return (srcInReg) ? INS_movaps : INS_movups;
3125 #elif defined(_TARGET_ARM64_)
3126         return (srcInReg) ? INS_mov : ins_Load(srcType);
3127 #else  // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3128         assert(!"unhandled SIMD type");
3129 #endif // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3130     }
3131
3132 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3133     if (varTypeIsFloating(srcType))
3134     {
3135         if (srcType == TYP_DOUBLE)
3136         {
3137             return (srcInReg) ? INS_movaps : INS_movsdsse2;
3138         }
3139         else if (srcType == TYP_FLOAT)
3140         {
3141             return (srcInReg) ? INS_movaps : INS_movss;
3142         }
3143         else
3144         {
3145             assert(!"unhandled floating type");
3146         }
3147     }
3148 #elif defined(_TARGET_ARM_)
3149     if (varTypeIsFloating(srcType))
3150         return INS_vmov;
3151 #else
3152     assert(!varTypeIsFloating(srcType));
3153 #endif
3154
3155 #if defined(_TARGET_XARCH_)
3156     if (!varTypeIsSmall(srcType))
3157     {
3158         ins = INS_mov;
3159     }
3160     else if (varTypeIsUnsigned(srcType))
3161     {
3162         ins = INS_movzx;
3163     }
3164     else
3165     {
3166         ins = INS_movsx;
3167     }
3168 #elif defined(_TARGET_ARM_)
3169     //
3170     // Register to Register zero/sign extend operation
3171     //
3172     if (srcInReg)
3173     {
3174         if (!varTypeIsSmall(srcType))
3175         {
3176             ins = INS_mov;
3177         }
3178         else if (varTypeIsUnsigned(srcType))
3179         {
3180             if (varTypeIsByte(srcType))
3181                 ins = INS_uxtb;
3182             else
3183                 ins = INS_uxth;
3184         }
3185         else
3186         {
3187             if (varTypeIsByte(srcType))
3188                 ins = INS_sxtb;
3189             else
3190                 ins = INS_sxth;
3191         }
3192     }
3193     else
3194     {
3195         ins = ins_Load(srcType);
3196     }
3197 #elif defined(_TARGET_ARM64_)
3198     //
3199     // Register to Register zero/sign extend operation
3200     //
3201     if (srcInReg)
3202     {
3203         if (varTypeIsUnsigned(srcType))
3204         {
3205             if (varTypeIsByte(srcType))
3206             {
3207                 ins = INS_uxtb;
3208             }
3209             else if (varTypeIsShort(srcType))
3210             {
3211                 ins = INS_uxth;
3212             }
3213             else
3214             {
3215                 // A mov Rd, Rm instruction performs the zero extend
3216                 // for the upper 32 bits when the size is EA_4BYTE
3217
3218                 ins = INS_mov;
3219             }
3220         }
3221         else
3222         {
3223             if (varTypeIsByte(srcType))
3224             {
3225                 ins = INS_sxtb;
3226             }
3227             else if (varTypeIsShort(srcType))
3228             {
3229                 ins = INS_sxth;
3230             }
3231             else
3232             {
3233                 if (srcType == TYP_INT)
3234                 {
3235                     ins = INS_sxtw;
3236                 }
3237                 else
3238                 {
3239                     ins = INS_mov;
3240                 }
3241             }
3242         }
3243     }
3244     else
3245     {
3246         ins = ins_Load(srcType);
3247     }
3248 #else
3249     NYI("ins_Move_Extend");
3250 #endif
3251     assert(ins != INS_invalid);
3252     return ins;
3253 }
3254
3255 /*****************************************************************************
3256  *
3257  *  Get the machine dependent instruction for performing a load for srcType
3258  *
3259  *  Parameters
3260  *      srcType   - source type
3261  *      aligned   - whether source is properly aligned if srcType is a SIMD type
3262  */
3263 instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false*/)
3264 {
3265     instruction ins = INS_invalid;
3266
3267     if (varTypeIsSIMD(srcType))
3268     {
3269 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3270 #ifdef FEATURE_SIMD
3271         if (srcType == TYP_SIMD8)
3272         {
3273             return INS_movsdsse2;
3274         }
3275         else
3276 #endif // FEATURE_SIMD
3277             if (compiler->canUseAVX())
3278         {
3279             return (aligned) ? INS_movapd : INS_movupd;
3280         }
3281         else
3282         {
3283             // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3284             // former doesn't require 66h prefix and one byte smaller than the
3285             // latter.
3286             return (aligned) ? INS_movaps : INS_movups;
3287         }
3288 #elif defined(_TARGET_ARM64_)
3289         return INS_ldr;
3290 #else
3291         assert(!"ins_Load with SIMD type");
3292 #endif
3293     }
3294
3295     if (varTypeIsFloating(srcType))
3296     {
3297 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3298         if (srcType == TYP_DOUBLE)
3299         {
3300             return INS_movsdsse2;
3301         }
3302         else if (srcType == TYP_FLOAT)
3303         {
3304             return INS_movss;
3305         }
3306         else
3307         {
3308             assert(!"unhandled floating type");
3309         }
3310 #elif defined(_TARGET_ARM64_)
3311         return INS_ldr;
3312 #elif defined(_TARGET_ARM_)
3313         return INS_vldr;
3314 #else
3315         assert(!varTypeIsFloating(srcType));
3316 #endif
3317     }
3318
3319 #if defined(_TARGET_XARCH_)
3320     if (!varTypeIsSmall(srcType))
3321     {
3322         ins = INS_mov;
3323     }
3324     else if (varTypeIsUnsigned(srcType))
3325     {
3326         ins = INS_movzx;
3327     }
3328     else
3329     {
3330         ins = INS_movsx;
3331     }
3332
3333 #elif defined(_TARGET_ARMARCH_)
3334     if (!varTypeIsSmall(srcType))
3335     {
3336 #if defined(_TARGET_ARM64_)
3337         if (!varTypeIsI(srcType) && !varTypeIsUnsigned(srcType))
3338         {
3339             ins = INS_ldrsw;
3340         }
3341         else
3342 #endif // defined(_TARGET_ARM64_)
3343         {
3344             ins = INS_ldr;
3345         }
3346     }
3347     else if (varTypeIsByte(srcType))
3348     {
3349         if (varTypeIsUnsigned(srcType))
3350             ins = INS_ldrb;
3351         else
3352             ins = INS_ldrsb;
3353     }
3354     else if (varTypeIsShort(srcType))
3355     {
3356         if (varTypeIsUnsigned(srcType))
3357             ins = INS_ldrh;
3358         else
3359             ins = INS_ldrsh;
3360     }
3361 #else
3362     NYI("ins_Load");
3363 #endif
3364
3365     assert(ins != INS_invalid);
3366     return ins;
3367 }
3368
3369 /*****************************************************************************
3370  *
3371  *  Get the machine dependent instruction for performing a reg-reg copy for dstType
3372  *
3373  *  Parameters
3374  *      dstType   - destination type
3375  */
3376 instruction CodeGen::ins_Copy(var_types dstType)
3377 {
3378 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3379     if (varTypeIsSIMD(dstType))
3380     {
3381         return INS_movaps;
3382     }
3383     else if (varTypeIsFloating(dstType))
3384     {
3385         // Both float and double copy can use movaps
3386         return INS_movaps;
3387     }
3388     else
3389     {
3390         return INS_mov;
3391     }
3392 #elif defined(_TARGET_ARM64_)
3393     if (varTypeIsFloating(dstType))
3394     {
3395         return INS_fmov;
3396     }
3397     else
3398     {
3399         return INS_mov;
3400     }
3401 #elif defined(_TARGET_ARM_)
3402     assert(!varTypeIsSIMD(dstType));
3403     if (varTypeIsFloating(dstType))
3404     {
3405         return INS_vmov;
3406     }
3407     else
3408     {
3409         return INS_mov;
3410     }
3411 #elif defined(_TARGET_X86_)
3412     assert(!varTypeIsSIMD(dstType));
3413     assert(!varTypeIsFloating(dstType));
3414     return INS_mov;
3415 #else // _TARGET_*
3416 #error "Unknown _TARGET_"
3417 #endif
3418 }
3419
3420 /*****************************************************************************
3421  *
3422  *  Get the machine dependent instruction for performing a store for dstType
3423  *
3424  *  Parameters
3425  *      dstType   - destination type
3426  *      aligned   - whether destination is properly aligned if dstType is a SIMD type
3427  */
3428 instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false*/)
3429 {
3430     instruction ins = INS_invalid;
3431
3432 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3433     if (varTypeIsSIMD(dstType))
3434     {
3435 #ifdef FEATURE_SIMD
3436         if (dstType == TYP_SIMD8)
3437         {
3438             return INS_movsdsse2;
3439         }
3440         else
3441 #endif // FEATURE_SIMD
3442             if (compiler->canUseAVX())
3443         {
3444             return (aligned) ? INS_movapd : INS_movupd;
3445         }
3446         else
3447         {
3448             // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3449             // former doesn't require 66h prefix and one byte smaller than the
3450             // latter.
3451             return (aligned) ? INS_movaps : INS_movups;
3452         }
3453     }
3454     else if (varTypeIsFloating(dstType))
3455     {
3456         if (dstType == TYP_DOUBLE)
3457         {
3458             return INS_movsdsse2;
3459         }
3460         else if (dstType == TYP_FLOAT)
3461         {
3462             return INS_movss;
3463         }
3464         else
3465         {
3466             assert(!"unhandled floating type");
3467         }
3468     }
3469 #elif defined(_TARGET_ARM64_)
3470     if (varTypeIsSIMD(dstType) || varTypeIsFloating(dstType))
3471     {
3472         // All sizes of SIMD and FP instructions use INS_str
3473         return INS_str;
3474     }
3475 #elif defined(_TARGET_ARM_)
3476     assert(!varTypeIsSIMD(dstType));
3477     if (varTypeIsFloating(dstType))
3478     {
3479         return INS_vstr;
3480     }
3481 #else
3482     assert(!varTypeIsSIMD(dstType));
3483     assert(!varTypeIsFloating(dstType));
3484 #endif
3485
3486 #if defined(_TARGET_XARCH_)
3487     ins = INS_mov;
3488 #elif defined(_TARGET_ARMARCH_)
3489     if (!varTypeIsSmall(dstType))
3490         ins = INS_str;
3491     else if (varTypeIsByte(dstType))
3492         ins = INS_strb;
3493     else if (varTypeIsShort(dstType))
3494         ins = INS_strh;
3495 #else
3496     NYI("ins_Store");
3497 #endif
3498
3499     assert(ins != INS_invalid);
3500     return ins;
3501 }
3502
3503 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3504
3505 bool CodeGen::isMoveIns(instruction ins)
3506 {
3507     return (ins == INS_mov);
3508 }
3509
3510 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3511 {
3512     // Do Not use this routine in RyuJIT backend. Instead use ins_Load()/ins_Store()
3513     unreached();
3514 }
3515
3516 // everything is just an addressing mode variation on x64
3517 instruction CodeGen::ins_FloatStore(var_types type)
3518 {
3519     // Do Not use this routine in RyuJIT backend. Instead use ins_Store()
3520     unreached();
3521 }
3522
3523 instruction CodeGen::ins_FloatCopy(var_types type)
3524 {
3525     // Do Not use this routine in RyuJIT backend. Instead use ins_Load().
3526     unreached();
3527 }
3528
3529 instruction CodeGen::ins_FloatCompare(var_types type)
3530 {
3531     return (type == TYP_FLOAT) ? INS_ucomiss : INS_ucomisd;
3532 }
3533
3534 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3535 {
3536     // On SSE2/AVX - the same instruction is used for moving double/quad word to XMM/YMM register.
3537     assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3538
3539 #if !defined(_TARGET_64BIT_)
3540     // No 64-bit registers on x86.
3541     assert((srcType != TYP_LONG) && (srcType != TYP_ULONG));
3542 #endif // !defined(_TARGET_64BIT_)
3543
3544     return INS_mov_i2xmm;
3545 }
3546
3547 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3548 {
3549     // On SSE2/AVX - the same instruction is used for moving double/quad word of XMM/YMM to an integer register.
3550     assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3551
3552 #if !defined(_TARGET_64BIT_)
3553     // No 64-bit registers on x86.
3554     assert((dstType != TYP_LONG) && (dstType != TYP_ULONG));
3555 #endif // !defined(_TARGET_64BIT_)
3556
3557     return INS_mov_xmm2i;
3558 }
3559
3560 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3561 {
3562     switch (oper)
3563     {
3564         case GT_ADD:
3565 #ifdef LEGACY_BACKEND
3566         case GT_ASG_ADD:
3567 #endif
3568             return type == TYP_DOUBLE ? INS_addsd : INS_addss;
3569         case GT_SUB:
3570 #ifdef LEGACY_BACKEND
3571         case GT_ASG_SUB:
3572 #endif
3573             return type == TYP_DOUBLE ? INS_subsd : INS_subss;
3574         case GT_MUL:
3575 #ifdef LEGACY_BACKEND
3576         case GT_ASG_MUL:
3577 #endif
3578             return type == TYP_DOUBLE ? INS_mulsd : INS_mulss;
3579         case GT_DIV:
3580 #ifdef LEGACY_BACKEND
3581         case GT_ASG_DIV:
3582 #endif
3583             return type == TYP_DOUBLE ? INS_divsd : INS_divss;
3584         case GT_AND:
3585             return type == TYP_DOUBLE ? INS_andpd : INS_andps;
3586         case GT_OR:
3587             return type == TYP_DOUBLE ? INS_orpd : INS_orps;
3588         case GT_XOR:
3589             return type == TYP_DOUBLE ? INS_xorpd : INS_xorps;
3590         default:
3591             unreached();
3592     }
3593 }
3594
3595 instruction CodeGen::ins_FloatSqrt(var_types type)
3596 {
3597     instruction ins = INS_invalid;
3598
3599     if (type == TYP_DOUBLE)
3600     {
3601         ins = INS_sqrtsd;
3602     }
3603     else if (type == TYP_FLOAT)
3604     {
3605         ins = INS_sqrtss;
3606     }
3607     else
3608     {
3609         assert(!"ins_FloatSqrt: Unsupported type");
3610         unreached();
3611     }
3612
3613     return ins;
3614 }
3615
3616 // Conversions to or from floating point values
3617 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3618 {
3619     // AVX: For now we support only conversion from Int/Long -> float
3620
3621     switch (from)
3622     {
3623         // int/long -> float/double use the same instruction but type size would be different.
3624         case TYP_INT:
3625         case TYP_LONG:
3626             switch (to)
3627             {
3628                 case TYP_FLOAT:
3629                     return INS_cvtsi2ss;
3630                 case TYP_DOUBLE:
3631                     return INS_cvtsi2sd;
3632                 default:
3633                     unreached();
3634             }
3635             break;
3636
3637         case TYP_FLOAT:
3638             switch (to)
3639             {
3640                 case TYP_INT:
3641                     return INS_cvttss2si;
3642                 case TYP_LONG:
3643                     return INS_cvttss2si;
3644                 case TYP_FLOAT:
3645                     return ins_Move_Extend(TYP_FLOAT, false);
3646                 case TYP_DOUBLE:
3647                     return INS_cvtss2sd;
3648                 default:
3649                     unreached();
3650             }
3651             break;
3652
3653         case TYP_DOUBLE:
3654             switch (to)
3655             {
3656                 case TYP_INT:
3657                     return INS_cvttsd2si;
3658                 case TYP_LONG:
3659                     return INS_cvttsd2si;
3660                 case TYP_FLOAT:
3661                     return INS_cvtsd2ss;
3662                 case TYP_DOUBLE:
3663                     return ins_Move_Extend(TYP_DOUBLE, false);
3664                 default:
3665                     unreached();
3666             }
3667             break;
3668
3669         default:
3670             unreached();
3671     }
3672 }
3673
3674 #elif defined(_TARGET_ARM_)
3675
3676 bool CodeGen::isMoveIns(instruction ins)
3677 {
3678     return (ins == INS_vmov) || (ins == INS_mov);
3679 }
3680
3681 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3682 {
3683     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3684     return INS_vldr;
3685 }
3686 instruction CodeGen::ins_FloatStore(var_types type)
3687 {
3688     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3689     return INS_vstr;
3690 }
3691 instruction CodeGen::ins_FloatCopy(var_types type)
3692 {
3693     assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3694     return INS_vmov;
3695 }
3696
3697 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3698 {
3699     assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
3700     assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3701
3702     if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
3703     {
3704         return INS_vmov_i2d;
3705     }
3706     else
3707     {
3708         return INS_vmov_i2f;
3709     }
3710 }
3711
3712 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3713 {
3714     assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
3715     assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3716
3717     if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
3718     {
3719         return INS_vmov_d2i;
3720     }
3721     else
3722     {
3723         return INS_vmov_f2i;
3724     }
3725 }
3726
3727 instruction CodeGen::ins_FloatCompare(var_types type)
3728 {
3729     // Not used and not implemented
3730     unreached();
3731 }
3732
3733 instruction CodeGen::ins_FloatSqrt(var_types type)
3734 {
3735     // Not used and not implemented
3736     unreached();
3737 }
3738
3739 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3740 {
3741     switch (oper)
3742     {
3743         case GT_ADD:
3744 #ifdef LEGACY_BACKEND
3745         case GT_ASG_ADD:
3746 #endif
3747             return INS_vadd;
3748         case GT_SUB:
3749 #ifdef LEGACY_BACKEND
3750         case GT_ASG_SUB:
3751 #endif
3752             return INS_vsub;
3753         case GT_MUL:
3754 #ifdef LEGACY_BACKEND
3755         case GT_ASG_MUL:
3756 #endif
3757             return INS_vmul;
3758             break;
3759         case GT_DIV:
3760 #ifdef LEGACY_BACKEND
3761         case GT_ASG_DIV:
3762 #endif
3763             return INS_vdiv;
3764         case GT_NEG:
3765             return INS_vneg;
3766         default:
3767             unreached();
3768     }
3769 }
3770
3771 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3772 {
3773     switch (from)
3774     {
3775         case TYP_INT:
3776             switch (to)
3777             {
3778                 case TYP_FLOAT:
3779                     return INS_vcvt_i2f;
3780                 case TYP_DOUBLE:
3781                     return INS_vcvt_i2d;
3782                 default:
3783                     unreached();
3784             }
3785             break;
3786         case TYP_UINT:
3787             switch (to)
3788             {
3789                 case TYP_FLOAT:
3790                     return INS_vcvt_u2f;
3791                 case TYP_DOUBLE:
3792                     return INS_vcvt_u2d;
3793                 default:
3794                     unreached();
3795             }
3796             break;
3797         case TYP_LONG:
3798             switch (to)
3799             {
3800                 case TYP_FLOAT:
3801                     NYI("long to float");
3802                 case TYP_DOUBLE:
3803                     NYI("long to double");
3804                 default:
3805                     unreached();
3806             }
3807             break;
3808         case TYP_FLOAT:
3809             switch (to)
3810             {
3811                 case TYP_INT:
3812                     return INS_vcvt_f2i;
3813                 case TYP_UINT:
3814                     return INS_vcvt_f2u;
3815                 case TYP_LONG:
3816                     NYI("float to long");
3817                 case TYP_DOUBLE:
3818                     return INS_vcvt_f2d;
3819                 case TYP_FLOAT:
3820                     return INS_vmov;
3821                 default:
3822                     unreached();
3823             }
3824             break;
3825         case TYP_DOUBLE:
3826             switch (to)
3827             {
3828                 case TYP_INT:
3829                     return INS_vcvt_d2i;
3830                 case TYP_UINT:
3831                     return INS_vcvt_d2u;
3832                 case TYP_LONG:
3833                     NYI("double to long");
3834                 case TYP_FLOAT:
3835                     return INS_vcvt_d2f;
3836                 case TYP_DOUBLE:
3837                     return INS_vmov;
3838                 default:
3839                     unreached();
3840             }
3841             break;
3842         default:
3843             unreached();
3844     }
3845 }
3846
3847 #endif // #elif defined(_TARGET_ARM_)
3848
3849 /*****************************************************************************
3850  *
3851  *  Machine independent way to return
3852  */
3853 void CodeGen::instGen_Return(unsigned stkArgSize)
3854 {
3855 #if defined(_TARGET_XARCH_)
3856     if (stkArgSize == 0)
3857     {
3858         instGen(INS_ret);
3859     }
3860     else
3861     {
3862         inst_IV(INS_ret, stkArgSize);
3863     }
3864 #elif defined(_TARGET_ARM_)
3865 //
3866 // The return on ARM is folded into the pop multiple instruction
3867 // and as we do not know the exact set of registers that we will
3868 // need to restore (pop) when we first call instGen_Return we will
3869 // instead just not emit anything for this method on the ARM
3870 // The return will be part of the pop multiple and that will be
3871 // part of the epilog that is generated by genFnEpilog()
3872 #elif defined(_TARGET_ARM64_)
3873     // This function shouldn't be used on ARM64.
3874     unreached();
3875 #else
3876     NYI("instGen_Return");
3877 #endif
3878 }
3879
3880 /*****************************************************************************
3881  *
3882  *  Emit a MemoryBarrier instruction
3883  *
3884  *     Note: all MemoryBarriers instructions can be removed by
3885  *           SET COMPlus_JitNoMemoryBarriers=1
3886  */
3887 #ifdef _TARGET_ARM64_
3888 void CodeGen::instGen_MemoryBarrier(insBarrier barrierType)
3889 #else
3890 void CodeGen::instGen_MemoryBarrier()
3891 #endif
3892 {
3893 #ifdef DEBUG
3894     if (JitConfig.JitNoMemoryBarriers() == 1)
3895     {
3896         return;
3897     }
3898 #endif // DEBUG
3899
3900 #if defined(_TARGET_XARCH_)
3901     instGen(INS_lock);
3902     getEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
3903 #elif defined(_TARGET_ARM_)
3904     getEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf);
3905 #elif defined(_TARGET_ARM64_)
3906     getEmitter()->emitIns_BARR(INS_dmb, barrierType);
3907 #else
3908 #error "Unknown _TARGET_"
3909 #endif
3910 }
3911
3912 /*****************************************************************************
3913  *
3914  *  Machine independent way to move a Zero value into a register
3915  */
3916 void CodeGen::instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags)
3917 {
3918 #if defined(_TARGET_XARCH_)
3919     getEmitter()->emitIns_R_R(INS_xor, size, reg, reg);
3920 #elif defined(_TARGET_ARMARCH_)
3921     getEmitter()->emitIns_R_I(INS_mov, size, reg, 0 ARM_ARG(flags));
3922 #else
3923 #error "Unknown _TARGET_"
3924 #endif
3925     regTracker.rsTrackRegIntCns(reg, 0);
3926 }
3927
3928 #ifdef LEGACY_BACKEND
3929 /*****************************************************************************
3930  *
3931  *  Machine independent way to move an immediate value into a register
3932  */
3933 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
3934 {
3935     if (!compiler->opts.compReloc)
3936     {
3937         size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
3938     }
3939
3940     if ((imm == 0) && !EA_IS_RELOC(size))
3941     {
3942         instGen_Set_Reg_To_Zero(size, reg, flags);
3943     }
3944     else
3945     {
3946 #if defined(_TARGET_XARCH_)
3947         getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
3948 #elif defined(_TARGET_ARM_)
3949
3950         if (EA_IS_RELOC(size))
3951         {
3952             genMov32RelocatableImmediate(size, imm, reg);
3953         }
3954         else if (arm_Valid_Imm_For_Mov(imm))
3955         {
3956             getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
3957         }
3958         else // We have to use a movw/movt pair of instructions
3959         {
3960             ssize_t imm_lo16 = (imm & 0xffff);
3961             ssize_t imm_hi16 = (imm >> 16) & 0xffff;
3962
3963             assert(arm_Valid_Imm_For_Mov(imm_lo16));
3964             assert(imm_hi16 != 0);
3965
3966             getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
3967
3968             // If we've got a low register, the high word is all bits set,
3969             // and the high bit of the low word is set, we can sign extend
3970             // halfword and save two bytes of encoding. This can happen for
3971             // small magnitude negative numbers 'n' for -32768 <= n <= -1.
3972
3973             if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
3974             {
3975                 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
3976             }
3977             else
3978             {
3979                 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
3980             }
3981
3982             if (flags == INS_FLAGS_SET)
3983                 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
3984         }
3985 #elif defined(_TARGET_ARM64_)
3986         NYI_ARM64("instGen_Set_Reg_To_Imm");
3987 #else
3988 #error "Unknown _TARGET_"
3989 #endif
3990     }
3991     regTracker.rsTrackRegIntCns(reg, imm);
3992 }
3993 #endif // LEGACY_BACKEND
3994
3995 /*****************************************************************************
3996  *
3997  *  Machine independent way to set the flags based on
3998  *   comparing a register with zero
3999  */
4000 void CodeGen::instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg)
4001 {
4002 #if defined(_TARGET_XARCH_)
4003     getEmitter()->emitIns_R_R(INS_test, size, reg, reg);
4004 #elif defined(_TARGET_ARMARCH_)
4005     getEmitter()->emitIns_R_I(INS_cmp, size, reg, 0);
4006 #else
4007 #error "Unknown _TARGET_"
4008 #endif
4009 }
4010
4011 /*****************************************************************************
4012  *
4013  *  Machine independent way to set the flags based upon
4014  *   comparing a register with another register
4015  */
4016 void CodeGen::instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2)
4017 {
4018 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARMARCH_)
4019     getEmitter()->emitIns_R_R(INS_cmp, size, reg1, reg2);
4020 #else
4021 #error "Unknown _TARGET_"
4022 #endif
4023 }
4024
4025 /*****************************************************************************
4026  *
4027  *  Machine independent way to set the flags based upon
4028  *   comparing a register with an immediate
4029  */
4030 void CodeGen::instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm)
4031 {
4032     if (imm == 0)
4033     {
4034         instGen_Compare_Reg_To_Zero(size, reg);
4035     }
4036     else
4037     {
4038 #if defined(_TARGET_XARCH_)
4039 #if defined(_TARGET_AMD64_)
4040         if ((EA_SIZE(size) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(size)))
4041         {
4042 #ifndef LEGACY_BACKEND
4043             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4044 #else  // LEGACY_BACKEND
4045             // Load imm into a register
4046             regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4047             instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4048             getEmitter()->emitIns_R_R(INS_cmp, EA_TYPE(size), reg, immReg);
4049 #endif // LEGACY_BACKEND
4050         }
4051         else
4052 #endif // _TARGET_AMD64_
4053         {
4054             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4055         }
4056 #elif defined(_TARGET_ARM_)
4057         if (arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4058         {
4059             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4060         }
4061         else // We need a scratch register
4062         {
4063 #ifndef LEGACY_BACKEND
4064             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4065 #else  // LEGACY_BACKEND
4066             // Load imm into a register
4067             regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4068             instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4069             getEmitter()->emitIns_R_R(INS_cmp, size, reg, immReg);
4070 #endif // !LEGACY_BACKEND
4071         }
4072 #elif defined(_TARGET_ARM64_)
4073         if (true) // TODO-ARM64-NYI: arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4074         {
4075             getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4076         }
4077         else // We need a scratch register
4078         {
4079             assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4080         }
4081 #else
4082 #error "Unknown _TARGET_"
4083 #endif
4084     }
4085 }
4086
4087 /*****************************************************************************
4088  *
4089  *  Machine independent way to move a stack based local variable into a register
4090  */
4091 void CodeGen::instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs)
4092 {
4093     emitAttr size = emitTypeSize(srcType);
4094
4095     getEmitter()->emitIns_R_S(ins_Load(srcType), size, dstReg, varNum, offs);
4096 }
4097
4098 /*****************************************************************************
4099  *
4100  *  Machine independent way to move a register into a stack based local variable
4101  */
4102 void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs)
4103 {
4104     emitAttr size = emitTypeSize(dstType);
4105
4106     getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs);
4107 }
4108
4109 /*****************************************************************************
4110  *
4111  *  Machine independent way to move an immediate into a stack based local variable
4112  */
4113 void CodeGen::instGen_Store_Imm_Into_Lcl(
4114     var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse)
4115 {
4116 #ifdef _TARGET_XARCH_
4117 #ifdef _TARGET_AMD64_
4118     if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr)))
4119     {
4120         assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl");
4121     }
4122     else
4123 #endif // _TARGET_AMD64_
4124     {
4125         getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm);
4126     }
4127 #elif defined(_TARGET_ARMARCH_)
4128     // Load imm into a register
4129     CLANG_FORMAT_COMMENT_ANCHOR;
4130
4131 #ifndef LEGACY_BACKEND
4132     regNumber immReg = regToUse;
4133     assert(regToUse != REG_NA);
4134 #else  // LEGACY_BACKEND
4135     regNumber immReg = (regToUse == REG_NA) ? regSet.rsGrabReg(RBM_ALLINT) : regToUse;
4136 #endif // LEGACY_BACKEND
4137     instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm);
4138     instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs);
4139     if (EA_IS_RELOC(sizeAttr))
4140     {
4141         regTracker.rsTrackRegTrash(immReg);
4142     }
4143 #else  // _TARGET_*
4144 #error "Unknown _TARGET_"
4145 #endif // _TARGET_*
4146 }
4147
4148 /*****************************************************************************/
4149 /*****************************************************************************/
4150 /*****************************************************************************/