37b9026db1428fecad6461896ad31af71ad8de04
[platform/upstream/coreclr.git] / src / jit / codegenarmarch.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                        ARM/ARM64 Code Generator Common Code               XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13 #include "jitpch.h"
14 #ifdef _MSC_VER
15 #pragma hdrstop
16 #endif
17
18 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
19
20 #ifdef _TARGET_ARMARCH_ // This file is ONLY used for ARM and ARM64 architectures
21
22 #include "codegen.h"
23 #include "lower.h"
24 #include "gcinfo.h"
25 #include "emit.h"
26
27 //------------------------------------------------------------------------
28 // genCodeForTreeNode Generate code for a single node in the tree.
29 //
30 // Preconditions:
31 //    All operands have been evaluated.
32 //
33 void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
34 {
35     regNumber targetReg  = treeNode->gtRegNum;
36     var_types targetType = treeNode->TypeGet();
37     emitter*  emit       = getEmitter();
38
39 #ifdef DEBUG
40     // Validate that all the operands for the current node are consumed in order.
41     // This is important because LSRA ensures that any necessary copies will be
42     // handled correctly.
43     lastConsumedNode = nullptr;
44     if (compiler->verbose)
45     {
46         unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
47         compiler->gtDispLIRNode(treeNode, "Generating: ");
48     }
49 #endif // DEBUG
50
51 #ifdef _TARGET_ARM64_ // TODO-ARM: is this applicable to ARM32?
52     // Is this a node whose value is already in a register?  LSRA denotes this by
53     // setting the GTF_REUSE_REG_VAL flag.
54     if (treeNode->IsReuseRegVal())
55     {
56         // For now, this is only used for constant nodes.
57         assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
58         JITDUMP("  TreeNode is marked ReuseReg\n");
59         return;
60     }
61 #endif // _TARGET_ARM64_
62
63     // contained nodes are part of their parents for codegen purposes
64     // ex : immediates, most LEAs
65     if (treeNode->isContained())
66     {
67         return;
68     }
69
70     switch (treeNode->gtOper)
71     {
72 #ifdef _TARGET_ARM64_
73
74         case GT_START_NONGC:
75             getEmitter()->emitDisableGC();
76             break;
77
78         case GT_PROF_HOOK:
79             // We should be seeing this only if profiler hook is needed
80             noway_assert(compiler->compIsProfilerHookNeeded());
81
82 #ifdef PROFILING_SUPPORTED
83             // Right now this node is used only for tail calls. In future if
84             // we intend to use it for Enter or Leave hooks, add a data member
85             // to this node indicating the kind of profiler hook. For example,
86             // helper number can be used.
87             genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
88 #endif // PROFILING_SUPPORTED
89             break;
90
91 #endif // _TARGET_ARM64_
92
93         case GT_LCLHEAP:
94             genLclHeap(treeNode);
95             break;
96
97         case GT_CNS_INT:
98         case GT_CNS_DBL:
99             genSetRegToConst(targetReg, targetType, treeNode);
100             genProduceReg(treeNode);
101             break;
102
103         case GT_NOT:
104         case GT_NEG:
105             genCodeForNegNot(treeNode);
106             break;
107
108         case GT_MOD:
109         case GT_UMOD:
110         case GT_DIV:
111         case GT_UDIV:
112             genCodeForDivMod(treeNode->AsOp());
113             break;
114
115         case GT_OR:
116         case GT_XOR:
117         case GT_AND:
118             assert(varTypeIsIntegralOrI(treeNode));
119
120             __fallthrough;
121
122 #if !defined(_TARGET_64BIT_)
123         case GT_ADD_LO:
124         case GT_ADD_HI:
125         case GT_SUB_LO:
126         case GT_SUB_HI:
127 #endif // !defined(_TARGET_64BIT_)
128
129         case GT_ADD:
130         case GT_SUB:
131         case GT_MUL:
132             genConsumeOperands(treeNode->AsOp());
133             genCodeForBinary(treeNode);
134             break;
135
136         case GT_LSH:
137         case GT_RSH:
138         case GT_RSZ:
139         // case GT_ROL: // No ROL instruction on ARM; it has been lowered to ROR.
140         case GT_ROR:
141             genCodeForShift(treeNode);
142             break;
143
144 #if !defined(_TARGET_64BIT_)
145
146         case GT_LSH_HI:
147         case GT_RSH_LO:
148             genCodeForShiftLong(treeNode);
149             break;
150
151 #endif // !defined(_TARGET_64BIT_)
152
153         case GT_CAST:
154             genCodeForCast(treeNode->AsOp());
155             break;
156
157         case GT_LCL_FLD_ADDR:
158         case GT_LCL_VAR_ADDR:
159             genCodeForLclAddr(treeNode);
160             break;
161
162         case GT_LCL_FLD:
163             genCodeForLclFld(treeNode->AsLclFld());
164             break;
165
166         case GT_LCL_VAR:
167             genCodeForLclVar(treeNode->AsLclVar());
168             break;
169
170         case GT_STORE_LCL_FLD:
171             genCodeForStoreLclFld(treeNode->AsLclFld());
172             break;
173
174         case GT_STORE_LCL_VAR:
175             genCodeForStoreLclVar(treeNode->AsLclVar());
176             break;
177
178         case GT_RETFILT:
179         case GT_RETURN:
180             genReturn(treeNode);
181             break;
182
183         case GT_LEA:
184             // If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction.
185             genLeaInstruction(treeNode->AsAddrMode());
186             break;
187
188         case GT_IND:
189             genCodeForIndir(treeNode->AsIndir());
190             break;
191
192 #ifdef _TARGET_ARM_
193         case GT_MUL_LONG:
194             genCodeForMulLong(treeNode->AsMulLong());
195             break;
196 #endif // _TARGET_ARM_
197
198 #ifdef _TARGET_ARM64_
199
200         case GT_MULHI:
201             genCodeForMulHi(treeNode->AsOp());
202             break;
203
204         case GT_SWAP:
205             genCodeForSwap(treeNode->AsOp());
206             break;
207 #endif // _TARGET_ARM64_
208
209         case GT_JMP:
210             genJmpMethod(treeNode);
211             break;
212
213         case GT_CKFINITE:
214             genCkfinite(treeNode);
215             break;
216
217         case GT_INTRINSIC:
218             genIntrinsic(treeNode);
219             break;
220
221 #ifdef FEATURE_SIMD
222         case GT_SIMD:
223             genSIMDIntrinsic(treeNode->AsSIMD());
224             break;
225 #endif // FEATURE_SIMD
226
227         case GT_EQ:
228         case GT_NE:
229         case GT_LT:
230         case GT_LE:
231         case GT_GE:
232         case GT_GT:
233             genCodeForCompare(treeNode->AsOp());
234             break;
235
236         case GT_JTRUE:
237             genCodeForJumpTrue(treeNode);
238             break;
239
240 #ifdef _TARGET_ARM_
241
242         case GT_JCC:
243             genCodeForJcc(treeNode->AsCC());
244             break;
245
246 #endif // _TARGET_ARM_
247
248         case GT_RETURNTRAP:
249             genCodeForReturnTrap(treeNode->AsOp());
250             break;
251
252         case GT_STOREIND:
253             genCodeForStoreInd(treeNode->AsStoreInd());
254             break;
255
256         case GT_COPY:
257             // This is handled at the time we call genConsumeReg() on the GT_COPY
258             break;
259
260         case GT_LIST:
261         case GT_FIELD_LIST:
262         case GT_ARGPLACE:
263             // Nothing to do
264             break;
265
266         case GT_PUTARG_STK:
267             genPutArgStk(treeNode->AsPutArgStk());
268             break;
269
270         case GT_PUTARG_REG:
271             genPutArgReg(treeNode->AsOp());
272             break;
273
274         case GT_CALL:
275             genCallInstruction(treeNode->AsCall());
276             break;
277
278         case GT_LOCKADD:
279         case GT_XCHG:
280         case GT_XADD:
281             genLockedInstructions(treeNode->AsOp());
282             break;
283
284         case GT_MEMORYBARRIER:
285             instGen_MemoryBarrier();
286             break;
287
288         case GT_CMPXCHG:
289             NYI("GT_CMPXCHG");
290             break;
291
292         case GT_RELOAD:
293             // do nothing - reload is just a marker.
294             // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
295             // into the register specified in this node.
296             break;
297
298         case GT_NOP:
299             break;
300
301         case GT_NO_OP:
302             instGen(INS_nop);
303             break;
304
305         case GT_ARR_BOUNDS_CHECK:
306 #ifdef FEATURE_SIMD
307         case GT_SIMD_CHK:
308 #endif // FEATURE_SIMD
309             genRangeCheck(treeNode);
310             break;
311
312         case GT_PHYSREG:
313             genCodeForPhysReg(treeNode->AsPhysReg());
314             break;
315
316         case GT_PHYSREGDST:
317             break;
318
319         case GT_NULLCHECK:
320             genCodeForNullCheck(treeNode->AsOp());
321             break;
322
323         case GT_CATCH_ARG:
324
325             noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
326
327             /* Catch arguments get passed in a register. genCodeForBBlist()
328                would have marked it as holding a GC object, but not used. */
329
330             noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
331             genConsumeReg(treeNode);
332             break;
333
334         case GT_PINVOKE_PROLOG:
335             noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
336
337             // the runtime side requires the codegen here to be consistent
338             emit->emitDisableRandomNops();
339             break;
340
341         case GT_LABEL:
342             genPendingCallLabel       = genCreateTempLabel();
343             treeNode->gtLabel.gtLabBB = genPendingCallLabel;
344             emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
345             break;
346
347         case GT_STORE_OBJ:
348         case GT_STORE_DYN_BLK:
349         case GT_STORE_BLK:
350             genCodeForStoreBlk(treeNode->AsBlk());
351             break;
352
353         case GT_JMPTABLE:
354             genJumpTable(treeNode);
355             break;
356
357         case GT_SWITCH_TABLE:
358             genTableBasedSwitch(treeNode);
359             break;
360
361         case GT_ARR_INDEX:
362             genCodeForArrIndex(treeNode->AsArrIndex());
363             break;
364
365         case GT_ARR_OFFSET:
366             genCodeForArrOffset(treeNode->AsArrOffs());
367             break;
368
369 #ifdef _TARGET_ARM_
370
371         case GT_CLS_VAR_ADDR:
372             emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
373             genProduceReg(treeNode);
374             break;
375
376         case GT_LONG:
377             assert(treeNode->isUsedFromReg());
378             genConsumeRegs(treeNode);
379             break;
380
381 #endif // _TARGET_ARM_
382
383         case GT_IL_OFFSET:
384             // Do nothing; these nodes are simply markers for debug info.
385             break;
386
387         default:
388         {
389 #ifdef DEBUG
390             char message[256];
391             _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
392                         GenTree::NodeName(treeNode->OperGet()));
393             NYIRAW(message);
394 #else
395             NYI("unimplemented node");
396 #endif
397         }
398         break;
399     }
400 }
401
402 //------------------------------------------------------------------------
403 // genSetRegToIcon: Generate code that will set the given register to the integer constant.
404 //
405 void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
406 {
407     // Reg cannot be a FP reg
408     assert(!genIsValidFloatReg(reg));
409
410     // The only TYP_REF constant that can come this path is a managed 'null' since it is not
411     // relocatable.  Other ref type constants (e.g. string objects) go through a different
412     // code path.
413     noway_assert(type != TYP_REF || val == 0);
414
415     instGen_Set_Reg_To_Imm(emitActualTypeSize(type), reg, val, flags);
416 }
417
418 //---------------------------------------------------------------------
419 // genIntrinsic - generate code for a given intrinsic
420 //
421 // Arguments
422 //    treeNode - the GT_INTRINSIC node
423 //
424 // Return value:
425 //    None
426 //
427 void CodeGen::genIntrinsic(GenTreePtr treeNode)
428 {
429     assert(treeNode->OperIs(GT_INTRINSIC));
430
431     // Both operand and its result must be of the same floating point type.
432     GenTreePtr srcNode = treeNode->gtOp.gtOp1;
433     assert(varTypeIsFloating(srcNode));
434     assert(srcNode->TypeGet() == treeNode->TypeGet());
435
436     // Right now only Abs/Round/Sqrt are treated as math intrinsics.
437     //
438     switch (treeNode->gtIntrinsic.gtIntrinsicId)
439     {
440         case CORINFO_INTRINSIC_Abs:
441             genConsumeOperands(treeNode->AsOp());
442             getEmitter()->emitInsBinary(INS_ABS, emitTypeSize(treeNode), treeNode, srcNode);
443             break;
444
445         case CORINFO_INTRINSIC_Round:
446             NYI_ARM("genIntrinsic for round - not implemented yet");
447             genConsumeOperands(treeNode->AsOp());
448             getEmitter()->emitInsBinary(INS_ROUND, emitTypeSize(treeNode), treeNode, srcNode);
449             break;
450
451         case CORINFO_INTRINSIC_Sqrt:
452             genConsumeOperands(treeNode->AsOp());
453             getEmitter()->emitInsBinary(INS_SQRT, emitTypeSize(treeNode), treeNode, srcNode);
454             break;
455
456         default:
457             assert(!"genIntrinsic: Unsupported intrinsic");
458             unreached();
459     }
460
461     genProduceReg(treeNode);
462 }
463
464 //---------------------------------------------------------------------
465 // genPutArgStk - generate code for a GT_PUTARG_STK node
466 //
467 // Arguments
468 //    treeNode - the GT_PUTARG_STK node
469 //
470 // Return value:
471 //    None
472 //
473 void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
474 {
475     assert(treeNode->OperIs(GT_PUTARG_STK));
476     var_types  targetType = treeNode->TypeGet();
477     GenTreePtr source     = treeNode->gtOp1;
478     emitter*   emit       = getEmitter();
479
480     // This is the varNum for our store operations,
481     // typically this is the varNum for the Outgoing arg space
482     // When we are generating a tail call it will be the varNum for arg0
483     unsigned varNumOut    = (unsigned)-1;
484     unsigned argOffsetMax = (unsigned)-1; // Records the maximum size of this area for assert checks
485
486     // Get argument offset to use with 'varNumOut'
487     // Here we cross check that argument offset hasn't changed from lowering to codegen since
488     // we are storing arg slot number in GT_PUTARG_STK node in lowering phase.
489     unsigned argOffsetOut = treeNode->gtSlotNum * TARGET_POINTER_SIZE;
490
491 #ifdef DEBUG
492     fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(treeNode->gtCall, treeNode);
493     assert(curArgTabEntry);
494     assert(argOffsetOut == (curArgTabEntry->slotNum * TARGET_POINTER_SIZE));
495 #endif // DEBUG
496
497     // Whether to setup stk arg in incoming or out-going arg area?
498     // Fast tail calls implemented as epilog+jmp = stk arg is setup in incoming arg area.
499     // All other calls - stk arg is setup in out-going arg area.
500     if (treeNode->putInIncomingArgArea())
501     {
502         NYI_ARM("genPutArgStk: fast tail call");
503
504 #ifdef _TARGET_ARM64_
505         varNumOut    = getFirstArgWithStackSlot();
506         argOffsetMax = compiler->compArgSize;
507 #if FEATURE_FASTTAILCALL
508         // This must be a fast tail call.
509         assert(treeNode->gtCall->IsFastTailCall());
510
511         // Since it is a fast tail call, the existence of first incoming arg is guaranteed
512         // because fast tail call requires that in-coming arg area of caller is >= out-going
513         // arg area required for tail call.
514         LclVarDsc* varDsc = &(compiler->lvaTable[varNumOut]);
515         assert(varDsc != nullptr);
516 #endif // FEATURE_FASTTAILCALL
517 #endif // _TARGET_ARM64_
518     }
519     else
520     {
521         varNumOut    = compiler->lvaOutgoingArgSpaceVar;
522         argOffsetMax = compiler->lvaOutgoingArgSpaceSize;
523     }
524
525     bool isStruct = (targetType == TYP_STRUCT) || (source->OperGet() == GT_FIELD_LIST);
526
527     if (!isStruct) // a normal non-Struct argument
528     {
529         instruction storeIns  = ins_Store(targetType);
530         emitAttr    storeAttr = emitTypeSize(targetType);
531
532         // If it is contained then source must be the integer constant zero
533         if (source->isContained())
534         {
535             assert(source->OperGet() == GT_CNS_INT);
536             assert(source->AsIntConCommon()->IconValue() == 0);
537             NYI_ARM("genPutArgStk: contained zero source");
538
539 #ifdef _TARGET_ARM64_
540             emit->emitIns_S_R(storeIns, storeAttr, REG_ZR, varNumOut, argOffsetOut);
541 #endif // _TARGET_ARM64_
542         }
543         else
544         {
545             genConsumeReg(source);
546             emit->emitIns_S_R(storeIns, storeAttr, source->gtRegNum, varNumOut, argOffsetOut);
547         }
548         argOffsetOut += EA_SIZE_IN_BYTES(storeAttr);
549         assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
550     }
551     else // We have some kind of a struct argument
552     {
553         assert(source->isContained()); // We expect that this node was marked as contained in Lower
554
555         if (source->OperGet() == GT_FIELD_LIST)
556         {
557             // Deal with the multi register passed struct args.
558             GenTreeFieldList* fieldListPtr = source->AsFieldList();
559
560             // Evaluate each of the GT_FIELD_LIST items into their register
561             // and store their register into the outgoing argument area
562             for (; fieldListPtr != nullptr; fieldListPtr = fieldListPtr->Rest())
563             {
564                 GenTreePtr nextArgNode = fieldListPtr->gtOp.gtOp1;
565                 genConsumeReg(nextArgNode);
566
567                 regNumber reg  = nextArgNode->gtRegNum;
568                 var_types type = nextArgNode->TypeGet();
569                 emitAttr  attr = emitTypeSize(type);
570
571                 // Emit store instructions to store the registers produced by the GT_FIELD_LIST into the outgoing
572                 // argument area
573                 emit->emitIns_S_R(ins_Store(type), attr, reg, varNumOut, argOffsetOut);
574                 argOffsetOut += EA_SIZE_IN_BYTES(attr);
575                 assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
576             }
577         }
578         else // We must have a GT_OBJ or a GT_LCL_VAR
579         {
580             noway_assert((source->OperGet() == GT_LCL_VAR) || (source->OperGet() == GT_OBJ));
581
582             var_types targetType = source->TypeGet();
583             noway_assert(varTypeIsStruct(targetType));
584
585             // We will copy this struct to the stack, possibly using a ldp/ldr instruction
586             // in ARM64/ARM
587             // Setup loReg (and hiReg) from the internal registers that we reserved in lower.
588             //
589             regNumber loReg = treeNode->ExtractTempReg();
590 #ifdef _TARGET_ARM64_
591             regNumber hiReg = treeNode->GetSingleTempReg();
592 #endif // _TARGET_ARM64_
593             regNumber addrReg = REG_NA;
594
595             GenTreeLclVarCommon* varNode  = nullptr;
596             GenTreePtr           addrNode = nullptr;
597
598             if (source->OperGet() == GT_LCL_VAR)
599             {
600                 varNode = source->AsLclVarCommon();
601             }
602             else // we must have a GT_OBJ
603             {
604                 assert(source->OperGet() == GT_OBJ);
605
606                 addrNode = source->gtOp.gtOp1;
607
608                 // addrNode can either be a GT_LCL_VAR_ADDR or an address expression
609                 //
610                 if (addrNode->OperGet() == GT_LCL_VAR_ADDR)
611                 {
612                     // We have a GT_OBJ(GT_LCL_VAR_ADDR)
613                     //
614                     // We will treat this case the same as above
615                     // (i.e if we just had this GT_LCL_VAR directly as the source)
616                     // so update 'source' to point this GT_LCL_VAR_ADDR node
617                     // and continue to the codegen for the LCL_VAR node below
618                     //
619                     varNode  = addrNode->AsLclVarCommon();
620                     addrNode = nullptr;
621                 }
622             }
623
624             // Either varNode or addrNOde must have been setup above,
625             // the xor ensures that only one of the two is setup, not both
626             assert((varNode != nullptr) ^ (addrNode != nullptr));
627
628             BYTE  gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
629             BYTE* gcPtrs                        = gcPtrArray;
630
631             unsigned gcPtrCount; // The count of GC pointers in the struct
632             int      structSize;
633             bool     isHfa;
634
635             // This is the varNum for our load operations,
636             // only used when we have a multireg struct with a LclVar source
637             unsigned varNumInp = BAD_VAR_NUM;
638
639             // Setup the structSize, isHFa, and gcPtrCount
640             if (varNode != nullptr)
641             {
642                 varNumInp = varNode->gtLclNum;
643                 assert(varNumInp < compiler->lvaCount);
644                 LclVarDsc* varDsc = &compiler->lvaTable[varNumInp];
645
646                 assert(varDsc->lvType == TYP_STRUCT);
647                 assert(varDsc->lvOnFrame);   // This struct also must live in the stack frame
648                 assert(!varDsc->lvRegister); // And it can't live in a register (SIMD)
649
650                 structSize = varDsc->lvSize(); // This yields the roundUp size, but that is fine
651                                                // as that is how much stack is allocated for this LclVar
652                 isHfa = varDsc->lvIsHfa();
653 #ifdef _TARGET_ARM64_
654                 gcPtrCount = varDsc->lvStructGcCount;
655                 for (unsigned i = 0; i < gcPtrCount; ++i)
656                     gcPtrs[i]   = varDsc->lvGcLayout[i];
657 #else // _TARGET_ARM_
658                 gcPtrs     = treeNode->gtGcPtrs;
659                 gcPtrCount = treeNode->gtNumSlots;
660 #endif // _TARGET_ARM_
661             }
662             else // addrNode is used
663             {
664                 assert(addrNode != nullptr);
665
666                 // Generate code to load the address that we need into a register
667                 genConsumeAddress(addrNode);
668                 addrReg = addrNode->gtRegNum;
669
670 #ifdef _TARGET_ARM64_
671                 // If addrReg equal to loReg, swap(loReg, hiReg)
672                 // This reduces code complexity by only supporting one addrReg overwrite case
673                 if (loReg == addrReg)
674                 {
675                     loReg = hiReg;
676                     hiReg = addrReg;
677                 }
678 #endif // _TARGET_ARM64_
679
680                 CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;
681
682                 structSize = compiler->info.compCompHnd->getClassSize(objClass);
683                 isHfa      = compiler->IsHfa(objClass);
684                 gcPtrCount = compiler->info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]);
685             }
686
687             // If we have an HFA we can't have any GC pointers,
688             // if not then the max size for the the struct is 16 bytes
689             if (isHfa)
690             {
691                 noway_assert(gcPtrCount == 0);
692             }
693 #ifdef _TARGET_ARM64_
694             else
695             {
696                 noway_assert(structSize <= 2 * TARGET_POINTER_SIZE);
697             }
698
699             noway_assert(structSize <= MAX_PASS_MULTIREG_BYTES);
700 #endif // _TARGET_ARM64_
701
702             int      remainingSize = structSize;
703             unsigned structOffset  = 0;
704             unsigned nextIndex     = 0;
705
706 #ifdef _TARGET_ARM64_
707             // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop
708             //             ldp     x2, x3, [x0]
709             //             stp     x2, x3, [sp, #16]
710
711             while (remainingSize >= 2 * TARGET_POINTER_SIZE)
712             {
713                 var_types type0 = compiler->getJitGCType(gcPtrs[nextIndex + 0]);
714                 var_types type1 = compiler->getJitGCType(gcPtrs[nextIndex + 1]);
715
716                 if (varNode != nullptr)
717                 {
718                     // Load from our varNumImp source
719                     emit->emitIns_R_R_S_S(INS_ldp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumInp,
720                                           0);
721                 }
722                 else
723                 {
724                     // check for case of destroying the addrRegister while we still need it
725                     assert(loReg != addrReg);
726                     noway_assert((remainingSize == 2 * TARGET_POINTER_SIZE) || (hiReg != addrReg));
727
728                     // Load from our address expression source
729                     emit->emitIns_R_R_R_I(INS_ldp, emitTypeSize(type0), loReg, hiReg, addrReg, structOffset,
730                                           INS_OPTS_NONE, emitTypeSize(type0));
731                 }
732
733                 // Emit stp instruction to store the two registers into the outgoing argument area
734                 emit->emitIns_S_S_R_R(INS_stp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumOut,
735                                       argOffsetOut);
736                 argOffsetOut += (2 * TARGET_POINTER_SIZE); // We stored 16-bytes of the struct
737                 assert(argOffsetOut <= argOffsetMax);      // We can't write beyound the outgoing area area
738
739                 remainingSize -= (2 * TARGET_POINTER_SIZE); // We loaded 16-bytes of the struct
740                 structOffset += (2 * TARGET_POINTER_SIZE);
741                 nextIndex += 2;
742             }
743 #else  // _TARGET_ARM_
744             // For a >= 4 byte structSize we will generate a ldr and str instruction each loop
745             //             ldr     r2, [r0]
746             //             str     r2, [sp, #16]
747             while (remainingSize >= TARGET_POINTER_SIZE)
748             {
749                 var_types type = compiler->getJitGCType(gcPtrs[nextIndex]);
750
751                 if (varNode != nullptr)
752                 {
753                     // Load from our varNumImp source
754                     emit->emitIns_R_S(INS_ldr, emitTypeSize(type), loReg, varNumInp, structOffset);
755                 }
756                 else
757                 {
758                     // check for case of destroying the addrRegister while we still need it
759                     assert(loReg != addrReg || remainingSize == TARGET_POINTER_SIZE);
760
761                     // Load from our address expression source
762                     emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), loReg, addrReg, structOffset);
763                 }
764
765                 // Emit str instruction to store the register into the outgoing argument area
766                 emit->emitIns_S_R(INS_str, emitTypeSize(type), loReg, varNumOut, argOffsetOut);
767                 argOffsetOut += TARGET_POINTER_SIZE;  // We stored 4-bytes of the struct
768                 assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
769
770                 remainingSize -= TARGET_POINTER_SIZE; // We loaded 4-bytes of the struct
771                 structOffset += TARGET_POINTER_SIZE;
772                 nextIndex += 1;
773             }
774 #endif // _TARGET_ARM_
775
776             // For a 12-byte structSize we will we will generate two load instructions
777             //             ldr     x2, [x0]
778             //             ldr     w3, [x0, #8]
779             //             str     x2, [sp, #16]
780             //             str     w3, [sp, #24]
781
782             while (remainingSize > 0)
783             {
784                 if (remainingSize >= TARGET_POINTER_SIZE)
785                 {
786                     var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
787                     emitAttr  nextAttr = emitTypeSize(nextType);
788                     remainingSize -= TARGET_POINTER_SIZE;
789
790                     if (varNode != nullptr)
791                     {
792                         // Load from our varNumImp source
793                         emit->emitIns_R_S(ins_Load(nextType), nextAttr, loReg, varNumInp, structOffset);
794                     }
795                     else
796                     {
797                         assert(loReg != addrReg);
798
799                         // Load from our address expression source
800                         emit->emitIns_R_R_I(ins_Load(nextType), nextAttr, loReg, addrReg, structOffset);
801                     }
802                     // Emit a store instruction to store the register into the outgoing argument area
803                     emit->emitIns_S_R(ins_Store(nextType), nextAttr, loReg, varNumOut, argOffsetOut);
804                     argOffsetOut += EA_SIZE_IN_BYTES(nextAttr);
805                     assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
806
807                     structOffset += TARGET_POINTER_SIZE;
808                     nextIndex++;
809                 }
810                 else // (remainingSize < TARGET_POINTER_SIZE)
811                 {
812                     int loadSize  = remainingSize;
813                     remainingSize = 0;
814
815                     // We should never have to do a non-pointer sized load when we have a LclVar source
816                     assert(varNode == nullptr);
817
818                     // the left over size is smaller than a pointer and thus can never be a GC type
819                     assert(varTypeIsGC(compiler->getJitGCType(gcPtrs[nextIndex])) == false);
820
821                     var_types loadType = TYP_UINT;
822                     if (loadSize == 1)
823                     {
824                         loadType = TYP_UBYTE;
825                     }
826                     else if (loadSize == 2)
827                     {
828                         loadType = TYP_USHORT;
829                     }
830                     else
831                     {
832                         // Need to handle additional loadSize cases here
833                         noway_assert(loadSize == 4);
834                     }
835
836                     instruction loadIns  = ins_Load(loadType);
837                     emitAttr    loadAttr = emitAttr(loadSize);
838
839                     assert(loReg != addrReg);
840
841                     emit->emitIns_R_R_I(loadIns, loadAttr, loReg, addrReg, structOffset);
842
843                     // Emit a store instruction to store the register into the outgoing argument area
844                     emit->emitIns_S_R(ins_Store(loadType), loadAttr, loReg, varNumOut, argOffsetOut);
845                     argOffsetOut += EA_SIZE_IN_BYTES(loadAttr);
846                     assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
847                 }
848             }
849         }
850     }
851 }
852
853 //---------------------------------------------------------------------
854 // genPutArgReg - generate code for a GT_PUTARG_REG node
855 //
856 // Arguments
857 //    tree - the GT_PUTARG_REG node
858 //
859 // Return value:
860 //    None
861 //
862 void CodeGen::genPutArgReg(GenTreeOp* tree)
863 {
864     assert(tree->OperIs(GT_PUTARG_REG));
865
866     var_types targetType = tree->TypeGet();
867     regNumber targetReg  = tree->gtRegNum;
868
869     assert(targetType != TYP_STRUCT);
870
871     GenTree* op1 = tree->gtOp1;
872     genConsumeReg(op1);
873
874     // If child node is not already in the register we need, move it
875     if (targetReg != op1->gtRegNum)
876     {
877         inst_RV_RV(ins_Copy(targetType), targetReg, op1->gtRegNum, targetType);
878     }
879
880     genProduceReg(tree);
881 }
882
883 //----------------------------------------------------------------------------------
884 // genMultiRegCallStoreToLocal: store multi-reg return value of a call node to a local
885 //
886 // Arguments:
887 //    treeNode  -  Gentree of GT_STORE_LCL_VAR
888 //
889 // Return Value:
890 //    None
891 //
892 // Assumption:
893 //    The child of store is a multi-reg call node.
894 //    genProduceReg() on treeNode is made by caller of this routine.
895 //
896 void CodeGen::genMultiRegCallStoreToLocal(GenTreePtr treeNode)
897 {
898     assert(treeNode->OperGet() == GT_STORE_LCL_VAR);
899
900 #if defined(_TARGET_ARM_)
901     // Longs are returned in two return registers on Arm32.
902     assert(varTypeIsLong(treeNode));
903 #elif defined(_TARGET_ARM64_)
904     // Structs of size >=9 and <=16 are returned in two return registers on ARM64 and HFAs.
905     assert(varTypeIsStruct(treeNode));
906 #endif // _TARGET_*
907
908     // Assumption: current implementation requires that a multi-reg
909     // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
910     // being promoted.
911     unsigned   lclNum = treeNode->AsLclVarCommon()->gtLclNum;
912     LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]);
913     noway_assert(varDsc->lvIsMultiRegRet);
914
915     GenTree*     op1       = treeNode->gtGetOp1();
916     GenTree*     actualOp1 = op1->gtSkipReloadOrCopy();
917     GenTreeCall* call      = actualOp1->AsCall();
918     assert(call->HasMultiRegRetVal());
919
920     genConsumeRegs(op1);
921
922     ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc();
923     unsigned        regCount     = pRetTypeDesc->GetReturnRegCount();
924
925     if (treeNode->gtRegNum != REG_NA)
926     {
927         // Right now the only enregistrable multi-reg return types supported are SIMD types.
928         assert(varTypeIsSIMD(treeNode));
929         NYI("GT_STORE_LCL_VAR of a SIMD enregisterable struct");
930     }
931     else
932     {
933         // Stack store
934         int offset = 0;
935         for (unsigned i = 0; i < regCount; ++i)
936         {
937             var_types type = pRetTypeDesc->GetReturnRegType(i);
938             regNumber reg  = call->GetRegNumByIdx(i);
939             if (op1->IsCopyOrReload())
940             {
941                 // GT_COPY/GT_RELOAD will have valid reg for those positions
942                 // that need to be copied or reloaded.
943                 regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i);
944                 if (reloadReg != REG_NA)
945                 {
946                     reg = reloadReg;
947                 }
948             }
949
950             assert(reg != REG_NA);
951             getEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, lclNum, offset);
952             offset += genTypeSize(type);
953         }
954
955         varDsc->lvRegNum = REG_STK;
956     }
957 }
958
959 //------------------------------------------------------------------------
960 // genRangeCheck: generate code for GT_ARR_BOUNDS_CHECK node.
961 //
962 void CodeGen::genRangeCheck(GenTreePtr oper)
963 {
964 #ifdef FEATURE_SIMD
965     noway_assert(oper->OperGet() == GT_ARR_BOUNDS_CHECK || oper->OperGet() == GT_SIMD_CHK);
966 #else  // !FEATURE_SIMD
967     noway_assert(oper->OperGet() == GT_ARR_BOUNDS_CHECK);
968 #endif // !FEATURE_SIMD
969
970     GenTreeBoundsChk* bndsChk = oper->AsBoundsChk();
971
972     GenTreePtr arrLen    = bndsChk->gtArrLen;
973     GenTreePtr arrIndex  = bndsChk->gtIndex;
974     GenTreePtr arrRef    = NULL;
975     int        lenOffset = 0;
976
977     GenTree*     src1;
978     GenTree*     src2;
979     emitJumpKind jmpKind;
980
981     genConsumeRegs(arrIndex);
982     genConsumeRegs(arrLen);
983
984     if (arrIndex->isContainedIntOrIImmed())
985     {
986         // To encode using a cmp immediate, we place the
987         //  constant operand in the second position
988         src1    = arrLen;
989         src2    = arrIndex;
990         jmpKind = genJumpKindForOper(GT_LE, CK_UNSIGNED);
991     }
992     else
993     {
994         src1    = arrIndex;
995         src2    = arrLen;
996         jmpKind = genJumpKindForOper(GT_GE, CK_UNSIGNED);
997     }
998
999     getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, src1, src2);
1000     genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
1001 }
1002
1003 //---------------------------------------------------------------------
1004 // genCodeForPhysReg - generate code for a GT_PHYSREG node
1005 //
1006 // Arguments
1007 //    tree - the GT_PHYSREG node
1008 //
1009 // Return value:
1010 //    None
1011 //
1012 void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
1013 {
1014     assert(tree->OperIs(GT_PHYSREG));
1015
1016     var_types targetType = tree->TypeGet();
1017     regNumber targetReg  = tree->gtRegNum;
1018
1019     if (targetReg != tree->gtSrcReg)
1020     {
1021         inst_RV_RV(ins_Copy(targetType), targetReg, tree->gtSrcReg, targetType);
1022         genTransferRegGCState(targetReg, tree->gtSrcReg);
1023     }
1024
1025     genProduceReg(tree);
1026 }
1027
1028 //---------------------------------------------------------------------
1029 // genCodeForNullCheck - generate code for a GT_NULLCHECK node
1030 //
1031 // Arguments
1032 //    tree - the GT_NULLCHECK node
1033 //
1034 // Return value:
1035 //    None
1036 //
1037 void CodeGen::genCodeForNullCheck(GenTreeOp* tree)
1038 {
1039     assert(tree->OperIs(GT_NULLCHECK));
1040     assert(!tree->gtOp1->isContained());
1041     regNumber addrReg = genConsumeReg(tree->gtOp1);
1042
1043 #ifdef _TARGET_ARM64_
1044     regNumber targetReg = REG_ZR;
1045 #else
1046     regNumber targetReg = tree->gtRegNum;
1047 #endif
1048
1049     getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
1050 }
1051
1052 //------------------------------------------------------------------------
1053 // genOffsetOfMDArrayLowerBound: Returns the offset from the Array object to the
1054 //   lower bound for the given dimension.
1055 //
1056 // Arguments:
1057 //    elemType  - the element type of the array
1058 //    rank      - the rank of the array
1059 //    dimension - the dimension for which the lower bound offset will be returned.
1060 //
1061 // Return Value:
1062 //    The offset.
1063 // TODO-Cleanup: move to CodeGenCommon.cpp
1064
1065 // static
1066 unsigned CodeGen::genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension)
1067 {
1068     // Note that the lower bound and length fields of the Array object are always TYP_INT
1069     return compiler->eeGetArrayDataOffset(elemType) + genTypeSize(TYP_INT) * (dimension + rank);
1070 }
1071
1072 //------------------------------------------------------------------------
1073 // genOffsetOfMDArrayLength: Returns the offset from the Array object to the
1074 //   size for the given dimension.
1075 //
1076 // Arguments:
1077 //    elemType  - the element type of the array
1078 //    rank      - the rank of the array
1079 //    dimension - the dimension for which the lower bound offset will be returned.
1080 //
1081 // Return Value:
1082 //    The offset.
1083 // TODO-Cleanup: move to CodeGenCommon.cpp
1084
1085 // static
1086 unsigned CodeGen::genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension)
1087 {
1088     // Note that the lower bound and length fields of the Array object are always TYP_INT
1089     return compiler->eeGetArrayDataOffset(elemType) + genTypeSize(TYP_INT) * dimension;
1090 }
1091
1092 //------------------------------------------------------------------------
1093 // genCodeForArrIndex: Generates code to bounds check the index for one dimension of an array reference,
1094 //                     producing the effective index by subtracting the lower bound.
1095 //
1096 // Arguments:
1097 //    arrIndex - the node for which we're generating code
1098 //
1099 // Return Value:
1100 //    None.
1101 //
1102 void CodeGen::genCodeForArrIndex(GenTreeArrIndex* arrIndex)
1103 {
1104     emitter*   emit      = getEmitter();
1105     GenTreePtr arrObj    = arrIndex->ArrObj();
1106     GenTreePtr indexNode = arrIndex->IndexExpr();
1107     regNumber  arrReg    = genConsumeReg(arrObj);
1108     regNumber  indexReg  = genConsumeReg(indexNode);
1109     regNumber  tgtReg    = arrIndex->gtRegNum;
1110     noway_assert(tgtReg != REG_NA);
1111
1112     // We will use a temp register to load the lower bound and dimension size values.
1113
1114     regNumber tmpReg = arrIndex->GetSingleTempReg();
1115     assert(tgtReg != tmpReg);
1116
1117     unsigned  dim      = arrIndex->gtCurrDim;
1118     unsigned  rank     = arrIndex->gtArrRank;
1119     var_types elemType = arrIndex->gtArrElemType;
1120     unsigned  offset;
1121
1122     offset = genOffsetOfMDArrayLowerBound(elemType, rank, dim);
1123     emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load
1124     emit->emitIns_R_R_R(INS_sub, EA_4BYTE, tgtReg, indexReg, tmpReg);
1125
1126     offset = genOffsetOfMDArrayDimensionSize(elemType, rank, dim);
1127     emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load
1128     emit->emitIns_R_R(INS_cmp, EA_4BYTE, tgtReg, tmpReg);
1129
1130     emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
1131     genJumpToThrowHlpBlk(jmpGEU, SCK_RNGCHK_FAIL);
1132
1133     genProduceReg(arrIndex);
1134 }
1135
1136 //------------------------------------------------------------------------
1137 // genCodeForArrOffset: Generates code to compute the flattened array offset for
1138 //    one dimension of an array reference:
1139 //        result = (prevDimOffset * dimSize) + effectiveIndex
1140 //    where dimSize is obtained from the arrObj operand
1141 //
1142 // Arguments:
1143 //    arrOffset - the node for which we're generating code
1144 //
1145 // Return Value:
1146 //    None.
1147 //
1148 // Notes:
1149 //    dimSize and effectiveIndex are always non-negative, the former by design,
1150 //    and the latter because it has been normalized to be zero-based.
1151
1152 void CodeGen::genCodeForArrOffset(GenTreeArrOffs* arrOffset)
1153 {
1154     GenTreePtr offsetNode = arrOffset->gtOffset;
1155     GenTreePtr indexNode  = arrOffset->gtIndex;
1156     regNumber  tgtReg     = arrOffset->gtRegNum;
1157
1158     noway_assert(tgtReg != REG_NA);
1159
1160     if (!offsetNode->IsIntegralConst(0))
1161     {
1162         emitter*  emit      = getEmitter();
1163         regNumber offsetReg = genConsumeReg(offsetNode);
1164         regNumber indexReg  = genConsumeReg(indexNode);
1165         regNumber arrReg    = genConsumeReg(arrOffset->gtArrObj);
1166         noway_assert(offsetReg != REG_NA);
1167         noway_assert(indexReg != REG_NA);
1168         noway_assert(arrReg != REG_NA);
1169
1170         regNumber tmpReg = arrOffset->GetSingleTempReg();
1171
1172         unsigned  dim      = arrOffset->gtCurrDim;
1173         unsigned  rank     = arrOffset->gtArrRank;
1174         var_types elemType = arrOffset->gtArrElemType;
1175         unsigned  offset   = genOffsetOfMDArrayDimensionSize(elemType, rank, dim);
1176
1177         // Load tmpReg with the dimension size and evaluate
1178         // tgtReg = offsetReg*tmpReg + indexReg.
1179         emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset);
1180         emit->emitIns_R_R_R_R(INS_MULADD, EA_PTRSIZE, tgtReg, tmpReg, offsetReg, indexReg);
1181     }
1182     else
1183     {
1184         regNumber indexReg = genConsumeReg(indexNode);
1185         if (indexReg != tgtReg)
1186         {
1187             inst_RV_RV(INS_mov, tgtReg, indexReg, TYP_INT);
1188         }
1189     }
1190     genProduceReg(arrOffset);
1191 }
1192
1193 //------------------------------------------------------------------------
1194 // indirForm: Make a temporary indir we can feed to pattern matching routines
1195 //    in cases where we don't want to instantiate all the indirs that happen.
1196 //
1197 GenTreeIndir CodeGen::indirForm(var_types type, GenTree* base)
1198 {
1199     GenTreeIndir i(GT_IND, type, base, nullptr);
1200     i.gtRegNum = REG_NA;
1201     // has to be nonnull (because contained nodes can't be the last in block)
1202     // but don't want it to be a valid pointer
1203     i.gtNext = (GenTree*)(-1);
1204     return i;
1205 }
1206
1207 //------------------------------------------------------------------------
1208 // intForm: Make a temporary int we can feed to pattern matching routines
1209 //    in cases where we don't want to instantiate.
1210 //
1211 GenTreeIntCon CodeGen::intForm(var_types type, ssize_t value)
1212 {
1213     GenTreeIntCon i(type, value);
1214     i.gtRegNum = REG_NA;
1215     // has to be nonnull (because contained nodes can't be the last in block)
1216     // but don't want it to be a valid pointer
1217     i.gtNext = (GenTree*)(-1);
1218     return i;
1219 }
1220
1221 //------------------------------------------------------------------------
1222 // genCodeForShift: Generates the code sequence for a GenTree node that
1223 // represents a bit shift or rotate operation (<<, >>, >>>, rol, ror).
1224 //
1225 // Arguments:
1226 //    tree - the bit shift node (that specifies the type of bit shift to perform).
1227 //
1228 // Assumptions:
1229 //    a) All GenTrees are register allocated.
1230 //
1231 void CodeGen::genCodeForShift(GenTreePtr tree)
1232 {
1233     var_types   targetType = tree->TypeGet();
1234     genTreeOps  oper       = tree->OperGet();
1235     instruction ins        = genGetInsForOper(oper, targetType);
1236     emitAttr    size       = emitTypeSize(tree);
1237
1238     assert(tree->gtRegNum != REG_NA);
1239
1240     genConsumeOperands(tree->AsOp());
1241
1242     GenTreePtr operand = tree->gtGetOp1();
1243     GenTreePtr shiftBy = tree->gtGetOp2();
1244     if (!shiftBy->IsCnsIntOrI())
1245     {
1246         getEmitter()->emitIns_R_R_R(ins, size, tree->gtRegNum, operand->gtRegNum, shiftBy->gtRegNum);
1247     }
1248     else
1249     {
1250         unsigned immWidth   = emitter::getBitWidth(size); // For ARM64, immWidth will be set to 32 or 64
1251         ssize_t  shiftByImm = shiftBy->gtIntCon.gtIconVal & (immWidth - 1);
1252
1253         getEmitter()->emitIns_R_R_I(ins, size, tree->gtRegNum, operand->gtRegNum, shiftByImm);
1254     }
1255
1256     genProduceReg(tree);
1257 }
1258
1259 //------------------------------------------------------------------------
1260 // genCodeForLclAddr: Generates the code for GT_LCL_FLD_ADDR/GT_LCL_VAR_ADDR.
1261 //
1262 // Arguments:
1263 //    tree - the node.
1264 //
1265 void CodeGen::genCodeForLclAddr(GenTree* tree)
1266 {
1267     assert(tree->OperIs(GT_LCL_FLD_ADDR, GT_LCL_VAR_ADDR));
1268
1269     var_types targetType = tree->TypeGet();
1270     regNumber targetReg  = tree->gtRegNum;
1271
1272     // Address of a local var.  This by itself should never be allocated a register.
1273     // If it is worth storing the address in a register then it should be cse'ed into
1274     // a temp and that would be allocated a register.
1275     noway_assert(targetType == TYP_BYREF);
1276     noway_assert(!tree->InReg());
1277
1278     inst_RV_TT(INS_lea, targetReg, tree, 0, EA_BYREF);
1279     genProduceReg(tree);
1280 }
1281
1282 //------------------------------------------------------------------------
1283 // genCodeForLclFld: Produce code for a GT_LCL_FLD node.
1284 //
1285 // Arguments:
1286 //    tree - the GT_LCL_FLD node
1287 //
1288 void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
1289 {
1290     assert(tree->OperIs(GT_LCL_FLD));
1291
1292     var_types targetType = tree->TypeGet();
1293     regNumber targetReg  = tree->gtRegNum;
1294     emitter*  emit       = getEmitter();
1295
1296     NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported");
1297     NYI_IF(targetReg == REG_NA, "GT_LCL_FLD: load local field not into a register is not supported");
1298
1299     emitAttr size   = emitTypeSize(targetType);
1300     unsigned offs   = tree->gtLclOffs;
1301     unsigned varNum = tree->gtLclNum;
1302     assert(varNum < compiler->lvaCount);
1303
1304     if (varTypeIsFloating(targetType))
1305     {
1306         if (tree->InReg())
1307         {
1308             NYI("GT_LCL_FLD with register to register Floating point move");
1309         }
1310         else
1311         {
1312             emit->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offs);
1313         }
1314     }
1315     else
1316     {
1317 #ifdef _TARGET_ARM64_
1318         size = EA_SET_SIZE(size, EA_8BYTE);
1319 #endif // _TARGET_ARM64_
1320         emit->emitIns_R_S(ins_Move_Extend(targetType, tree->InReg()), size, targetReg, varNum, offs);
1321     }
1322
1323     genProduceReg(tree);
1324 }
1325
1326 //------------------------------------------------------------------------
1327 // genCodeForIndir: Produce code for a GT_IND node.
1328 //
1329 // Arguments:
1330 //    tree - the GT_IND node
1331 //
1332 void CodeGen::genCodeForIndir(GenTreeIndir* tree)
1333 {
1334     assert(tree->OperIs(GT_IND));
1335
1336     var_types targetType = tree->TypeGet();
1337     regNumber targetReg  = tree->gtRegNum;
1338     emitter*  emit       = getEmitter();
1339
1340     genConsumeAddress(tree->Addr());
1341     emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(tree), targetReg, tree);
1342     genProduceReg(tree);
1343
1344     if (tree->gtFlags & GTF_IND_VOLATILE)
1345     {
1346 #ifdef _TARGET_ARM64_
1347         // issue a INS_BARRIER_LD after a volatile LdInd operation
1348         instGen_MemoryBarrier(INS_BARRIER_LD);
1349 #else
1350         // issue a full memory barrier after a volatile LdInd operation
1351         instGen_MemoryBarrier();
1352 #endif // _TARGET_ARM64_
1353     }
1354 }
1355
1356 // Generate code for a CpBlk node by the means of the VM memcpy helper call
1357 // Preconditions:
1358 // a) The size argument of the CpBlk is not an integer constant
1359 // b) The size argument is a constant but is larger than CPBLK_MOVS_LIMIT bytes.
1360 void CodeGen::genCodeForCpBlk(GenTreeBlk* cpBlkNode)
1361 {
1362     // Make sure we got the arguments of the cpblk operation in the right registers
1363     unsigned   blockSize = cpBlkNode->Size();
1364     GenTreePtr dstAddr   = cpBlkNode->Addr();
1365     assert(!dstAddr->isContained());
1366
1367     genConsumeBlockOp(cpBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);
1368
1369 #ifdef _TARGET_ARM64_
1370     if (blockSize != 0)
1371     {
1372         assert(blockSize > CPBLK_UNROLL_LIMIT);
1373     }
1374 #endif // _TARGET_ARM64_
1375
1376     if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
1377     {
1378         // issue a full memory barrier before a volatile CpBlk operation
1379         instGen_MemoryBarrier();
1380     }
1381
1382     genEmitHelperCall(CORINFO_HELP_MEMCPY, 0, EA_UNKNOWN);
1383
1384     if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
1385     {
1386 #ifdef _TARGET_ARM64_
1387         // issue a INS_BARRIER_ISHLD after a volatile CpBlk operation
1388         instGen_MemoryBarrier(INS_BARRIER_ISHLD);
1389 #else
1390         // issue a full memory barrier after a volatile CpBlk operation
1391         instGen_MemoryBarrier();
1392 #endif // _TARGET_ARM64_
1393     }
1394 }
1395
1396 // Generates code for InitBlk by calling the VM memset helper function.
1397 // Preconditions:
1398 // a) The size argument of the InitBlk is not an integer constant.
1399 // b) The size argument of the InitBlk is >= INITBLK_STOS_LIMIT bytes.
1400 void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
1401 {
1402     // Make sure we got the arguments of the initblk operation in the right registers
1403     unsigned   size    = initBlkNode->Size();
1404     GenTreePtr dstAddr = initBlkNode->Addr();
1405     GenTreePtr initVal = initBlkNode->Data();
1406     if (initVal->OperIsInitVal())
1407     {
1408         initVal = initVal->gtGetOp1();
1409     }
1410
1411     assert(!dstAddr->isContained());
1412     assert(!initVal->isContained());
1413     if (initBlkNode->gtOper == GT_STORE_DYN_BLK)
1414     {
1415         assert(initBlkNode->AsDynBlk()->gtDynamicSize->gtRegNum == REG_ARG_2);
1416     }
1417     else
1418     {
1419         assert(initBlkNode->gtRsvdRegs == RBM_ARG_2);
1420     }
1421
1422 #ifdef _TARGET_ARM64_
1423     if (size != 0)
1424     {
1425         assert(size > INITBLK_UNROLL_LIMIT);
1426     }
1427 #endif // _TARGET_ARM64_
1428
1429     genConsumeBlockOp(initBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);
1430
1431     if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
1432     {
1433         // issue a full memory barrier before a volatile initBlock Operation
1434         instGen_MemoryBarrier();
1435     }
1436
1437     genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
1438 }
1439
1440 //------------------------------------------------------------------------
1441 // genRegCopy: Generate a register copy.
1442 //
1443 void CodeGen::genRegCopy(GenTree* treeNode)
1444 {
1445     assert(treeNode->OperGet() == GT_COPY);
1446
1447     var_types targetType = treeNode->TypeGet();
1448     regNumber targetReg  = treeNode->gtRegNum;
1449     assert(targetReg != REG_NA);
1450
1451     GenTree* op1 = treeNode->gtOp.gtOp1;
1452
1453     // Check whether this node and the node from which we're copying the value have the same
1454     // register type.
1455     // This can happen if (currently iff) we have a SIMD vector type that fits in an integer
1456     // register, in which case it is passed as an argument, or returned from a call,
1457     // in an integer register and must be copied if it's in an xmm register.
1458
1459     if (varTypeIsFloating(treeNode) != varTypeIsFloating(op1))
1460     {
1461         NYI_ARM("genRegCopy floating point");
1462 #ifdef _TARGET_ARM64_
1463         inst_RV_RV(INS_fmov, targetReg, genConsumeReg(op1), targetType);
1464 #endif // _TARGET_ARM64_
1465     }
1466     else
1467     {
1468         inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType);
1469     }
1470
1471     if (op1->IsLocal())
1472     {
1473         // The lclVar will never be a def.
1474         // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will
1475         // appropriately set the gcInfo for the copied value.
1476         // If not, there are two cases we need to handle:
1477         // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable
1478         //   will remain live in its original register.
1479         //   genProduceReg() will appropriately set the gcInfo for the copied value,
1480         //   and genConsumeReg will reset it.
1481         // - Otherwise, we need to update register info for the lclVar.
1482
1483         GenTreeLclVarCommon* lcl = op1->AsLclVarCommon();
1484         assert((lcl->gtFlags & GTF_VAR_DEF) == 0);
1485
1486         if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0)
1487         {
1488             LclVarDsc* varDsc = &compiler->lvaTable[lcl->gtLclNum];
1489
1490             // If we didn't just spill it (in genConsumeReg, above), then update the register info
1491             if (varDsc->lvRegNum != REG_STK)
1492             {
1493                 // The old location is dying
1494                 genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1));
1495
1496                 gcInfo.gcMarkRegSetNpt(genRegMask(op1->gtRegNum));
1497
1498                 genUpdateVarReg(varDsc, treeNode);
1499
1500                 // The new location is going live
1501                 genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode));
1502             }
1503         }
1504     }
1505
1506     genProduceReg(treeNode);
1507 }
1508
1509 //------------------------------------------------------------------------
1510 // genCallInstruction: Produce code for a GT_CALL node
1511 //
1512 void CodeGen::genCallInstruction(GenTreeCall* call)
1513 {
1514     gtCallTypes callType = (gtCallTypes)call->gtCallType;
1515
1516     IL_OFFSETX ilOffset = BAD_IL_OFFSET;
1517
1518     // all virtuals should have been expanded into a control expression
1519     assert(!call->IsVirtual() || call->gtControlExpr || call->gtCallAddr);
1520
1521     // Consume all the arg regs
1522     for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
1523     {
1524         assert(list->OperIsList());
1525
1526         GenTreePtr argNode = list->Current();
1527
1528         fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode->gtSkipReloadOrCopy());
1529         assert(curArgTabEntry);
1530
1531         if (curArgTabEntry->regNum == REG_STK)
1532             continue;
1533
1534         // Deal with multi register passed struct args.
1535         if (argNode->OperGet() == GT_FIELD_LIST)
1536         {
1537             GenTreeArgList* argListPtr   = argNode->AsArgList();
1538             unsigned        iterationNum = 0;
1539             regNumber       argReg       = curArgTabEntry->regNum;
1540             for (; argListPtr != nullptr; argListPtr = argListPtr->Rest(), iterationNum++)
1541             {
1542                 GenTreePtr putArgRegNode = argListPtr->gtOp.gtOp1;
1543                 assert(putArgRegNode->gtOper == GT_PUTARG_REG);
1544
1545                 genConsumeReg(putArgRegNode);
1546
1547                 if (putArgRegNode->gtRegNum != argReg)
1548                 {
1549                     inst_RV_RV(ins_Move_Extend(putArgRegNode->TypeGet(), putArgRegNode->InReg()), argReg,
1550                                putArgRegNode->gtRegNum);
1551                 }
1552
1553                 argReg = genRegArgNext(argReg);
1554
1555 #if defined(_TARGET_ARM_)
1556                 // A double register is modelled as an even-numbered single one
1557                 if (putArgRegNode->TypeGet() == TYP_DOUBLE)
1558                 {
1559                     argReg = genRegArgNext(argReg);
1560                 }
1561 #endif // _TARGET_ARM_
1562             }
1563         }
1564         else
1565         {
1566             regNumber argReg = curArgTabEntry->regNum;
1567             genConsumeReg(argNode);
1568             if (argNode->gtRegNum != argReg)
1569             {
1570                 inst_RV_RV(ins_Move_Extend(argNode->TypeGet(), argNode->InReg()), argReg, argNode->gtRegNum);
1571             }
1572         }
1573
1574         // In the case of a varargs call,
1575         // the ABI dictates that if we have floating point args,
1576         // we must pass the enregistered arguments in both the
1577         // integer and floating point registers so, let's do that.
1578         if (call->IsVarargs() && varTypeIsFloating(argNode))
1579         {
1580             NYI_ARM("CodeGen - IsVarargs");
1581             NYI_ARM64("CodeGen - IsVarargs");
1582         }
1583     }
1584
1585     // Insert a null check on "this" pointer if asked.
1586     if (call->NeedsNullCheck())
1587     {
1588         const regNumber regThis = genGetThisArgReg(call);
1589
1590 #if defined(_TARGET_ARM_)
1591         const regNumber tmpReg = call->ExtractTempReg();
1592         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, regThis, 0);
1593 #elif defined(_TARGET_ARM64_)
1594         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, regThis, 0);
1595 #endif // _TARGET_*
1596     }
1597
1598     // Either gtControlExpr != null or gtCallAddr != null or it is a direct non-virtual call to a user or helper method.
1599     CORINFO_METHOD_HANDLE methHnd;
1600     GenTree*              target = call->gtControlExpr;
1601     if (callType == CT_INDIRECT)
1602     {
1603         assert(target == nullptr);
1604         target  = call->gtCallAddr;
1605         methHnd = nullptr;
1606     }
1607     else
1608     {
1609         methHnd = call->gtCallMethHnd;
1610     }
1611
1612     CORINFO_SIG_INFO* sigInfo = nullptr;
1613 #ifdef DEBUG
1614     // Pass the call signature information down into the emitter so the emitter can associate
1615     // native call sites with the signatures they were generated from.
1616     if (callType != CT_HELPER)
1617     {
1618         sigInfo = call->callSig;
1619     }
1620 #endif // DEBUG
1621
1622     // If fast tail call, then we are done.  In this case we setup the args (both reg args
1623     // and stack args in incoming arg area) and call target.  Epilog sequence would
1624     // generate "br <reg>".
1625     if (call->IsFastTailCall())
1626     {
1627         // Don't support fast tail calling JIT helpers
1628         assert(callType != CT_HELPER);
1629
1630         // Fast tail calls materialize call target either in gtControlExpr or in gtCallAddr.
1631         assert(target != nullptr);
1632
1633         genConsumeReg(target);
1634
1635         NYI_ARM("fast tail call");
1636
1637 #ifdef _TARGET_ARM64_
1638         // Use IP0 as the call target register.
1639         if (target->gtRegNum != REG_IP0)
1640         {
1641             inst_RV_RV(INS_mov, REG_IP0, target->gtRegNum);
1642         }
1643 #endif // _TARGET_ARM64_
1644
1645         return;
1646     }
1647
1648     // For a pinvoke to unmanaged code we emit a label to clear
1649     // the GC pointer state before the callsite.
1650     // We can't utilize the typical lazy killing of GC pointers
1651     // at (or inside) the callsite.
1652     if (call->IsUnmanaged())
1653     {
1654         genDefineTempLabel(genCreateTempLabel());
1655     }
1656
1657     // Determine return value size(s).
1658     ReturnTypeDesc* pRetTypeDesc  = call->GetReturnTypeDesc();
1659     emitAttr        retSize       = EA_PTRSIZE;
1660     emitAttr        secondRetSize = EA_UNKNOWN;
1661
1662     if (call->HasMultiRegRetVal())
1663     {
1664         retSize       = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
1665         secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
1666     }
1667     else
1668     {
1669         assert(!varTypeIsStruct(call));
1670
1671         if (call->gtType == TYP_REF || call->gtType == TYP_ARRAY)
1672         {
1673             retSize = EA_GCREF;
1674         }
1675         else if (call->gtType == TYP_BYREF)
1676         {
1677             retSize = EA_BYREF;
1678         }
1679     }
1680
1681     // We need to propagate the IL offset information to the call instruction, so we can emit
1682     // an IL to native mapping record for the call, to support managed return value debugging.
1683     // We don't want tail call helper calls that were converted from normal calls to get a record,
1684     // so we skip this hash table lookup logic in that case.
1685     if (compiler->opts.compDbgInfo && compiler->genCallSite2ILOffsetMap != nullptr && !call->IsTailCall())
1686     {
1687         (void)compiler->genCallSite2ILOffsetMap->Lookup(call, &ilOffset);
1688     }
1689
1690     if (target != nullptr)
1691     {
1692         // A call target can not be a contained indirection
1693         assert(!target->isContainedIndir());
1694
1695         genConsumeReg(target);
1696
1697         // We have already generated code for gtControlExpr evaluating it into a register.
1698         // We just need to emit "call reg" in this case.
1699         //
1700         assert(genIsValidIntReg(target->gtRegNum));
1701
1702         genEmitCall(emitter::EC_INDIR_R, methHnd,
1703                     INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr
1704                     retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, target->gtRegNum);
1705     }
1706     else
1707     {
1708         // Generate a direct call to a non-virtual user defined or helper method
1709         assert(callType == CT_HELPER || callType == CT_USER_FUNC);
1710
1711         void* addr = nullptr;
1712         if (callType == CT_HELPER)
1713         {
1714             // Direct call to a helper method.
1715             CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
1716             noway_assert(helperNum != CORINFO_HELP_UNDEF);
1717
1718             void* pAddr = nullptr;
1719             addr        = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
1720
1721             if (addr == nullptr)
1722             {
1723                 addr = pAddr;
1724             }
1725         }
1726         else
1727         {
1728             // Direct call to a non-virtual user function.
1729             CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
1730             if (call->IsSameThis())
1731             {
1732                 aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
1733             }
1734
1735             if ((call->NeedsNullCheck()) == 0)
1736             {
1737                 aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
1738             }
1739
1740             CORINFO_CONST_LOOKUP addrInfo;
1741             compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo, aflags);
1742
1743             addr = addrInfo.addr;
1744         }
1745
1746         assert(addr != nullptr);
1747
1748 // Non-virtual direct call to known addresses
1749 #ifdef _TARGET_ARM_
1750         if (!arm_Valid_Imm_For_BL((ssize_t)addr))
1751         {
1752             regNumber tmpReg = call->GetSingleTempReg();
1753             instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr);
1754             genEmitCall(emitter::EC_INDIR_R, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) NULL, retSize, ilOffset, tmpReg);
1755         }
1756         else
1757 #endif // _TARGET_ARM_
1758         {
1759             genEmitCall(emitter::EC_FUNC_TOKEN, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) addr,
1760                         retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
1761         }
1762
1763 #if 0 && defined(_TARGET_ARM64_)
1764         // Use this path if you want to load an absolute call target using 
1765         //  a sequence of movs followed by an indirect call (blr instruction)
1766
1767         // Load the call target address in x16
1768         instGen_Set_Reg_To_Imm(EA_8BYTE, REG_IP0, (ssize_t) addr);
1769
1770         // indirect call to constant address in IP0
1771         genEmitCall(emitter::EC_INDIR_R,
1772                     methHnd, 
1773                     INDEBUG_LDISASM_COMMA(sigInfo)
1774                     nullptr, //addr
1775                     retSize,
1776                     secondRetSize,
1777                     ilOffset,
1778                     REG_IP0);
1779 #endif
1780     }
1781
1782     // if it was a pinvoke we may have needed to get the address of a label
1783     if (genPendingCallLabel)
1784     {
1785         assert(call->IsUnmanaged());
1786         genDefineTempLabel(genPendingCallLabel);
1787         genPendingCallLabel = nullptr;
1788     }
1789
1790     // Update GC info:
1791     // All Callee arg registers are trashed and no longer contain any GC pointers.
1792     // TODO-Bug?: As a matter of fact shouldn't we be killing all of callee trashed regs here?
1793     // For now we will assert that other than arg regs gc ref/byref set doesn't contain any other
1794     // registers from RBM_CALLEE_TRASH
1795     assert((gcInfo.gcRegGCrefSetCur & (RBM_CALLEE_TRASH & ~RBM_ARG_REGS)) == 0);
1796     assert((gcInfo.gcRegByrefSetCur & (RBM_CALLEE_TRASH & ~RBM_ARG_REGS)) == 0);
1797     gcInfo.gcRegGCrefSetCur &= ~RBM_ARG_REGS;
1798     gcInfo.gcRegByrefSetCur &= ~RBM_ARG_REGS;
1799
1800     var_types returnType = call->TypeGet();
1801     if (returnType != TYP_VOID)
1802     {
1803         regNumber returnReg;
1804
1805         if (call->HasMultiRegRetVal())
1806         {
1807             assert(pRetTypeDesc != nullptr);
1808             unsigned regCount = pRetTypeDesc->GetReturnRegCount();
1809
1810             // If regs allocated to call node are different from ABI return
1811             // regs in which the call has returned its result, move the result
1812             // to regs allocated to call node.
1813             for (unsigned i = 0; i < regCount; ++i)
1814             {
1815                 var_types regType      = pRetTypeDesc->GetReturnRegType(i);
1816                 returnReg              = pRetTypeDesc->GetABIReturnReg(i);
1817                 regNumber allocatedReg = call->GetRegNumByIdx(i);
1818                 if (returnReg != allocatedReg)
1819                 {
1820                     inst_RV_RV(ins_Copy(regType), allocatedReg, returnReg, regType);
1821                 }
1822             }
1823         }
1824         else
1825         {
1826 #ifdef _TARGET_ARM_
1827             if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
1828             {
1829                 // The CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
1830                 // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers.
1831                 returnReg = REG_PINVOKE_TCB;
1832             }
1833             else
1834 #endif // _TARGET_ARM_
1835                 if (varTypeIsFloating(returnType))
1836             {
1837                 returnReg = REG_FLOATRET;
1838             }
1839             else
1840             {
1841                 returnReg = REG_INTRET;
1842             }
1843
1844             if (call->gtRegNum != returnReg)
1845             {
1846                 inst_RV_RV(ins_Copy(returnType), call->gtRegNum, returnReg, returnType);
1847             }
1848         }
1849
1850         genProduceReg(call);
1851     }
1852
1853     // If there is nothing next, that means the result is thrown away, so this value is not live.
1854     // However, for minopts or debuggable code, we keep it live to support managed return value debugging.
1855     if ((call->gtNext == nullptr) && !compiler->opts.MinOpts() && !compiler->opts.compDbgCode)
1856     {
1857         gcInfo.gcMarkRegSetNpt(RBM_INTRET);
1858     }
1859 }
1860
1861 // Produce code for a GT_JMP node.
1862 // The arguments of the caller needs to be transferred to the callee before exiting caller.
1863 // The actual jump to callee is generated as part of caller epilog sequence.
1864 // Therefore the codegen of GT_JMP is to ensure that the callee arguments are correctly setup.
1865 void CodeGen::genJmpMethod(GenTreePtr jmp)
1866 {
1867     assert(jmp->OperGet() == GT_JMP);
1868     assert(compiler->compJmpOpUsed);
1869
1870     // If no arguments, nothing to do
1871     if (compiler->info.compArgsCount == 0)
1872     {
1873         return;
1874     }
1875
1876     // Make sure register arguments are in their initial registers
1877     // and stack arguments are put back as well.
1878     unsigned   varNum;
1879     LclVarDsc* varDsc;
1880
1881     // First move any en-registered stack arguments back to the stack.
1882     // At the same time any reg arg not in correct reg is moved back to its stack location.
1883     //
1884     // We are not strictly required to spill reg args that are not in the desired reg for a jmp call
1885     // But that would require us to deal with circularity while moving values around.  Spilling
1886     // to stack makes the implementation simple, which is not a bad trade off given Jmp calls
1887     // are not frequent.
1888     for (varNum = 0; (varNum < compiler->info.compArgsCount); varNum++)
1889     {
1890         varDsc = compiler->lvaTable + varNum;
1891
1892         if (varDsc->lvPromoted)
1893         {
1894             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
1895
1896             unsigned fieldVarNum = varDsc->lvFieldLclStart;
1897             varDsc               = compiler->lvaTable + fieldVarNum;
1898         }
1899         noway_assert(varDsc->lvIsParam);
1900
1901         if (varDsc->lvIsRegArg && (varDsc->lvRegNum != REG_STK))
1902         {
1903             // Skip reg args which are already in its right register for jmp call.
1904             // If not, we will spill such args to their stack locations.
1905             //
1906             // If we need to generate a tail call profiler hook, then spill all
1907             // arg regs to free them up for the callback.
1908             if (!compiler->compIsProfilerHookNeeded() && (varDsc->lvRegNum == varDsc->lvArgReg))
1909                 continue;
1910         }
1911         else if (varDsc->lvRegNum == REG_STK)
1912         {
1913             // Skip args which are currently living in stack.
1914             continue;
1915         }
1916
1917         // If we came here it means either a reg argument not in the right register or
1918         // a stack argument currently living in a register.  In either case the following
1919         // assert should hold.
1920         assert(varDsc->lvRegNum != REG_STK);
1921         assert(varDsc->TypeGet() != TYP_STRUCT);
1922         var_types storeType = genActualType(varDsc->TypeGet());
1923         emitAttr  storeSize = emitActualTypeSize(storeType);
1924
1925         getEmitter()->emitIns_S_R(ins_Store(storeType), storeSize, varDsc->lvRegNum, varNum, 0);
1926         // Update lvRegNum life and GC info to indicate lvRegNum is dead and varDsc stack slot is going live.
1927         // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
1928         // Therefore manually update life of varDsc->lvRegNum.
1929         regMaskTP tempMask = genRegMask(varDsc->lvRegNum);
1930         regSet.RemoveMaskVars(tempMask);
1931         gcInfo.gcMarkRegSetNpt(tempMask);
1932         if (compiler->lvaIsGCTracked(varDsc))
1933         {
1934             VarSetOps::AddElemD(compiler, gcInfo.gcVarPtrSetCur, varNum);
1935         }
1936     }
1937
1938 #ifdef PROFILING_SUPPORTED
1939     // At this point all arg regs are free.
1940     // Emit tail call profiler callback.
1941     genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
1942 #endif
1943
1944     // Next move any un-enregistered register arguments back to their register.
1945     regMaskTP fixedIntArgMask = RBM_NONE;    // tracks the int arg regs occupying fixed args in case of a vararg method.
1946     unsigned  firstArgVarNum  = BAD_VAR_NUM; // varNum of the first argument in case of a vararg method.
1947     for (varNum = 0; (varNum < compiler->info.compArgsCount); varNum++)
1948     {
1949         varDsc = compiler->lvaTable + varNum;
1950         if (varDsc->lvPromoted)
1951         {
1952             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
1953
1954             unsigned fieldVarNum = varDsc->lvFieldLclStart;
1955             varDsc               = compiler->lvaTable + fieldVarNum;
1956         }
1957         noway_assert(varDsc->lvIsParam);
1958
1959         // Skip if arg not passed in a register.
1960         if (!varDsc->lvIsRegArg)
1961             continue;
1962
1963         // Register argument
1964         noway_assert(isRegParamType(genActualType(varDsc->TypeGet())));
1965
1966         // Is register argument already in the right register?
1967         // If not load it from its stack location.
1968         regNumber argReg     = varDsc->lvArgReg; // incoming arg register
1969         regNumber argRegNext = REG_NA;
1970
1971         if (varDsc->lvRegNum != argReg)
1972         {
1973             var_types loadType = TYP_UNDEF;
1974             if (varTypeIsStruct(varDsc))
1975             {
1976                 // Must be <= 16 bytes or else it wouldn't be passed in registers
1977                 noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= MAX_PASS_MULTIREG_BYTES);
1978                 loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]);
1979             }
1980             else
1981             {
1982                 loadType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet()));
1983             }
1984             emitAttr loadSize = emitActualTypeSize(loadType);
1985             getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argReg, varNum, 0);
1986
1987             // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live.
1988             // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
1989             // Therefore manually update life of argReg.  Note that GT_JMP marks the end of the basic block
1990             // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList().
1991             regSet.AddMaskVars(genRegMask(argReg));
1992             gcInfo.gcMarkRegPtrVal(argReg, loadType);
1993
1994             if (compiler->lvaIsMultiregStruct(varDsc))
1995             {
1996                 if (varDsc->lvIsHfa())
1997                 {
1998                     NYI_ARM("CodeGen::genJmpMethod with multireg HFA arg");
1999                     NYI_ARM64("CodeGen::genJmpMethod with multireg HFA arg");
2000                 }
2001
2002                 // Restore the second register.
2003                 argRegNext = genRegArgNext(argReg);
2004
2005                 loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]);
2006                 loadSize = emitActualTypeSize(loadType);
2007                 getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE);
2008
2009                 regSet.AddMaskVars(genRegMask(argRegNext));
2010                 gcInfo.gcMarkRegPtrVal(argRegNext, loadType);
2011             }
2012
2013             if (compiler->lvaIsGCTracked(varDsc))
2014             {
2015                 VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varNum);
2016             }
2017         }
2018
2019         // In case of a jmp call to a vararg method ensure only integer registers are passed.
2020         if (compiler->info.compIsVarArgs)
2021         {
2022             assert((genRegMask(argReg) & RBM_ARG_REGS) != RBM_NONE);
2023
2024             fixedIntArgMask |= genRegMask(argReg);
2025
2026             if (compiler->lvaIsMultiregStruct(varDsc))
2027             {
2028                 assert(argRegNext != REG_NA);
2029                 fixedIntArgMask |= genRegMask(argRegNext);
2030             }
2031
2032             if (argReg == REG_ARG_0)
2033             {
2034                 assert(firstArgVarNum == BAD_VAR_NUM);
2035                 firstArgVarNum = varNum;
2036             }
2037         }
2038     }
2039
2040     // Jmp call to a vararg method - if the method has fewer than fixed arguments that can be max size of reg,
2041     // load the remaining integer arg registers from the corresponding
2042     // shadow stack slots.  This is for the reason that we don't know the number and type
2043     // of non-fixed params passed by the caller, therefore we have to assume the worst case
2044     // of caller passing all integer arg regs that can be max size of reg.
2045     //
2046     // The caller could have passed gc-ref/byref type var args.  Since these are var args
2047     // the callee no way of knowing their gc-ness.  Therefore, mark the region that loads
2048     // remaining arg registers from shadow stack slots as non-gc interruptible.
2049     if (fixedIntArgMask != RBM_NONE)
2050     {
2051         assert(compiler->info.compIsVarArgs);
2052         assert(firstArgVarNum != BAD_VAR_NUM);
2053
2054         regMaskTP remainingIntArgMask = RBM_ARG_REGS & ~fixedIntArgMask;
2055         if (remainingIntArgMask != RBM_NONE)
2056         {
2057             getEmitter()->emitDisableGC();
2058             for (int argNum = 0, argOffset = 0; argNum < MAX_REG_ARG; ++argNum)
2059             {
2060                 regNumber argReg     = intArgRegs[argNum];
2061                 regMaskTP argRegMask = genRegMask(argReg);
2062
2063                 if ((remainingIntArgMask & argRegMask) != 0)
2064                 {
2065                     remainingIntArgMask &= ~argRegMask;
2066                     getEmitter()->emitIns_R_S(INS_ldr, EA_PTRSIZE, argReg, firstArgVarNum, argOffset);
2067                 }
2068
2069                 argOffset += REGSIZE_BYTES;
2070             }
2071             getEmitter()->emitEnableGC();
2072         }
2073     }
2074 }
2075
2076 //------------------------------------------------------------------------
2077 // genIntToIntCast: Generate code for an integer cast
2078 //
2079 // Arguments:
2080 //    treeNode - The GT_CAST node
2081 //
2082 // Return Value:
2083 //    None.
2084 //
2085 // Assumptions:
2086 //    The treeNode must have an assigned register.
2087 //    For a signed convert from byte, the source must be in a byte-addressable register.
2088 //    Neither the source nor target type can be a floating point type.
2089 //
2090 // TODO-ARM64-CQ: Allow castOp to be a contained node without an assigned register.
2091 //
2092 void CodeGen::genIntToIntCast(GenTreePtr treeNode)
2093 {
2094     assert(treeNode->OperGet() == GT_CAST);
2095
2096     GenTreePtr castOp = treeNode->gtCast.CastOp();
2097     emitter*   emit   = getEmitter();
2098
2099     var_types dstType     = treeNode->CastToType();
2100     var_types srcType     = genActualType(castOp->TypeGet());
2101     emitAttr  movSize     = emitActualTypeSize(dstType);
2102     bool      movRequired = false;
2103
2104 #ifdef _TARGET_ARM_
2105     if (varTypeIsLong(srcType))
2106     {
2107         genLongToIntCast(treeNode);
2108         return;
2109     }
2110 #endif // _TARGET_ARM_
2111
2112     regNumber targetReg = treeNode->gtRegNum;
2113     regNumber sourceReg = castOp->gtRegNum;
2114
2115     // For Long to Int conversion we will have a reserved integer register to hold the immediate mask
2116     regNumber tmpReg = (treeNode->AvailableTempRegCount() == 0) ? REG_NA : treeNode->GetSingleTempReg();
2117
2118     assert(genIsValidIntReg(targetReg));
2119     assert(genIsValidIntReg(sourceReg));
2120
2121     instruction ins = INS_invalid;
2122
2123     genConsumeReg(castOp);
2124     Lowering::CastInfo castInfo;
2125
2126     // Get information about the cast.
2127     Lowering::getCastDescription(treeNode, &castInfo);
2128
2129     if (castInfo.requiresOverflowCheck)
2130     {
2131         emitAttr cmpSize = EA_ATTR(genTypeSize(srcType));
2132
2133         if (castInfo.signCheckOnly)
2134         {
2135             // We only need to check for a negative value in sourceReg
2136             emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, 0);
2137             emitJumpKind jmpLT = genJumpKindForOper(GT_LT, CK_SIGNED);
2138             genJumpToThrowHlpBlk(jmpLT, SCK_OVERFLOW);
2139             noway_assert(genTypeSize(srcType) == 4 || genTypeSize(srcType) == 8);
2140             // This is only interesting case to ensure zero-upper bits.
2141             if ((srcType == TYP_INT) && (dstType == TYP_ULONG))
2142             {
2143                 // cast to TYP_ULONG:
2144                 // We use a mov with size=EA_4BYTE
2145                 // which will zero out the upper bits
2146                 movSize     = EA_4BYTE;
2147                 movRequired = true;
2148             }
2149         }
2150         else if (castInfo.unsignedSource || castInfo.unsignedDest)
2151         {
2152             // When we are converting from/to unsigned,
2153             // we only have to check for any bits set in 'typeMask'
2154
2155             noway_assert(castInfo.typeMask != 0);
2156 #if defined(_TARGET_ARM_)
2157             if (arm_Valid_Imm_For_Instr(INS_tst, castInfo.typeMask, INS_FLAGS_DONT_CARE))
2158             {
2159                 emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask);
2160             }
2161             else
2162             {
2163                 noway_assert(tmpReg != REG_NA);
2164                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMask);
2165                 emit->emitIns_R_R(INS_tst, cmpSize, sourceReg, tmpReg);
2166             }
2167 #elif defined(_TARGET_ARM64_)
2168             emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask);
2169 #endif // _TARGET_ARM*
2170             emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
2171             genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
2172         }
2173         else
2174         {
2175             // For a narrowing signed cast
2176             //
2177             // We must check the value is in a signed range.
2178
2179             // Compare with the MAX
2180
2181             noway_assert((castInfo.typeMin != 0) && (castInfo.typeMax != 0));
2182
2183 #if defined(_TARGET_ARM_)
2184             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE))
2185 #elif defined(_TARGET_ARM64_)
2186             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, cmpSize))
2187 #endif // _TARGET_*
2188             {
2189                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, castInfo.typeMax);
2190             }
2191             else
2192             {
2193                 noway_assert(tmpReg != REG_NA);
2194                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMax);
2195                 emit->emitIns_R_R(INS_cmp, cmpSize, sourceReg, tmpReg);
2196             }
2197
2198             emitJumpKind jmpGT = genJumpKindForOper(GT_GT, CK_SIGNED);
2199             genJumpToThrowHlpBlk(jmpGT, SCK_OVERFLOW);
2200
2201 // Compare with the MIN
2202
2203 #if defined(_TARGET_ARM_)
2204             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE))
2205 #elif defined(_TARGET_ARM64_)
2206             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, cmpSize))
2207 #endif // _TARGET_*
2208             {
2209                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, castInfo.typeMin);
2210             }
2211             else
2212             {
2213                 noway_assert(tmpReg != REG_NA);
2214                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMin);
2215                 emit->emitIns_R_R(INS_cmp, cmpSize, sourceReg, tmpReg);
2216             }
2217
2218             emitJumpKind jmpLT = genJumpKindForOper(GT_LT, CK_SIGNED);
2219             genJumpToThrowHlpBlk(jmpLT, SCK_OVERFLOW);
2220         }
2221         ins = INS_mov;
2222     }
2223     else // Non-overflow checking cast.
2224     {
2225         if (genTypeSize(srcType) == genTypeSize(dstType))
2226         {
2227             ins = INS_mov;
2228         }
2229         else
2230         {
2231             var_types extendType = TYP_UNKNOWN;
2232
2233             if (genTypeSize(srcType) < genTypeSize(dstType))
2234             {
2235                 // If we need to treat a signed type as unsigned
2236                 if ((treeNode->gtFlags & GTF_UNSIGNED) != 0)
2237                 {
2238                     extendType = genUnsignedType(srcType);
2239                 }
2240                 else
2241                     extendType = srcType;
2242 #ifdef _TARGET_ARM_
2243                 movSize = emitTypeSize(extendType);
2244 #endif // _TARGET_ARM_
2245                 if (extendType == TYP_UINT)
2246                 {
2247 #ifdef _TARGET_ARM64_
2248                     // If we are casting from a smaller type to
2249                     // a larger type, then we need to make sure the
2250                     // higher 4 bytes are zero to gaurentee the correct value.
2251                     // Therefore using a mov with EA_4BYTE in place of EA_8BYTE
2252                     // will zero the upper bits
2253                     movSize = EA_4BYTE;
2254 #endif // _TARGET_ARM64_
2255                     movRequired = true;
2256                 }
2257             }
2258             else // (genTypeSize(srcType) > genTypeSize(dstType))
2259             {
2260                 // If we need to treat a signed type as unsigned
2261                 if ((treeNode->gtFlags & GTF_UNSIGNED) != 0)
2262                 {
2263                     extendType = genUnsignedType(dstType);
2264                 }
2265                 else
2266                     extendType = dstType;
2267 #if defined(_TARGET_ARM_)
2268                 movSize = emitTypeSize(extendType);
2269 #elif defined(_TARGET_ARM64_)
2270                 if (extendType == TYP_INT)
2271                 {
2272                     movSize = EA_8BYTE; // a sxtw instruction requires EA_8BYTE
2273                 }
2274 #endif // _TARGET_*
2275             }
2276
2277             ins = ins_Move_Extend(extendType, castOp->InReg());
2278         }
2279     }
2280
2281     // We should never be generating a load from memory instruction here!
2282     assert(!emit->emitInsIsLoad(ins));
2283
2284     if ((ins != INS_mov) || movRequired || (targetReg != sourceReg))
2285     {
2286         emit->emitIns_R_R(ins, movSize, targetReg, sourceReg);
2287     }
2288
2289     genProduceReg(treeNode);
2290 }
2291
2292 //------------------------------------------------------------------------
2293 // genFloatToFloatCast: Generate code for a cast between float and double
2294 //
2295 // Arguments:
2296 //    treeNode - The GT_CAST node
2297 //
2298 // Return Value:
2299 //    None.
2300 //
2301 // Assumptions:
2302 //    Cast is a non-overflow conversion.
2303 //    The treeNode must have an assigned register.
2304 //    The cast is between float and double.
2305 //
2306 void CodeGen::genFloatToFloatCast(GenTreePtr treeNode)
2307 {
2308     // float <--> double conversions are always non-overflow ones
2309     assert(treeNode->OperGet() == GT_CAST);
2310     assert(!treeNode->gtOverflow());
2311
2312     regNumber targetReg = treeNode->gtRegNum;
2313     assert(genIsValidFloatReg(targetReg));
2314
2315     GenTreePtr op1 = treeNode->gtOp.gtOp1;
2316     assert(!op1->isContained());               // Cannot be contained
2317     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
2318
2319     var_types dstType = treeNode->CastToType();
2320     var_types srcType = op1->TypeGet();
2321     assert(varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
2322
2323     genConsumeOperands(treeNode->AsOp());
2324
2325     // treeNode must be a reg
2326     assert(!treeNode->isContained());
2327
2328 #if defined(_TARGET_ARM_)
2329
2330     if (srcType != dstType)
2331     {
2332         instruction insVcvt = (srcType == TYP_FLOAT) ? INS_vcvt_f2d  // convert Float to Double
2333                                                      : INS_vcvt_d2f; // convert Double to Float
2334
2335         getEmitter()->emitIns_R_R(insVcvt, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2336     }
2337     else if (treeNode->gtRegNum != op1->gtRegNum)
2338     {
2339         getEmitter()->emitIns_R_R(INS_vmov, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2340     }
2341
2342 #elif defined(_TARGET_ARM64_)
2343
2344     if (srcType != dstType)
2345     {
2346         insOpts cvtOption = (srcType == TYP_FLOAT) ? INS_OPTS_S_TO_D  // convert Single to Double
2347                                                    : INS_OPTS_D_TO_S; // convert Double to Single
2348
2349         getEmitter()->emitIns_R_R(INS_fcvt, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum, cvtOption);
2350     }
2351     else if (treeNode->gtRegNum != op1->gtRegNum)
2352     {
2353         // If double to double cast or float to float cast. Emit a move instruction.
2354         getEmitter()->emitIns_R_R(INS_mov, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2355     }
2356
2357 #endif // _TARGET_*
2358
2359     genProduceReg(treeNode);
2360 }
2361
2362 //------------------------------------------------------------------------
2363 // genCreateAndStoreGCInfo: Create and record GC Info for the function.
2364 //
2365 void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize,
2366                                       unsigned prologSize,
2367                                       unsigned epilogSize DEBUGARG(void* codePtr))
2368 {
2369     IAllocator*    allowZeroAlloc = new (compiler, CMK_GC) AllowZeroAllocator(compiler->getAllocatorGC());
2370     GcInfoEncoder* gcInfoEncoder  = new (compiler, CMK_GC)
2371         GcInfoEncoder(compiler->info.compCompHnd, compiler->info.compMethodInfo, allowZeroAlloc, NOMEM);
2372     assert(gcInfoEncoder != nullptr);
2373
2374     // Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
2375     gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
2376
2377     // We keep the call count for the second call to gcMakeRegPtrTable() below.
2378     unsigned callCnt = 0;
2379
2380     // First we figure out the encoder ID's for the stack slots and registers.
2381     gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
2382
2383     // Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
2384     gcInfoEncoder->FinalizeSlotIds();
2385
2386     // Now we can actually use those slot ID's to declare live ranges.
2387     gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
2388
2389 #ifdef _TARGET_ARM64_
2390
2391     if (compiler->opts.compDbgEnC)
2392     {
2393         // what we have to preserve is called the "frame header" (see comments in VM\eetwain.cpp)
2394         // which is:
2395         //  -return address
2396         //  -saved off RBP
2397         //  -saved 'this' pointer and bool for synchronized methods
2398
2399         // 4 slots for RBP + return address + RSI + RDI
2400         int preservedAreaSize = 4 * REGSIZE_BYTES;
2401
2402         if (compiler->info.compFlags & CORINFO_FLG_SYNCH)
2403         {
2404             if (!(compiler->info.compFlags & CORINFO_FLG_STATIC))
2405                 preservedAreaSize += REGSIZE_BYTES;
2406
2407             preservedAreaSize += 1; // bool for synchronized methods
2408         }
2409
2410         // Used to signal both that the method is compiled for EnC, and also the size of the block at the top of the
2411         // frame
2412         gcInfoEncoder->SetSizeOfEditAndContinuePreservedArea(preservedAreaSize);
2413     }
2414
2415 #endif // _TARGET_ARM64_
2416
2417     gcInfoEncoder->Build();
2418
2419     // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
2420     // let's save the values anyway for debugging purposes
2421     compiler->compInfoBlkAddr = gcInfoEncoder->Emit();
2422     compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface
2423 }
2424
2425 //-------------------------------------------------------------------------------------------
2426 // genJumpKindsForTree:  Determine the number and kinds of conditional branches
2427 //                       necessary to implement the given GT_CMP node
2428 //
2429 // Arguments:
2430 //   cmpTree           - (input) The GenTree node that is used to set the Condition codes
2431 //                     - The GenTree Relop node that was used to set the Condition codes
2432 //   jmpKind[2]        - (output) One or two conditional branch instructions
2433 //   jmpToTrueLabel[2] - (output) On Arm64 both branches will always branch to the true label
2434 //
2435 // Return Value:
2436 //    Sets the proper values into the array elements of jmpKind[] and jmpToTrueLabel[]
2437 //
2438 // Assumptions:
2439 //    At least one conditional branch instruction will be returned.
2440 //    Typically only one conditional branch is needed
2441 //     and the second jmpKind[] value is set to EJ_NONE
2442 //
2443 void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2])
2444 {
2445     // On ARM both branches will always branch to the true label
2446     jmpToTrueLabel[0] = true;
2447     jmpToTrueLabel[1] = true;
2448
2449     // For integer comparisons just use genJumpKindForOper
2450     if (!varTypeIsFloating(cmpTree->gtOp.gtOp1->gtEffectiveVal()))
2451     {
2452         CompareKind compareKind = ((cmpTree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
2453         jmpKind[0]              = genJumpKindForOper(cmpTree->gtOper, compareKind);
2454         jmpKind[1]              = EJ_NONE;
2455     }
2456     else // We have a Floating Point Compare operation
2457     {
2458         assert(cmpTree->OperIsCompare());
2459
2460         // For details on this mapping, see the ARM Condition Code table
2461         // at section A8.3   in the ARMv7 architecture manual or
2462         // at section C1.2.3 in the ARMV8 architecture manual.
2463
2464         // We must check the GTF_RELOP_NAN_UN to find out
2465         // if we need to branch when we have a NaN operand.
2466         //
2467         if ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) != 0)
2468         {
2469             // Must branch if we have an NaN, unordered
2470             switch (cmpTree->gtOper)
2471             {
2472                 case GT_EQ:
2473                     jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's)
2474                     jmpKind[1] = EJ_vs; // branch or set when we have a NaN
2475                     break;
2476
2477                 case GT_NE:
2478                     jmpKind[0] = EJ_ne; // branch or set when not equal (or have NaN's)
2479                     jmpKind[1] = EJ_NONE;
2480                     break;
2481
2482                 case GT_LT:
2483                     jmpKind[0] = EJ_lt; // branch or set when less than (or have NaN's)
2484                     jmpKind[1] = EJ_NONE;
2485                     break;
2486
2487                 case GT_LE:
2488                     jmpKind[0] = EJ_le; // branch or set when less than or equal (or have NaN's)
2489                     jmpKind[1] = EJ_NONE;
2490                     break;
2491
2492                 case GT_GT:
2493                     jmpKind[0] = EJ_hi; // branch or set when greater than (or have NaN's)
2494                     jmpKind[1] = EJ_NONE;
2495                     break;
2496
2497                 case GT_GE:
2498                     jmpKind[0] = EJ_hs; // branch or set when greater than or equal (or have NaN's)
2499                     jmpKind[1] = EJ_NONE;
2500                     break;
2501
2502                 default:
2503                     unreached();
2504             }
2505         }
2506         else // ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) == 0)
2507         {
2508             // Do not branch if we have an NaN, unordered
2509             switch (cmpTree->gtOper)
2510             {
2511                 case GT_EQ:
2512                     jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's)
2513                     jmpKind[1] = EJ_NONE;
2514                     break;
2515
2516                 case GT_NE:
2517                     jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's)
2518                     jmpKind[1] = EJ_lo; // branch or set when less than (and no NaN's)
2519                     break;
2520
2521                 case GT_LT:
2522                     jmpKind[0] = EJ_lo; // branch or set when less than (and no NaN's)
2523                     jmpKind[1] = EJ_NONE;
2524                     break;
2525
2526                 case GT_LE:
2527                     jmpKind[0] = EJ_ls; // branch or set when less than or equal (and no NaN's)
2528                     jmpKind[1] = EJ_NONE;
2529                     break;
2530
2531                 case GT_GT:
2532                     jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's)
2533                     jmpKind[1] = EJ_NONE;
2534                     break;
2535
2536                 case GT_GE:
2537                     jmpKind[0] = EJ_ge; // branch or set when greater than or equal (and no NaN's)
2538                     jmpKind[1] = EJ_NONE;
2539                     break;
2540
2541                 default:
2542                     unreached();
2543             }
2544         }
2545     }
2546 }
2547
2548 //------------------------------------------------------------------------
2549 // genCodeForJumpTrue: Generates code for jmpTrue statement.
2550 //
2551 // Arguments:
2552 //    tree - The GT_JTRUE tree node.
2553 //
2554 // Return Value:
2555 //    None
2556 //
2557 void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
2558 {
2559     GenTree* cmp = tree->gtOp.gtOp1->gtEffectiveVal();
2560     assert(cmp->OperIsCompare());
2561     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
2562
2563     // Get the "kind" and type of the comparison.  Note that whether it is an unsigned cmp
2564     // is governed by a flag NOT by the inherent type of the node
2565     emitJumpKind jumpKind[2];
2566     bool         branchToTrueLabel[2];
2567     genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
2568     assert(jumpKind[0] != EJ_NONE);
2569
2570     // On ARM the branches will always branch to the true label
2571     assert(branchToTrueLabel[0]);
2572     inst_JMP(jumpKind[0], compiler->compCurBB->bbJumpDest);
2573
2574     if (jumpKind[1] != EJ_NONE)
2575     {
2576         // the second conditional branch always has to be to the true label
2577         assert(branchToTrueLabel[1]);
2578         inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
2579     }
2580 }
2581
2582 #if defined(_TARGET_ARM_)
2583
2584 //------------------------------------------------------------------------
2585 // genCodeForJcc: Produce code for a GT_JCC node.
2586 //
2587 // Arguments:
2588 //    tree - the node
2589 //
2590 void CodeGen::genCodeForJcc(GenTreeCC* tree)
2591 {
2592     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
2593
2594     CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
2595     emitJumpKind jumpKind    = genJumpKindForOper(tree->gtCondition, compareKind);
2596
2597     inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
2598 }
2599
2600 #endif // defined(_TARGET_ARM_)
2601
2602 //------------------------------------------------------------------------
2603 // genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
2604 //
2605 // Arguments:
2606 //    tree - the node
2607 //
2608 void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
2609 {
2610     assert(blkOp->OperIs(GT_STORE_OBJ, GT_STORE_DYN_BLK, GT_STORE_BLK));
2611
2612     if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
2613     {
2614         assert(blkOp->AsObj()->gtGcPtrCount != 0);
2615         genCodeForCpObj(blkOp->AsObj());
2616         return;
2617     }
2618
2619     if (blkOp->gtBlkOpGcUnsafe)
2620     {
2621         getEmitter()->emitDisableGC();
2622     }
2623     bool isCopyBlk = blkOp->OperIsCopyBlkOp();
2624
2625     switch (blkOp->gtBlkOpKind)
2626     {
2627         case GenTreeBlk::BlkOpKindHelper:
2628             if (isCopyBlk)
2629             {
2630                 genCodeForCpBlk(blkOp);
2631             }
2632             else
2633             {
2634                 genCodeForInitBlk(blkOp);
2635             }
2636             break;
2637
2638         case GenTreeBlk::BlkOpKindUnroll:
2639             if (isCopyBlk)
2640             {
2641                 genCodeForCpBlkUnroll(blkOp);
2642             }
2643             else
2644             {
2645                 genCodeForInitBlkUnroll(blkOp);
2646             }
2647             break;
2648
2649         default:
2650             unreached();
2651     }
2652
2653     if (blkOp->gtBlkOpGcUnsafe)
2654     {
2655         getEmitter()->emitEnableGC();
2656     }
2657 }
2658
2659 #endif // _TARGET_ARMARCH_
2660
2661 #endif // !LEGACY_BACKEND