[RyuJIT/ARM32] Remove NYI: using zero register
[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->AsMultiRegOp());
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         case GT_CMP:
234             genCodeForCompare(treeNode->AsOp());
235             break;
236
237         case GT_JTRUE:
238             genCodeForJumpTrue(treeNode);
239             break;
240
241 #ifdef _TARGET_ARM_
242
243         case GT_JCC:
244             genCodeForJcc(treeNode->AsCC());
245             break;
246
247         case GT_SETCC:
248             genCodeForSetcc(treeNode->AsCC());
249             break;
250
251 #endif // _TARGET_ARM_
252
253         case GT_RETURNTRAP:
254             genCodeForReturnTrap(treeNode->AsOp());
255             break;
256
257         case GT_STOREIND:
258             genCodeForStoreInd(treeNode->AsStoreInd());
259             break;
260
261         case GT_COPY:
262             // This is handled at the time we call genConsumeReg() on the GT_COPY
263             break;
264
265         case GT_LIST:
266         case GT_FIELD_LIST:
267         case GT_ARGPLACE:
268             // Nothing to do
269             break;
270
271         case GT_PUTARG_STK:
272             genPutArgStk(treeNode->AsPutArgStk());
273             break;
274
275         case GT_PUTARG_REG:
276             genPutArgReg(treeNode->AsOp());
277             break;
278
279 #ifdef _TARGET_ARM_
280         case GT_PUTARG_SPLIT:
281             genPutArgSplit(treeNode->AsPutArgSplit());
282             break;
283 #endif
284
285         case GT_CALL:
286             genCallInstruction(treeNode->AsCall());
287             break;
288
289         case GT_LOCKADD:
290         case GT_XCHG:
291         case GT_XADD:
292             genLockedInstructions(treeNode->AsOp());
293             break;
294
295         case GT_MEMORYBARRIER:
296             instGen_MemoryBarrier();
297             break;
298
299         case GT_CMPXCHG:
300             NYI("GT_CMPXCHG");
301             break;
302
303         case GT_RELOAD:
304             // do nothing - reload is just a marker.
305             // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
306             // into the register specified in this node.
307             break;
308
309         case GT_NOP:
310             break;
311
312         case GT_NO_OP:
313             instGen(INS_nop);
314             break;
315
316         case GT_ARR_BOUNDS_CHECK:
317 #ifdef FEATURE_SIMD
318         case GT_SIMD_CHK:
319 #endif // FEATURE_SIMD
320             genRangeCheck(treeNode);
321             break;
322
323         case GT_PHYSREG:
324             genCodeForPhysReg(treeNode->AsPhysReg());
325             break;
326
327         case GT_NULLCHECK:
328             genCodeForNullCheck(treeNode->AsOp());
329             break;
330
331         case GT_CATCH_ARG:
332
333             noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
334
335             /* Catch arguments get passed in a register. genCodeForBBlist()
336                would have marked it as holding a GC object, but not used. */
337
338             noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
339             genConsumeReg(treeNode);
340             break;
341
342         case GT_PINVOKE_PROLOG:
343             noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
344
345             // the runtime side requires the codegen here to be consistent
346             emit->emitDisableRandomNops();
347             break;
348
349         case GT_LABEL:
350             genPendingCallLabel       = genCreateTempLabel();
351             treeNode->gtLabel.gtLabBB = genPendingCallLabel;
352             emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
353             break;
354
355         case GT_STORE_OBJ:
356         case GT_STORE_DYN_BLK:
357         case GT_STORE_BLK:
358             genCodeForStoreBlk(treeNode->AsBlk());
359             break;
360
361         case GT_JMPTABLE:
362             genJumpTable(treeNode);
363             break;
364
365         case GT_SWITCH_TABLE:
366             genTableBasedSwitch(treeNode);
367             break;
368
369         case GT_ARR_INDEX:
370             genCodeForArrIndex(treeNode->AsArrIndex());
371             break;
372
373         case GT_ARR_OFFSET:
374             genCodeForArrOffset(treeNode->AsArrOffs());
375             break;
376
377 #ifdef _TARGET_ARM_
378
379         case GT_CLS_VAR_ADDR:
380             emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
381             genProduceReg(treeNode);
382             break;
383
384         case GT_LONG:
385             assert(treeNode->isUsedFromReg());
386             genConsumeRegs(treeNode);
387             break;
388
389 #endif // _TARGET_ARM_
390
391         case GT_IL_OFFSET:
392             // Do nothing; these nodes are simply markers for debug info.
393             break;
394
395         default:
396         {
397 #ifdef DEBUG
398             char message[256];
399             _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
400                         GenTree::OpName(treeNode->OperGet()));
401             NYIRAW(message);
402 #else
403             NYI("unimplemented node");
404 #endif
405         }
406         break;
407     }
408 }
409
410 //------------------------------------------------------------------------
411 // genSetRegToIcon: Generate code that will set the given register to the integer constant.
412 //
413 void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
414 {
415     // Reg cannot be a FP reg
416     assert(!genIsValidFloatReg(reg));
417
418     // The only TYP_REF constant that can come this path is a managed 'null' since it is not
419     // relocatable.  Other ref type constants (e.g. string objects) go through a different
420     // code path.
421     noway_assert(type != TYP_REF || val == 0);
422
423     instGen_Set_Reg_To_Imm(emitActualTypeSize(type), reg, val, flags);
424 }
425
426 //---------------------------------------------------------------------
427 // genIntrinsic - generate code for a given intrinsic
428 //
429 // Arguments
430 //    treeNode - the GT_INTRINSIC node
431 //
432 // Return value:
433 //    None
434 //
435 void CodeGen::genIntrinsic(GenTreePtr treeNode)
436 {
437     assert(treeNode->OperIs(GT_INTRINSIC));
438
439     // Both operand and its result must be of the same floating point type.
440     GenTreePtr srcNode = treeNode->gtOp.gtOp1;
441     assert(varTypeIsFloating(srcNode));
442     assert(srcNode->TypeGet() == treeNode->TypeGet());
443
444     // Right now only Abs/Round/Sqrt are treated as math intrinsics.
445     //
446     switch (treeNode->gtIntrinsic.gtIntrinsicId)
447     {
448         case CORINFO_INTRINSIC_Abs:
449             genConsumeOperands(treeNode->AsOp());
450             getEmitter()->emitInsBinary(INS_ABS, emitTypeSize(treeNode), treeNode, srcNode);
451             break;
452
453         case CORINFO_INTRINSIC_Round:
454             NYI_ARM("genIntrinsic for round - not implemented yet");
455             genConsumeOperands(treeNode->AsOp());
456             getEmitter()->emitInsBinary(INS_ROUND, emitTypeSize(treeNode), treeNode, srcNode);
457             break;
458
459         case CORINFO_INTRINSIC_Sqrt:
460             genConsumeOperands(treeNode->AsOp());
461             getEmitter()->emitInsBinary(INS_SQRT, emitTypeSize(treeNode), treeNode, srcNode);
462             break;
463
464         default:
465             assert(!"genIntrinsic: Unsupported intrinsic");
466             unreached();
467     }
468
469     genProduceReg(treeNode);
470 }
471
472 //---------------------------------------------------------------------
473 // genPutArgStk - generate code for a GT_PUTARG_STK node
474 //
475 // Arguments
476 //    treeNode - the GT_PUTARG_STK node
477 //
478 // Return value:
479 //    None
480 //
481 void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
482 {
483     assert(treeNode->OperIs(GT_PUTARG_STK));
484     var_types  targetType = treeNode->TypeGet();
485     GenTreePtr source     = treeNode->gtOp1;
486     emitter*   emit       = getEmitter();
487
488     // This is the varNum for our store operations,
489     // typically this is the varNum for the Outgoing arg space
490     // When we are generating a tail call it will be the varNum for arg0
491     unsigned varNumOut    = (unsigned)-1;
492     unsigned argOffsetMax = (unsigned)-1; // Records the maximum size of this area for assert checks
493
494     // Get argument offset to use with 'varNumOut'
495     // Here we cross check that argument offset hasn't changed from lowering to codegen since
496     // we are storing arg slot number in GT_PUTARG_STK node in lowering phase.
497     unsigned argOffsetOut = treeNode->gtSlotNum * TARGET_POINTER_SIZE;
498
499 #ifdef DEBUG
500     fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(treeNode->gtCall, treeNode);
501     assert(curArgTabEntry);
502     assert(argOffsetOut == (curArgTabEntry->slotNum * TARGET_POINTER_SIZE));
503 #endif // DEBUG
504
505     // Whether to setup stk arg in incoming or out-going arg area?
506     // Fast tail calls implemented as epilog+jmp = stk arg is setup in incoming arg area.
507     // All other calls - stk arg is setup in out-going arg area.
508     if (treeNode->putInIncomingArgArea())
509     {
510         NYI_ARM("genPutArgStk: fast tail call");
511
512 #ifdef _TARGET_ARM64_
513         varNumOut    = getFirstArgWithStackSlot();
514         argOffsetMax = compiler->compArgSize;
515 #if FEATURE_FASTTAILCALL
516         // This must be a fast tail call.
517         assert(treeNode->gtCall->IsFastTailCall());
518
519         // Since it is a fast tail call, the existence of first incoming arg is guaranteed
520         // because fast tail call requires that in-coming arg area of caller is >= out-going
521         // arg area required for tail call.
522         LclVarDsc* varDsc = &(compiler->lvaTable[varNumOut]);
523         assert(varDsc != nullptr);
524 #endif // FEATURE_FASTTAILCALL
525 #endif // _TARGET_ARM64_
526     }
527     else
528     {
529         varNumOut    = compiler->lvaOutgoingArgSpaceVar;
530         argOffsetMax = compiler->lvaOutgoingArgSpaceSize;
531     }
532
533     bool isStruct = (targetType == TYP_STRUCT) || (source->OperGet() == GT_FIELD_LIST);
534
535     if (!isStruct) // a normal non-Struct argument
536     {
537         instruction storeIns  = ins_Store(targetType);
538         emitAttr    storeAttr = emitTypeSize(targetType);
539
540         // If it is contained then source must be the integer constant zero
541         if (source->isContained())
542         {
543 #ifdef _TARGET_ARM64_
544             assert(source->OperGet() == GT_CNS_INT);
545             assert(source->AsIntConCommon()->IconValue() == 0);
546
547             emit->emitIns_S_R(storeIns, storeAttr, REG_ZR, varNumOut, argOffsetOut);
548 #else  // !_TARGET_ARM64_
549             // There is no zero register on ARM32
550             unreached();
551 #endif // !_TARGET_ARM64
552         }
553         else
554         {
555             genConsumeReg(source);
556             emit->emitIns_S_R(storeIns, storeAttr, source->gtRegNum, varNumOut, argOffsetOut);
557             if (compiler->opts.compUseSoftFP && targetType == TYP_LONG)
558             {
559                 // This case currently only occurs for double types that are passed as TYP_LONG;
560                 // actual long types would have been decomposed by now.
561                 assert(source->IsCopyOrReload());
562                 regNumber otherReg = (regNumber)source->AsCopyOrReload()->GetRegNumByIdx(1);
563                 assert(otherReg != REG_NA);
564                 argOffsetOut += EA_4BYTE;
565                 emit->emitIns_S_R(storeIns, storeAttr, otherReg, varNumOut, argOffsetOut);
566             }
567         }
568         argOffsetOut += EA_SIZE_IN_BYTES(storeAttr);
569         assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
570     }
571     else // We have some kind of a struct argument
572     {
573         assert(source->isContained()); // We expect that this node was marked as contained in Lower
574
575         if (source->OperGet() == GT_FIELD_LIST)
576         {
577             // Deal with the multi register passed struct args.
578             GenTreeFieldList* fieldListPtr = source->AsFieldList();
579
580             // Evaluate each of the GT_FIELD_LIST items into their register
581             // and store their register into the outgoing argument area
582             for (; fieldListPtr != nullptr; fieldListPtr = fieldListPtr->Rest())
583             {
584                 GenTreePtr nextArgNode = fieldListPtr->gtOp.gtOp1;
585                 genConsumeReg(nextArgNode);
586
587                 regNumber reg  = nextArgNode->gtRegNum;
588                 var_types type = nextArgNode->TypeGet();
589                 emitAttr  attr = emitTypeSize(type);
590
591                 // Emit store instructions to store the registers produced by the GT_FIELD_LIST into the outgoing
592                 // argument area
593                 emit->emitIns_S_R(ins_Store(type), attr, reg, varNumOut, argOffsetOut);
594                 argOffsetOut += EA_SIZE_IN_BYTES(attr);
595                 assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
596             }
597         }
598         else // We must have a GT_OBJ or a GT_LCL_VAR
599         {
600             noway_assert((source->OperGet() == GT_LCL_VAR) || (source->OperGet() == GT_OBJ));
601
602             var_types targetType = source->TypeGet();
603             noway_assert(varTypeIsStruct(targetType));
604
605             // We will copy this struct to the stack, possibly using a ldp/ldr instruction
606             // in ARM64/ARM
607             // Setup loReg (and hiReg) from the internal registers that we reserved in lower.
608             //
609             regNumber loReg = treeNode->ExtractTempReg();
610 #ifdef _TARGET_ARM64_
611             regNumber hiReg = treeNode->GetSingleTempReg();
612 #endif // _TARGET_ARM64_
613             regNumber addrReg = REG_NA;
614
615             GenTreeLclVarCommon* varNode  = nullptr;
616             GenTreePtr           addrNode = nullptr;
617
618             if (source->OperGet() == GT_LCL_VAR)
619             {
620                 varNode = source->AsLclVarCommon();
621             }
622             else // we must have a GT_OBJ
623             {
624                 assert(source->OperGet() == GT_OBJ);
625
626                 addrNode = source->gtOp.gtOp1;
627
628                 // addrNode can either be a GT_LCL_VAR_ADDR or an address expression
629                 //
630                 if (addrNode->OperGet() == GT_LCL_VAR_ADDR)
631                 {
632                     // We have a GT_OBJ(GT_LCL_VAR_ADDR)
633                     //
634                     // We will treat this case the same as above
635                     // (i.e if we just had this GT_LCL_VAR directly as the source)
636                     // so update 'source' to point this GT_LCL_VAR_ADDR node
637                     // and continue to the codegen for the LCL_VAR node below
638                     //
639                     varNode  = addrNode->AsLclVarCommon();
640                     addrNode = nullptr;
641                 }
642             }
643
644             // Either varNode or addrNOde must have been setup above,
645             // the xor ensures that only one of the two is setup, not both
646             assert((varNode != nullptr) ^ (addrNode != nullptr));
647
648             BYTE  gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
649             BYTE* gcPtrs                        = gcPtrArray;
650
651             unsigned gcPtrCount; // The count of GC pointers in the struct
652             int      structSize;
653             bool     isHfa;
654
655             // This is the varNum for our load operations,
656             // only used when we have a multireg struct with a LclVar source
657             unsigned varNumInp = BAD_VAR_NUM;
658
659 #ifdef _TARGET_ARM_
660             // On ARM32, size of reference map can be larger than MAX_ARG_REG_COUNT
661             gcPtrs     = treeNode->gtGcPtrs;
662             gcPtrCount = treeNode->gtNumberReferenceSlots;
663 #endif
664             // Setup the structSize, isHFa, and gcPtrCount
665             if (varNode != nullptr)
666             {
667                 varNumInp = varNode->gtLclNum;
668                 assert(varNumInp < compiler->lvaCount);
669                 LclVarDsc* varDsc = &compiler->lvaTable[varNumInp];
670
671                 assert(varDsc->lvType == TYP_STRUCT);
672 #ifdef _TARGET_ARM_
673                 if (varDsc->lvPromoted)
674                 {
675                     NYI_ARM("CodeGen::genPutArgStk - promoted struct");
676                 }
677                 else
678 #endif // _TARGET_ARM_
679                     // This struct also must live in the stack frame
680                     // And it can't live in a register (SIMD)
681                     assert(varDsc->lvOnFrame && !varDsc->lvRegister);
682
683                 structSize = varDsc->lvSize(); // This yields the roundUp size, but that is fine
684                                                // as that is how much stack is allocated for this LclVar
685                 isHfa = varDsc->lvIsHfa();
686 #ifdef _TARGET_ARM64_
687                 gcPtrCount = varDsc->lvStructGcCount;
688                 for (unsigned i = 0; i < gcPtrCount; ++i)
689                     gcPtrs[i]   = varDsc->lvGcLayout[i];
690 #endif // _TARGET_ARM_
691             }
692             else // addrNode is used
693             {
694                 assert(addrNode != nullptr);
695
696                 // Generate code to load the address that we need into a register
697                 genConsumeAddress(addrNode);
698                 addrReg = addrNode->gtRegNum;
699
700 #ifdef _TARGET_ARM64_
701                 // If addrReg equal to loReg, swap(loReg, hiReg)
702                 // This reduces code complexity by only supporting one addrReg overwrite case
703                 if (loReg == addrReg)
704                 {
705                     loReg = hiReg;
706                     hiReg = addrReg;
707                 }
708 #endif // _TARGET_ARM64_
709
710                 CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;
711
712                 structSize = compiler->info.compCompHnd->getClassSize(objClass);
713                 isHfa      = compiler->IsHfa(objClass);
714 #ifdef _TARGET_ARM64_
715                 gcPtrCount = compiler->info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]);
716 #endif
717             }
718
719             // If we have an HFA we can't have any GC pointers,
720             // if not then the max size for the the struct is 16 bytes
721             if (isHfa)
722             {
723                 noway_assert(gcPtrCount == 0);
724             }
725 #ifdef _TARGET_ARM64_
726             else
727             {
728                 noway_assert(structSize <= 2 * TARGET_POINTER_SIZE);
729             }
730
731             noway_assert(structSize <= MAX_PASS_MULTIREG_BYTES);
732 #endif // _TARGET_ARM64_
733
734             int      remainingSize = structSize;
735             unsigned structOffset  = 0;
736             unsigned nextIndex     = 0;
737
738 #ifdef _TARGET_ARM64_
739             // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop
740             //             ldp     x2, x3, [x0]
741             //             stp     x2, x3, [sp, #16]
742
743             while (remainingSize >= 2 * TARGET_POINTER_SIZE)
744             {
745                 var_types type0 = compiler->getJitGCType(gcPtrs[nextIndex + 0]);
746                 var_types type1 = compiler->getJitGCType(gcPtrs[nextIndex + 1]);
747
748                 if (varNode != nullptr)
749                 {
750                     // Load from our varNumImp source
751                     emit->emitIns_R_R_S_S(INS_ldp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumInp,
752                                           0);
753                 }
754                 else
755                 {
756                     // check for case of destroying the addrRegister while we still need it
757                     assert(loReg != addrReg);
758                     noway_assert((remainingSize == 2 * TARGET_POINTER_SIZE) || (hiReg != addrReg));
759
760                     // Load from our address expression source
761                     emit->emitIns_R_R_R_I(INS_ldp, emitTypeSize(type0), loReg, hiReg, addrReg, structOffset,
762                                           INS_OPTS_NONE, emitTypeSize(type0));
763                 }
764
765                 // Emit stp instruction to store the two registers into the outgoing argument area
766                 emit->emitIns_S_S_R_R(INS_stp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumOut,
767                                       argOffsetOut);
768                 argOffsetOut += (2 * TARGET_POINTER_SIZE); // We stored 16-bytes of the struct
769                 assert(argOffsetOut <= argOffsetMax);      // We can't write beyound the outgoing area area
770
771                 remainingSize -= (2 * TARGET_POINTER_SIZE); // We loaded 16-bytes of the struct
772                 structOffset += (2 * TARGET_POINTER_SIZE);
773                 nextIndex += 2;
774             }
775 #else  // _TARGET_ARM_
776             // For a >= 4 byte structSize we will generate a ldr and str instruction each loop
777             //             ldr     r2, [r0]
778             //             str     r2, [sp, #16]
779             while (remainingSize >= TARGET_POINTER_SIZE)
780             {
781                 var_types type = compiler->getJitGCType(gcPtrs[nextIndex]);
782
783                 if (varNode != nullptr)
784                 {
785                     // Load from our varNumImp source
786                     emit->emitIns_R_S(INS_ldr, emitTypeSize(type), loReg, varNumInp, structOffset);
787                 }
788                 else
789                 {
790                     // check for case of destroying the addrRegister while we still need it
791                     assert(loReg != addrReg || remainingSize == TARGET_POINTER_SIZE);
792
793                     // Load from our address expression source
794                     emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), loReg, addrReg, structOffset);
795                 }
796
797                 // Emit str instruction to store the register into the outgoing argument area
798                 emit->emitIns_S_R(INS_str, emitTypeSize(type), loReg, varNumOut, argOffsetOut);
799                 argOffsetOut += TARGET_POINTER_SIZE;  // We stored 4-bytes of the struct
800                 assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
801
802                 remainingSize -= TARGET_POINTER_SIZE; // We loaded 4-bytes of the struct
803                 structOffset += TARGET_POINTER_SIZE;
804                 nextIndex += 1;
805             }
806 #endif // _TARGET_ARM_
807
808             // For a 12-byte structSize we will we will generate two load instructions
809             //             ldr     x2, [x0]
810             //             ldr     w3, [x0, #8]
811             //             str     x2, [sp, #16]
812             //             str     w3, [sp, #24]
813
814             while (remainingSize > 0)
815             {
816                 if (remainingSize >= TARGET_POINTER_SIZE)
817                 {
818                     var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
819                     emitAttr  nextAttr = emitTypeSize(nextType);
820                     remainingSize -= TARGET_POINTER_SIZE;
821
822                     if (varNode != nullptr)
823                     {
824                         // Load from our varNumImp source
825                         emit->emitIns_R_S(ins_Load(nextType), nextAttr, loReg, varNumInp, structOffset);
826                     }
827                     else
828                     {
829                         assert(loReg != addrReg);
830
831                         // Load from our address expression source
832                         emit->emitIns_R_R_I(ins_Load(nextType), nextAttr, loReg, addrReg, structOffset);
833                     }
834                     // Emit a store instruction to store the register into the outgoing argument area
835                     emit->emitIns_S_R(ins_Store(nextType), nextAttr, loReg, varNumOut, argOffsetOut);
836                     argOffsetOut += EA_SIZE_IN_BYTES(nextAttr);
837                     assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
838
839                     structOffset += TARGET_POINTER_SIZE;
840                     nextIndex++;
841                 }
842                 else // (remainingSize < TARGET_POINTER_SIZE)
843                 {
844                     int loadSize  = remainingSize;
845                     remainingSize = 0;
846
847                     // We should never have to do a non-pointer sized load when we have a LclVar source
848                     assert(varNode == nullptr);
849
850                     // the left over size is smaller than a pointer and thus can never be a GC type
851                     assert(varTypeIsGC(compiler->getJitGCType(gcPtrs[nextIndex])) == false);
852
853                     var_types loadType = TYP_UINT;
854                     if (loadSize == 1)
855                     {
856                         loadType = TYP_UBYTE;
857                     }
858                     else if (loadSize == 2)
859                     {
860                         loadType = TYP_USHORT;
861                     }
862                     else
863                     {
864                         // Need to handle additional loadSize cases here
865                         noway_assert(loadSize == 4);
866                     }
867
868                     instruction loadIns  = ins_Load(loadType);
869                     emitAttr    loadAttr = emitAttr(loadSize);
870
871                     assert(loReg != addrReg);
872
873                     emit->emitIns_R_R_I(loadIns, loadAttr, loReg, addrReg, structOffset);
874
875                     // Emit a store instruction to store the register into the outgoing argument area
876                     emit->emitIns_S_R(ins_Store(loadType), loadAttr, loReg, varNumOut, argOffsetOut);
877                     argOffsetOut += EA_SIZE_IN_BYTES(loadAttr);
878                     assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
879                 }
880             }
881         }
882     }
883 }
884
885 //---------------------------------------------------------------------
886 // genPutArgReg - generate code for a GT_PUTARG_REG node
887 //
888 // Arguments
889 //    tree - the GT_PUTARG_REG node
890 //
891 // Return value:
892 //    None
893 //
894 void CodeGen::genPutArgReg(GenTreeOp* tree)
895 {
896     assert(tree->OperIs(GT_PUTARG_REG));
897
898     var_types targetType = tree->TypeGet();
899     regNumber targetReg  = tree->gtRegNum;
900
901     assert(targetType != TYP_STRUCT);
902
903     GenTree* op1 = tree->gtOp1;
904     genConsumeReg(op1);
905
906     // If child node is not already in the register we need, move it
907     if (targetReg != op1->gtRegNum)
908     {
909         inst_RV_RV(ins_Copy(targetType), targetReg, op1->gtRegNum, targetType);
910     }
911
912     genProduceReg(tree);
913 }
914
915 #ifdef _TARGET_ARM_
916 //---------------------------------------------------------------------
917 // genPutArgSplit - generate code for a GT_PUTARG_SPLIT node
918 //
919 // Arguments
920 //    tree - the GT_PUTARG_SPLIT node
921 //
922 // Return value:
923 //    None
924 //
925 void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
926 {
927     assert(treeNode->OperIs(GT_PUTARG_SPLIT));
928
929     GenTreePtr source       = treeNode->gtOp1;
930     emitter*   emit         = getEmitter();
931     unsigned   varNumOut    = compiler->lvaOutgoingArgSpaceVar;
932     unsigned   argOffsetMax = compiler->lvaOutgoingArgSpaceSize;
933     unsigned   argOffsetOut = treeNode->gtSlotNum * TARGET_POINTER_SIZE;
934
935     if (source->OperGet() == GT_FIELD_LIST)
936     {
937         GenTreeFieldList* fieldListPtr = source->AsFieldList();
938
939         // Evaluate each of the GT_FIELD_LIST items into their register
940         // and store their register into the outgoing argument area
941         for (unsigned idx = 0; fieldListPtr != nullptr; fieldListPtr = fieldListPtr->Rest(), idx++)
942         {
943             GenTreePtr nextArgNode = fieldListPtr->gtGetOp1();
944             regNumber  fieldReg    = nextArgNode->gtRegNum;
945             genConsumeReg(nextArgNode);
946
947             if (idx >= treeNode->gtNumRegs)
948             {
949                 var_types type = nextArgNode->TypeGet();
950                 emitAttr  attr = emitTypeSize(type);
951
952                 // Emit store instructions to store the registers produced by the GT_FIELD_LIST into the outgoing
953                 // argument area
954                 emit->emitIns_S_R(ins_Store(type), attr, fieldReg, varNumOut, argOffsetOut);
955                 argOffsetOut += EA_SIZE_IN_BYTES(attr);
956                 assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
957             }
958             else
959             {
960                 var_types type   = treeNode->GetRegType(idx);
961                 regNumber argReg = treeNode->GetRegNumByIdx(idx);
962
963                 // If child node is not already in the register we need, move it
964                 if (argReg != fieldReg)
965                 {
966                     inst_RV_RV(ins_Copy(type), argReg, fieldReg, type);
967                 }
968             }
969         }
970     }
971     else
972     {
973         var_types targetType = source->TypeGet();
974         assert(source->OperGet() == GT_OBJ);
975         assert(varTypeIsStruct(targetType));
976
977         regNumber baseReg = treeNode->ExtractTempReg();
978         regNumber addrReg = REG_NA;
979
980         GenTreeLclVarCommon* varNode  = nullptr;
981         GenTreePtr           addrNode = nullptr;
982
983         addrNode = source->gtOp.gtOp1;
984
985         // addrNode can either be a GT_LCL_VAR_ADDR or an address expression
986         //
987         if (addrNode->OperGet() == GT_LCL_VAR_ADDR)
988         {
989             // We have a GT_OBJ(GT_LCL_VAR_ADDR)
990             //
991             // We will treat this case the same as above
992             // (i.e if we just had this GT_LCL_VAR directly as the source)
993             // so update 'source' to point this GT_LCL_VAR_ADDR node
994             // and continue to the codegen for the LCL_VAR node below
995             //
996             varNode  = addrNode->AsLclVarCommon();
997             addrNode = nullptr;
998         }
999
1000         // Either varNode or addrNOde must have been setup above,
1001         // the xor ensures that only one of the two is setup, not both
1002         assert((varNode != nullptr) ^ (addrNode != nullptr));
1003
1004         // Setup the structSize, isHFa, and gcPtrCount
1005         BYTE*    gcPtrs     = treeNode->gtGcPtrs;
1006         unsigned gcPtrCount = treeNode->gtNumberReferenceSlots; // The count of GC pointers in the struct
1007         int      structSize = treeNode->getArgSize();
1008
1009         // This is the varNum for our load operations,
1010         // only used when we have a struct with a LclVar source
1011         unsigned srcVarNum = BAD_VAR_NUM;
1012
1013         if (varNode != nullptr)
1014         {
1015             srcVarNum = varNode->gtLclNum;
1016             assert(srcVarNum < compiler->lvaCount);
1017
1018             // handle promote situation
1019             LclVarDsc* varDsc = compiler->lvaTable + srcVarNum;
1020             if (varDsc->lvPromoted)
1021             {
1022                 NYI_ARM("CodeGen::genPutArgSplit - promoted struct");
1023             }
1024
1025             // We don't split HFA struct
1026             assert(!varDsc->lvIsHfa());
1027         }
1028         else // addrNode is used
1029         {
1030             assert(addrNode != nullptr);
1031
1032             // Generate code to load the address that we need into a register
1033             genConsumeAddress(addrNode);
1034             addrReg = addrNode->gtRegNum;
1035
1036             // If addrReg equal to baseReg, we use the last target register as alternative baseReg.
1037             // Because the candidate mask for the internal baseReg does not include any of the target register,
1038             // we can ensure that baseReg, addrReg, and the last target register are not all same.
1039             assert(baseReg != addrReg);
1040
1041             // We don't split HFA struct
1042             assert(!compiler->IsHfa(source->gtObj.gtClass));
1043         }
1044
1045         // Put on stack first
1046         unsigned nextIndex     = treeNode->gtNumRegs;
1047         unsigned structOffset  = nextIndex * TARGET_POINTER_SIZE;
1048         int      remainingSize = structSize - structOffset;
1049
1050         // remainingSize is always multiple of TARGET_POINTER_SIZE
1051         assert(remainingSize % TARGET_POINTER_SIZE == 0);
1052         while (remainingSize > 0)
1053         {
1054             var_types type = compiler->getJitGCType(gcPtrs[nextIndex]);
1055
1056             if (varNode != nullptr)
1057             {
1058                 // Load from our varNumImp source
1059                 emit->emitIns_R_S(INS_ldr, emitTypeSize(type), baseReg, srcVarNum, structOffset);
1060             }
1061             else
1062             {
1063                 // check for case of destroying the addrRegister while we still need it
1064                 assert(baseReg != addrReg);
1065
1066                 // Load from our address expression source
1067                 emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), baseReg, addrReg, structOffset);
1068             }
1069
1070             // Emit str instruction to store the register into the outgoing argument area
1071             emit->emitIns_S_R(INS_str, emitTypeSize(type), baseReg, varNumOut, argOffsetOut);
1072             argOffsetOut += TARGET_POINTER_SIZE;  // We stored 4-bytes of the struct
1073             assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
1074             remainingSize -= TARGET_POINTER_SIZE; // We loaded 4-bytes of the struct
1075             structOffset += TARGET_POINTER_SIZE;
1076             nextIndex += 1;
1077         }
1078
1079         // We set up the registers in order, so that we assign the last target register `baseReg` is no longer in use,
1080         // in case we had to reuse the last target register for it.
1081         structOffset = 0;
1082         for (unsigned idx = 0; idx < treeNode->gtNumRegs; idx++)
1083         {
1084             regNumber targetReg = treeNode->GetRegNumByIdx(idx);
1085             var_types type      = treeNode->GetRegType(idx);
1086
1087             if (varNode != nullptr)
1088             {
1089                 // Load from our varNumImp source
1090                 emit->emitIns_R_S(INS_ldr, emitTypeSize(type), targetReg, srcVarNum, structOffset);
1091             }
1092             else
1093             {
1094                 // check for case of destroying the addrRegister while we still need it
1095                 if (targetReg == addrReg && idx != treeNode->gtNumRegs - 1)
1096                 {
1097                     assert(targetReg != baseReg);
1098                     emit->emitIns_R_R(INS_mov, emitTypeSize(type), baseReg, addrReg);
1099                     addrReg = baseReg;
1100                 }
1101
1102                 // Load from our address expression source
1103                 emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), targetReg, addrReg, structOffset);
1104             }
1105             structOffset += TARGET_POINTER_SIZE;
1106         }
1107     }
1108     genProduceReg(treeNode);
1109 }
1110 #endif // _TARGET_ARM_
1111
1112 //----------------------------------------------------------------------------------
1113 // genMultiRegCallStoreToLocal: store multi-reg return value of a call node to a local
1114 //
1115 // Arguments:
1116 //    treeNode  -  Gentree of GT_STORE_LCL_VAR
1117 //
1118 // Return Value:
1119 //    None
1120 //
1121 // Assumption:
1122 //    The child of store is a multi-reg call node.
1123 //    genProduceReg() on treeNode is made by caller of this routine.
1124 //
1125 void CodeGen::genMultiRegCallStoreToLocal(GenTreePtr treeNode)
1126 {
1127     assert(treeNode->OperGet() == GT_STORE_LCL_VAR);
1128
1129 #if defined(_TARGET_ARM_)
1130     // Longs are returned in two return registers on Arm32.
1131     // Structs are returned in four registers on ARM32 and HFAs.
1132     assert(varTypeIsLong(treeNode) || varTypeIsStruct(treeNode));
1133 #elif defined(_TARGET_ARM64_)
1134     // Structs of size >=9 and <=16 are returned in two return registers on ARM64 and HFAs.
1135     assert(varTypeIsStruct(treeNode));
1136 #endif // _TARGET_*
1137
1138     // Assumption: current implementation requires that a multi-reg
1139     // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
1140     // being promoted.
1141     unsigned   lclNum = treeNode->AsLclVarCommon()->gtLclNum;
1142     LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]);
1143     noway_assert(varDsc->lvIsMultiRegRet);
1144
1145     GenTree*     op1       = treeNode->gtGetOp1();
1146     GenTree*     actualOp1 = op1->gtSkipReloadOrCopy();
1147     GenTreeCall* call      = actualOp1->AsCall();
1148     assert(call->HasMultiRegRetVal());
1149
1150     genConsumeRegs(op1);
1151
1152     ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc();
1153     unsigned        regCount     = pRetTypeDesc->GetReturnRegCount();
1154
1155     if (treeNode->gtRegNum != REG_NA)
1156     {
1157         // Right now the only enregistrable multi-reg return types supported are SIMD types.
1158         assert(varTypeIsSIMD(treeNode));
1159         NYI("GT_STORE_LCL_VAR of a SIMD enregisterable struct");
1160     }
1161     else
1162     {
1163         // Stack store
1164         int offset = 0;
1165         for (unsigned i = 0; i < regCount; ++i)
1166         {
1167             var_types type = pRetTypeDesc->GetReturnRegType(i);
1168             regNumber reg  = call->GetRegNumByIdx(i);
1169             if (op1->IsCopyOrReload())
1170             {
1171                 // GT_COPY/GT_RELOAD will have valid reg for those positions
1172                 // that need to be copied or reloaded.
1173                 regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i);
1174                 if (reloadReg != REG_NA)
1175                 {
1176                     reg = reloadReg;
1177                 }
1178             }
1179
1180             assert(reg != REG_NA);
1181             getEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, lclNum, offset);
1182             offset += genTypeSize(type);
1183         }
1184
1185         varDsc->lvRegNum = REG_STK;
1186     }
1187 }
1188
1189 //------------------------------------------------------------------------
1190 // genRangeCheck: generate code for GT_ARR_BOUNDS_CHECK node.
1191 //
1192 void CodeGen::genRangeCheck(GenTreePtr oper)
1193 {
1194 #ifdef FEATURE_SIMD
1195     noway_assert(oper->OperGet() == GT_ARR_BOUNDS_CHECK || oper->OperGet() == GT_SIMD_CHK);
1196 #else  // !FEATURE_SIMD
1197     noway_assert(oper->OperGet() == GT_ARR_BOUNDS_CHECK);
1198 #endif // !FEATURE_SIMD
1199
1200     GenTreeBoundsChk* bndsChk = oper->AsBoundsChk();
1201
1202     GenTreePtr arrLen    = bndsChk->gtArrLen;
1203     GenTreePtr arrIndex  = bndsChk->gtIndex;
1204     GenTreePtr arrRef    = NULL;
1205     int        lenOffset = 0;
1206
1207     GenTree*     src1;
1208     GenTree*     src2;
1209     emitJumpKind jmpKind;
1210
1211     genConsumeRegs(arrIndex);
1212     genConsumeRegs(arrLen);
1213
1214     if (arrIndex->isContainedIntOrIImmed())
1215     {
1216         // To encode using a cmp immediate, we place the
1217         //  constant operand in the second position
1218         src1    = arrLen;
1219         src2    = arrIndex;
1220         jmpKind = genJumpKindForOper(GT_LE, CK_UNSIGNED);
1221     }
1222     else
1223     {
1224         src1    = arrIndex;
1225         src2    = arrLen;
1226         jmpKind = genJumpKindForOper(GT_GE, CK_UNSIGNED);
1227     }
1228
1229     getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, src1, src2);
1230     genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
1231 }
1232
1233 //---------------------------------------------------------------------
1234 // genCodeForPhysReg - generate code for a GT_PHYSREG node
1235 //
1236 // Arguments
1237 //    tree - the GT_PHYSREG node
1238 //
1239 // Return value:
1240 //    None
1241 //
1242 void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
1243 {
1244     assert(tree->OperIs(GT_PHYSREG));
1245
1246     var_types targetType = tree->TypeGet();
1247     regNumber targetReg  = tree->gtRegNum;
1248
1249     if (targetReg != tree->gtSrcReg)
1250     {
1251         inst_RV_RV(ins_Copy(targetType), targetReg, tree->gtSrcReg, targetType);
1252         genTransferRegGCState(targetReg, tree->gtSrcReg);
1253     }
1254
1255     genProduceReg(tree);
1256 }
1257
1258 //---------------------------------------------------------------------
1259 // genCodeForNullCheck - generate code for a GT_NULLCHECK node
1260 //
1261 // Arguments
1262 //    tree - the GT_NULLCHECK node
1263 //
1264 // Return value:
1265 //    None
1266 //
1267 void CodeGen::genCodeForNullCheck(GenTreeOp* tree)
1268 {
1269     assert(tree->OperIs(GT_NULLCHECK));
1270     assert(!tree->gtOp1->isContained());
1271     regNumber addrReg = genConsumeReg(tree->gtOp1);
1272
1273 #ifdef _TARGET_ARM64_
1274     regNumber targetReg = REG_ZR;
1275 #else
1276     regNumber targetReg = tree->gtRegNum;
1277 #endif
1278
1279     getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
1280 }
1281
1282 //------------------------------------------------------------------------
1283 // genOffsetOfMDArrayLowerBound: Returns the offset from the Array object to the
1284 //   lower bound for the given dimension.
1285 //
1286 // Arguments:
1287 //    elemType  - the element type of the array
1288 //    rank      - the rank of the array
1289 //    dimension - the dimension for which the lower bound offset will be returned.
1290 //
1291 // Return Value:
1292 //    The offset.
1293 // TODO-Cleanup: move to CodeGenCommon.cpp
1294
1295 // static
1296 unsigned CodeGen::genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension)
1297 {
1298     // Note that the lower bound and length fields of the Array object are always TYP_INT
1299     return compiler->eeGetArrayDataOffset(elemType) + genTypeSize(TYP_INT) * (dimension + rank);
1300 }
1301
1302 //------------------------------------------------------------------------
1303 // genOffsetOfMDArrayLength: Returns the offset from the Array object to the
1304 //   size for the given dimension.
1305 //
1306 // Arguments:
1307 //    elemType  - the element type of the array
1308 //    rank      - the rank of the array
1309 //    dimension - the dimension for which the lower bound offset will be returned.
1310 //
1311 // Return Value:
1312 //    The offset.
1313 // TODO-Cleanup: move to CodeGenCommon.cpp
1314
1315 // static
1316 unsigned CodeGen::genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension)
1317 {
1318     // Note that the lower bound and length fields of the Array object are always TYP_INT
1319     return compiler->eeGetArrayDataOffset(elemType) + genTypeSize(TYP_INT) * dimension;
1320 }
1321
1322 //------------------------------------------------------------------------
1323 // genCodeForArrIndex: Generates code to bounds check the index for one dimension of an array reference,
1324 //                     producing the effective index by subtracting the lower bound.
1325 //
1326 // Arguments:
1327 //    arrIndex - the node for which we're generating code
1328 //
1329 // Return Value:
1330 //    None.
1331 //
1332 void CodeGen::genCodeForArrIndex(GenTreeArrIndex* arrIndex)
1333 {
1334     emitter*   emit      = getEmitter();
1335     GenTreePtr arrObj    = arrIndex->ArrObj();
1336     GenTreePtr indexNode = arrIndex->IndexExpr();
1337     regNumber  arrReg    = genConsumeReg(arrObj);
1338     regNumber  indexReg  = genConsumeReg(indexNode);
1339     regNumber  tgtReg    = arrIndex->gtRegNum;
1340     noway_assert(tgtReg != REG_NA);
1341
1342     // We will use a temp register to load the lower bound and dimension size values.
1343
1344     regNumber tmpReg = arrIndex->GetSingleTempReg();
1345     assert(tgtReg != tmpReg);
1346
1347     unsigned  dim      = arrIndex->gtCurrDim;
1348     unsigned  rank     = arrIndex->gtArrRank;
1349     var_types elemType = arrIndex->gtArrElemType;
1350     unsigned  offset;
1351
1352     offset = genOffsetOfMDArrayLowerBound(elemType, rank, dim);
1353     emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load
1354     emit->emitIns_R_R_R(INS_sub, EA_4BYTE, tgtReg, indexReg, tmpReg);
1355
1356     offset = genOffsetOfMDArrayDimensionSize(elemType, rank, dim);
1357     emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load
1358     emit->emitIns_R_R(INS_cmp, EA_4BYTE, tgtReg, tmpReg);
1359
1360     emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
1361     genJumpToThrowHlpBlk(jmpGEU, SCK_RNGCHK_FAIL);
1362
1363     genProduceReg(arrIndex);
1364 }
1365
1366 //------------------------------------------------------------------------
1367 // genCodeForArrOffset: Generates code to compute the flattened array offset for
1368 //    one dimension of an array reference:
1369 //        result = (prevDimOffset * dimSize) + effectiveIndex
1370 //    where dimSize is obtained from the arrObj operand
1371 //
1372 // Arguments:
1373 //    arrOffset - the node for which we're generating code
1374 //
1375 // Return Value:
1376 //    None.
1377 //
1378 // Notes:
1379 //    dimSize and effectiveIndex are always non-negative, the former by design,
1380 //    and the latter because it has been normalized to be zero-based.
1381
1382 void CodeGen::genCodeForArrOffset(GenTreeArrOffs* arrOffset)
1383 {
1384     GenTreePtr offsetNode = arrOffset->gtOffset;
1385     GenTreePtr indexNode  = arrOffset->gtIndex;
1386     regNumber  tgtReg     = arrOffset->gtRegNum;
1387
1388     noway_assert(tgtReg != REG_NA);
1389
1390     if (!offsetNode->IsIntegralConst(0))
1391     {
1392         emitter*  emit      = getEmitter();
1393         regNumber offsetReg = genConsumeReg(offsetNode);
1394         regNumber indexReg  = genConsumeReg(indexNode);
1395         regNumber arrReg    = genConsumeReg(arrOffset->gtArrObj);
1396         noway_assert(offsetReg != REG_NA);
1397         noway_assert(indexReg != REG_NA);
1398         noway_assert(arrReg != REG_NA);
1399
1400         regNumber tmpReg = arrOffset->GetSingleTempReg();
1401
1402         unsigned  dim      = arrOffset->gtCurrDim;
1403         unsigned  rank     = arrOffset->gtArrRank;
1404         var_types elemType = arrOffset->gtArrElemType;
1405         unsigned  offset   = genOffsetOfMDArrayDimensionSize(elemType, rank, dim);
1406
1407         // Load tmpReg with the dimension size and evaluate
1408         // tgtReg = offsetReg*tmpReg + indexReg.
1409         emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset);
1410         emit->emitIns_R_R_R_R(INS_MULADD, EA_PTRSIZE, tgtReg, tmpReg, offsetReg, indexReg);
1411     }
1412     else
1413     {
1414         regNumber indexReg = genConsumeReg(indexNode);
1415         if (indexReg != tgtReg)
1416         {
1417             inst_RV_RV(INS_mov, tgtReg, indexReg, TYP_INT);
1418         }
1419     }
1420     genProduceReg(arrOffset);
1421 }
1422
1423 //------------------------------------------------------------------------
1424 // indirForm: Make a temporary indir we can feed to pattern matching routines
1425 //    in cases where we don't want to instantiate all the indirs that happen.
1426 //
1427 GenTreeIndir CodeGen::indirForm(var_types type, GenTree* base)
1428 {
1429     GenTreeIndir i(GT_IND, type, base, nullptr);
1430     i.gtRegNum = REG_NA;
1431     i.SetContained();
1432     // has to be nonnull (because contained nodes can't be the last in block)
1433     // but don't want it to be a valid pointer
1434     i.gtNext = (GenTree*)(-1);
1435     return i;
1436 }
1437
1438 //------------------------------------------------------------------------
1439 // intForm: Make a temporary int we can feed to pattern matching routines
1440 //    in cases where we don't want to instantiate.
1441 //
1442 GenTreeIntCon CodeGen::intForm(var_types type, ssize_t value)
1443 {
1444     GenTreeIntCon i(type, value);
1445     i.gtRegNum = REG_NA;
1446     // has to be nonnull (because contained nodes can't be the last in block)
1447     // but don't want it to be a valid pointer
1448     i.gtNext = (GenTree*)(-1);
1449     return i;
1450 }
1451
1452 //------------------------------------------------------------------------
1453 // genCodeForShift: Generates the code sequence for a GenTree node that
1454 // represents a bit shift or rotate operation (<<, >>, >>>, rol, ror).
1455 //
1456 // Arguments:
1457 //    tree - the bit shift node (that specifies the type of bit shift to perform).
1458 //
1459 // Assumptions:
1460 //    a) All GenTrees are register allocated.
1461 //
1462 void CodeGen::genCodeForShift(GenTreePtr tree)
1463 {
1464     var_types   targetType = tree->TypeGet();
1465     genTreeOps  oper       = tree->OperGet();
1466     instruction ins        = genGetInsForOper(oper, targetType);
1467     emitAttr    size       = emitTypeSize(tree);
1468
1469     assert(tree->gtRegNum != REG_NA);
1470
1471     genConsumeOperands(tree->AsOp());
1472
1473     GenTreePtr operand = tree->gtGetOp1();
1474     GenTreePtr shiftBy = tree->gtGetOp2();
1475     if (!shiftBy->IsCnsIntOrI())
1476     {
1477         getEmitter()->emitIns_R_R_R(ins, size, tree->gtRegNum, operand->gtRegNum, shiftBy->gtRegNum);
1478     }
1479     else
1480     {
1481         unsigned immWidth   = emitter::getBitWidth(size); // For ARM64, immWidth will be set to 32 or 64
1482         ssize_t  shiftByImm = shiftBy->gtIntCon.gtIconVal & (immWidth - 1);
1483
1484         getEmitter()->emitIns_R_R_I(ins, size, tree->gtRegNum, operand->gtRegNum, shiftByImm);
1485     }
1486
1487     genProduceReg(tree);
1488 }
1489
1490 //------------------------------------------------------------------------
1491 // genCodeForLclAddr: Generates the code for GT_LCL_FLD_ADDR/GT_LCL_VAR_ADDR.
1492 //
1493 // Arguments:
1494 //    tree - the node.
1495 //
1496 void CodeGen::genCodeForLclAddr(GenTree* tree)
1497 {
1498     assert(tree->OperIs(GT_LCL_FLD_ADDR, GT_LCL_VAR_ADDR));
1499
1500     var_types targetType = tree->TypeGet();
1501     regNumber targetReg  = tree->gtRegNum;
1502
1503     // Address of a local var.
1504     noway_assert(targetType == TYP_BYREF);
1505
1506     inst_RV_TT(INS_lea, targetReg, tree, 0, EA_BYREF);
1507     genProduceReg(tree);
1508 }
1509
1510 //------------------------------------------------------------------------
1511 // genCodeForLclFld: Produce code for a GT_LCL_FLD node.
1512 //
1513 // Arguments:
1514 //    tree - the GT_LCL_FLD node
1515 //
1516 void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
1517 {
1518     assert(tree->OperIs(GT_LCL_FLD));
1519
1520     var_types targetType = tree->TypeGet();
1521     regNumber targetReg  = tree->gtRegNum;
1522     emitter*  emit       = getEmitter();
1523
1524     NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported");
1525     assert(targetReg != REG_NA);
1526
1527     emitAttr size   = emitTypeSize(targetType);
1528     unsigned offs   = tree->gtLclOffs;
1529     unsigned varNum = tree->gtLclNum;
1530     assert(varNum < compiler->lvaCount);
1531
1532     if (varTypeIsFloating(targetType))
1533     {
1534         emit->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offs);
1535     }
1536     else
1537     {
1538 #ifdef _TARGET_ARM64_
1539         size = EA_SET_SIZE(size, EA_8BYTE);
1540 #endif // _TARGET_ARM64_
1541         emit->emitIns_R_S(ins_Move_Extend(targetType, false), size, targetReg, varNum, offs);
1542     }
1543
1544     genProduceReg(tree);
1545 }
1546
1547 //------------------------------------------------------------------------
1548 // genCodeForIndir: Produce code for a GT_IND node.
1549 //
1550 // Arguments:
1551 //    tree - the GT_IND node
1552 //
1553 void CodeGen::genCodeForIndir(GenTreeIndir* tree)
1554 {
1555     assert(tree->OperIs(GT_IND));
1556
1557     var_types   targetType = tree->TypeGet();
1558     regNumber   targetReg  = tree->gtRegNum;
1559     emitter*    emit       = getEmitter();
1560     emitAttr    attr       = emitTypeSize(tree);
1561     instruction ins        = ins_Load(targetType);
1562
1563     assert((attr != EA_1BYTE) || !(tree->gtFlags & GTF_IND_UNALIGNED));
1564
1565     genConsumeAddress(tree->Addr());
1566     if (tree->gtFlags & GTF_IND_VOLATILE)
1567     {
1568 #ifdef _TARGET_ARM64_
1569         GenTree* addr           = tree->Addr();
1570         bool     useLoadAcquire = genIsValidIntReg(targetReg) && !addr->isContained() &&
1571                               (varTypeIsUnsigned(targetType) || varTypeIsI(targetType)) &&
1572                               !(tree->gtFlags & GTF_IND_UNALIGNED);
1573
1574         if (useLoadAcquire)
1575         {
1576             switch (EA_SIZE(attr))
1577             {
1578                 case EA_1BYTE:
1579                     assert(ins == INS_ldrb);
1580                     ins = INS_ldarb;
1581                     break;
1582                 case EA_2BYTE:
1583                     assert(ins == INS_ldrh);
1584                     ins = INS_ldarh;
1585                     break;
1586                 case EA_4BYTE:
1587                 case EA_8BYTE:
1588                     assert(ins == INS_ldr);
1589                     ins = INS_ldar;
1590                     break;
1591                 default:
1592                     assert(false); // We should not get here
1593             }
1594         }
1595
1596         emit->emitInsLoadStoreOp(ins, attr, targetReg, tree);
1597
1598         if (!useLoadAcquire) // issue a INS_BARRIER_OSHLD after a volatile LdInd operation
1599             instGen_MemoryBarrier(INS_BARRIER_OSHLD);
1600 #else
1601         emit->emitInsLoadStoreOp(ins, attr, targetReg, tree);
1602
1603         // issue a full memory barrier after a volatile LdInd operation
1604         instGen_MemoryBarrier();
1605 #endif // _TARGET_ARM64_
1606     }
1607     else
1608     {
1609         emit->emitInsLoadStoreOp(ins, attr, targetReg, tree);
1610     }
1611
1612     genProduceReg(tree);
1613 }
1614
1615 // Generate code for a CpBlk node by the means of the VM memcpy helper call
1616 // Preconditions:
1617 // a) The size argument of the CpBlk is not an integer constant
1618 // b) The size argument is a constant but is larger than CPBLK_MOVS_LIMIT bytes.
1619 void CodeGen::genCodeForCpBlk(GenTreeBlk* cpBlkNode)
1620 {
1621     // Make sure we got the arguments of the cpblk operation in the right registers
1622     unsigned   blockSize = cpBlkNode->Size();
1623     GenTreePtr dstAddr   = cpBlkNode->Addr();
1624     assert(!dstAddr->isContained());
1625
1626     genConsumeBlockOp(cpBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);
1627
1628 #ifdef _TARGET_ARM64_
1629     if (blockSize != 0)
1630     {
1631         assert(blockSize > CPBLK_UNROLL_LIMIT);
1632     }
1633 #endif // _TARGET_ARM64_
1634
1635     if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
1636     {
1637         // issue a full memory barrier before a volatile CpBlk operation
1638         instGen_MemoryBarrier();
1639     }
1640
1641     genEmitHelperCall(CORINFO_HELP_MEMCPY, 0, EA_UNKNOWN);
1642
1643     if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE)
1644     {
1645 #ifdef _TARGET_ARM64_
1646         // issue a INS_BARRIER_ISHLD after a volatile CpBlk operation
1647         instGen_MemoryBarrier(INS_BARRIER_ISHLD);
1648 #else
1649         // issue a full memory barrier after a volatile CpBlk operation
1650         instGen_MemoryBarrier();
1651 #endif // _TARGET_ARM64_
1652     }
1653 }
1654
1655 // Generates code for InitBlk by calling the VM memset helper function.
1656 // Preconditions:
1657 // a) The size argument of the InitBlk is not an integer constant.
1658 // b) The size argument of the InitBlk is >= INITBLK_STOS_LIMIT bytes.
1659 void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
1660 {
1661     // Make sure we got the arguments of the initblk operation in the right registers
1662     unsigned   size    = initBlkNode->Size();
1663     GenTreePtr dstAddr = initBlkNode->Addr();
1664     GenTreePtr initVal = initBlkNode->Data();
1665     if (initVal->OperIsInitVal())
1666     {
1667         initVal = initVal->gtGetOp1();
1668     }
1669
1670     assert(!dstAddr->isContained());
1671     assert(!initVal->isContained());
1672     if (initBlkNode->gtOper == GT_STORE_DYN_BLK)
1673     {
1674         assert(initBlkNode->AsDynBlk()->gtDynamicSize->gtRegNum == REG_ARG_2);
1675     }
1676     else
1677     {
1678         assert(initBlkNode->gtRsvdRegs == RBM_ARG_2);
1679     }
1680
1681 #ifdef _TARGET_ARM64_
1682     if (size != 0)
1683     {
1684         assert(size > INITBLK_UNROLL_LIMIT);
1685     }
1686 #endif // _TARGET_ARM64_
1687
1688     genConsumeBlockOp(initBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);
1689
1690     if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
1691     {
1692         // issue a full memory barrier before a volatile initBlock Operation
1693         instGen_MemoryBarrier();
1694     }
1695
1696     genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
1697 }
1698
1699 //------------------------------------------------------------------------
1700 // genRegCopy: Generate a register copy.
1701 //
1702 void CodeGen::genRegCopy(GenTree* treeNode)
1703 {
1704     assert(treeNode->OperGet() == GT_COPY);
1705
1706     var_types targetType = treeNode->TypeGet();
1707     regNumber targetReg  = treeNode->gtRegNum;
1708     assert(targetReg != REG_NA);
1709
1710     GenTree* op1 = treeNode->gtOp.gtOp1;
1711
1712     // Check whether this node and the node from which we're copying the value have the same
1713     // register type.
1714     // This can happen if (currently iff) we have a SIMD vector type that fits in an integer
1715     // register, in which case it is passed as an argument, or returned from a call,
1716     // in an integer register and must be copied if it's in an xmm register.
1717
1718     if (varTypeIsFloating(treeNode) != varTypeIsFloating(op1))
1719     {
1720 #ifdef _TARGET_ARM64_
1721         inst_RV_RV(INS_fmov, targetReg, genConsumeReg(op1), targetType);
1722 #else  // !_TARGET_ARM64_
1723         if (varTypeIsFloating(treeNode))
1724         {
1725             NYI_ARM("genRegCopy from 'int' to 'float'");
1726         }
1727         else
1728         {
1729             assert(varTypeIsFloating(op1));
1730
1731             if (op1->TypeGet() == TYP_FLOAT)
1732             {
1733                 inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType);
1734             }
1735             else
1736             {
1737                 regNumber otherReg = (regNumber)treeNode->AsCopyOrReload()->gtOtherRegs[0];
1738                 assert(otherReg != REG_NA);
1739                 inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE);
1740             }
1741         }
1742 #endif // !_TARGET_ARM64_
1743     }
1744     else
1745     {
1746         inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType);
1747     }
1748
1749     if (op1->IsLocal())
1750     {
1751         // The lclVar will never be a def.
1752         // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will
1753         // appropriately set the gcInfo for the copied value.
1754         // If not, there are two cases we need to handle:
1755         // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable
1756         //   will remain live in its original register.
1757         //   genProduceReg() will appropriately set the gcInfo for the copied value,
1758         //   and genConsumeReg will reset it.
1759         // - Otherwise, we need to update register info for the lclVar.
1760
1761         GenTreeLclVarCommon* lcl = op1->AsLclVarCommon();
1762         assert((lcl->gtFlags & GTF_VAR_DEF) == 0);
1763
1764         if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0)
1765         {
1766             LclVarDsc* varDsc = &compiler->lvaTable[lcl->gtLclNum];
1767
1768             // If we didn't just spill it (in genConsumeReg, above), then update the register info
1769             if (varDsc->lvRegNum != REG_STK)
1770             {
1771                 // The old location is dying
1772                 genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1));
1773
1774                 gcInfo.gcMarkRegSetNpt(genRegMask(op1->gtRegNum));
1775
1776                 genUpdateVarReg(varDsc, treeNode);
1777
1778                 // The new location is going live
1779                 genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode));
1780             }
1781         }
1782     }
1783
1784     genProduceReg(treeNode);
1785 }
1786
1787 //------------------------------------------------------------------------
1788 // genCallInstruction: Produce code for a GT_CALL node
1789 //
1790 void CodeGen::genCallInstruction(GenTreeCall* call)
1791 {
1792     gtCallTypes callType = (gtCallTypes)call->gtCallType;
1793
1794     IL_OFFSETX ilOffset = BAD_IL_OFFSET;
1795
1796     // all virtuals should have been expanded into a control expression
1797     assert(!call->IsVirtual() || call->gtControlExpr || call->gtCallAddr);
1798
1799     // Consume all the arg regs
1800     for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
1801     {
1802         assert(list->OperIsList());
1803
1804         GenTreePtr argNode = list->Current();
1805
1806         fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode->gtSkipReloadOrCopy());
1807         assert(curArgTabEntry);
1808
1809         if (curArgTabEntry->regNum == REG_STK)
1810             continue;
1811
1812         // Deal with multi register passed struct args.
1813         if (argNode->OperGet() == GT_FIELD_LIST)
1814         {
1815             GenTreeArgList* argListPtr   = argNode->AsArgList();
1816             unsigned        iterationNum = 0;
1817             regNumber       argReg       = curArgTabEntry->regNum;
1818             for (; argListPtr != nullptr; argListPtr = argListPtr->Rest(), iterationNum++)
1819             {
1820                 GenTreePtr putArgRegNode = argListPtr->gtOp.gtOp1;
1821                 assert(putArgRegNode->gtOper == GT_PUTARG_REG);
1822
1823                 genConsumeReg(putArgRegNode);
1824
1825                 if (putArgRegNode->gtRegNum != argReg)
1826                 {
1827                     inst_RV_RV(ins_Move_Extend(putArgRegNode->TypeGet(), true), argReg, putArgRegNode->gtRegNum);
1828                 }
1829
1830                 argReg = genRegArgNext(argReg);
1831
1832 #if defined(_TARGET_ARM_)
1833                 // A double register is modelled as an even-numbered single one
1834                 if (putArgRegNode->TypeGet() == TYP_DOUBLE)
1835                 {
1836                     argReg = genRegArgNext(argReg);
1837                 }
1838 #endif // _TARGET_ARM_
1839             }
1840         }
1841 #ifdef _TARGET_ARM_
1842         else if (curArgTabEntry->isSplit)
1843         {
1844             assert(curArgTabEntry->numRegs >= 1);
1845             genConsumeArgSplitStruct(argNode->AsPutArgSplit());
1846             for (unsigned idx = 0; idx < curArgTabEntry->numRegs; idx++)
1847             {
1848                 regNumber argReg   = (regNumber)((unsigned)curArgTabEntry->regNum + idx);
1849                 regNumber allocReg = argNode->AsPutArgSplit()->GetRegNumByIdx(idx);
1850                 if (argReg != allocReg)
1851                 {
1852                     inst_RV_RV(ins_Move_Extend(argNode->TypeGet(), true), argReg, allocReg);
1853                 }
1854             }
1855         }
1856 #endif
1857         else
1858         {
1859             regNumber argReg = curArgTabEntry->regNum;
1860             genConsumeReg(argNode);
1861             if (argNode->gtRegNum != argReg)
1862             {
1863                 inst_RV_RV(ins_Move_Extend(argNode->TypeGet(), true), argReg, argNode->gtRegNum);
1864             }
1865         }
1866
1867         // In the case of a varargs call,
1868         // the ABI dictates that if we have floating point args,
1869         // we must pass the enregistered arguments in both the
1870         // integer and floating point registers so, let's do that.
1871         if (call->IsVarargs() && varTypeIsFloating(argNode))
1872         {
1873             NYI_ARM("CodeGen - IsVarargs");
1874             NYI_ARM64("CodeGen - IsVarargs");
1875         }
1876     }
1877
1878     // Insert a null check on "this" pointer if asked.
1879     if (call->NeedsNullCheck())
1880     {
1881         const regNumber regThis = genGetThisArgReg(call);
1882
1883 #if defined(_TARGET_ARM_)
1884         const regNumber tmpReg = call->ExtractTempReg();
1885         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, regThis, 0);
1886 #elif defined(_TARGET_ARM64_)
1887         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, regThis, 0);
1888 #endif // _TARGET_*
1889     }
1890
1891     // Either gtControlExpr != null or gtCallAddr != null or it is a direct non-virtual call to a user or helper method.
1892     CORINFO_METHOD_HANDLE methHnd;
1893     GenTree*              target = call->gtControlExpr;
1894     if (callType == CT_INDIRECT)
1895     {
1896         assert(target == nullptr);
1897         target  = call->gtCallAddr;
1898         methHnd = nullptr;
1899     }
1900     else
1901     {
1902         methHnd = call->gtCallMethHnd;
1903     }
1904
1905     CORINFO_SIG_INFO* sigInfo = nullptr;
1906 #ifdef DEBUG
1907     // Pass the call signature information down into the emitter so the emitter can associate
1908     // native call sites with the signatures they were generated from.
1909     if (callType != CT_HELPER)
1910     {
1911         sigInfo = call->callSig;
1912     }
1913 #endif // DEBUG
1914
1915     // If fast tail call, then we are done.  In this case we setup the args (both reg args
1916     // and stack args in incoming arg area) and call target.  Epilog sequence would
1917     // generate "br <reg>".
1918     if (call->IsFastTailCall())
1919     {
1920         // Don't support fast tail calling JIT helpers
1921         assert(callType != CT_HELPER);
1922
1923         // Fast tail calls materialize call target either in gtControlExpr or in gtCallAddr.
1924         assert(target != nullptr);
1925
1926         genConsumeReg(target);
1927
1928         NYI_ARM("fast tail call");
1929
1930 #ifdef _TARGET_ARM64_
1931         // Use IP0 as the call target register.
1932         if (target->gtRegNum != REG_IP0)
1933         {
1934             inst_RV_RV(INS_mov, REG_IP0, target->gtRegNum);
1935         }
1936 #endif // _TARGET_ARM64_
1937
1938         return;
1939     }
1940
1941     // For a pinvoke to unmanaged code we emit a label to clear
1942     // the GC pointer state before the callsite.
1943     // We can't utilize the typical lazy killing of GC pointers
1944     // at (or inside) the callsite.
1945     if (call->IsUnmanaged())
1946     {
1947         genDefineTempLabel(genCreateTempLabel());
1948     }
1949
1950     // Determine return value size(s).
1951     ReturnTypeDesc* pRetTypeDesc  = call->GetReturnTypeDesc();
1952     emitAttr        retSize       = EA_PTRSIZE;
1953     emitAttr        secondRetSize = EA_UNKNOWN;
1954
1955     if (call->HasMultiRegRetVal())
1956     {
1957         retSize       = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
1958         secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
1959     }
1960     else
1961     {
1962         assert(!varTypeIsStruct(call));
1963
1964         if (call->gtType == TYP_REF || call->gtType == TYP_ARRAY)
1965         {
1966             retSize = EA_GCREF;
1967         }
1968         else if (call->gtType == TYP_BYREF)
1969         {
1970             retSize = EA_BYREF;
1971         }
1972     }
1973
1974     // We need to propagate the IL offset information to the call instruction, so we can emit
1975     // an IL to native mapping record for the call, to support managed return value debugging.
1976     // We don't want tail call helper calls that were converted from normal calls to get a record,
1977     // so we skip this hash table lookup logic in that case.
1978     if (compiler->opts.compDbgInfo && compiler->genCallSite2ILOffsetMap != nullptr && !call->IsTailCall())
1979     {
1980         (void)compiler->genCallSite2ILOffsetMap->Lookup(call, &ilOffset);
1981     }
1982
1983     if (target != nullptr)
1984     {
1985         // A call target can not be a contained indirection
1986         assert(!target->isContainedIndir());
1987
1988         genConsumeReg(target);
1989
1990         // We have already generated code for gtControlExpr evaluating it into a register.
1991         // We just need to emit "call reg" in this case.
1992         //
1993         assert(genIsValidIntReg(target->gtRegNum));
1994
1995         genEmitCall(emitter::EC_INDIR_R, methHnd,
1996                     INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr
1997                     retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, target->gtRegNum);
1998     }
1999     else
2000     {
2001         // Generate a direct call to a non-virtual user defined or helper method
2002         assert(callType == CT_HELPER || callType == CT_USER_FUNC);
2003
2004         void* addr = nullptr;
2005         if (callType == CT_HELPER)
2006         {
2007             // Direct call to a helper method.
2008             CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
2009             noway_assert(helperNum != CORINFO_HELP_UNDEF);
2010
2011             void* pAddr = nullptr;
2012             addr        = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
2013
2014             if (addr == nullptr)
2015             {
2016                 addr = pAddr;
2017             }
2018         }
2019         else
2020         {
2021             // Direct call to a non-virtual user function.
2022             CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
2023             if (call->IsSameThis())
2024             {
2025                 aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
2026             }
2027
2028             if ((call->NeedsNullCheck()) == 0)
2029             {
2030                 aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
2031             }
2032
2033             CORINFO_CONST_LOOKUP addrInfo;
2034             compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo, aflags);
2035
2036             addr = addrInfo.addr;
2037         }
2038
2039         assert(addr != nullptr);
2040
2041 // Non-virtual direct call to known addresses
2042 #ifdef _TARGET_ARM_
2043         if (!arm_Valid_Imm_For_BL((ssize_t)addr))
2044         {
2045             regNumber tmpReg = call->GetSingleTempReg();
2046             instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr);
2047             genEmitCall(emitter::EC_INDIR_R, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) NULL, retSize, ilOffset, tmpReg);
2048         }
2049         else
2050 #endif // _TARGET_ARM_
2051         {
2052             genEmitCall(emitter::EC_FUNC_TOKEN, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) addr,
2053                         retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
2054         }
2055
2056 #if 0 && defined(_TARGET_ARM64_)
2057         // Use this path if you want to load an absolute call target using 
2058         //  a sequence of movs followed by an indirect call (blr instruction)
2059
2060         // Load the call target address in x16
2061         instGen_Set_Reg_To_Imm(EA_8BYTE, REG_IP0, (ssize_t) addr);
2062
2063         // indirect call to constant address in IP0
2064         genEmitCall(emitter::EC_INDIR_R,
2065                     methHnd, 
2066                     INDEBUG_LDISASM_COMMA(sigInfo)
2067                     nullptr, //addr
2068                     retSize,
2069                     secondRetSize,
2070                     ilOffset,
2071                     REG_IP0);
2072 #endif
2073     }
2074
2075     // if it was a pinvoke we may have needed to get the address of a label
2076     if (genPendingCallLabel)
2077     {
2078         assert(call->IsUnmanaged());
2079         genDefineTempLabel(genPendingCallLabel);
2080         genPendingCallLabel = nullptr;
2081     }
2082
2083     // Update GC info:
2084     // All Callee arg registers are trashed and no longer contain any GC pointers.
2085     // TODO-Bug?: As a matter of fact shouldn't we be killing all of callee trashed regs here?
2086     // For now we will assert that other than arg regs gc ref/byref set doesn't contain any other
2087     // registers from RBM_CALLEE_TRASH
2088     assert((gcInfo.gcRegGCrefSetCur & (RBM_CALLEE_TRASH & ~RBM_ARG_REGS)) == 0);
2089     assert((gcInfo.gcRegByrefSetCur & (RBM_CALLEE_TRASH & ~RBM_ARG_REGS)) == 0);
2090     gcInfo.gcRegGCrefSetCur &= ~RBM_ARG_REGS;
2091     gcInfo.gcRegByrefSetCur &= ~RBM_ARG_REGS;
2092
2093     var_types returnType = call->TypeGet();
2094     if (returnType != TYP_VOID)
2095     {
2096         regNumber returnReg;
2097
2098         if (call->HasMultiRegRetVal())
2099         {
2100             assert(pRetTypeDesc != nullptr);
2101             unsigned regCount = pRetTypeDesc->GetReturnRegCount();
2102
2103             // If regs allocated to call node are different from ABI return
2104             // regs in which the call has returned its result, move the result
2105             // to regs allocated to call node.
2106             for (unsigned i = 0; i < regCount; ++i)
2107             {
2108                 var_types regType      = pRetTypeDesc->GetReturnRegType(i);
2109                 returnReg              = pRetTypeDesc->GetABIReturnReg(i);
2110                 regNumber allocatedReg = call->GetRegNumByIdx(i);
2111                 if (returnReg != allocatedReg)
2112                 {
2113                     inst_RV_RV(ins_Copy(regType), allocatedReg, returnReg, regType);
2114                 }
2115             }
2116         }
2117         else
2118         {
2119 #ifdef _TARGET_ARM_
2120             if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
2121             {
2122                 // The CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
2123                 // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers.
2124                 returnReg = REG_PINVOKE_TCB;
2125             }
2126             else
2127 #endif // _TARGET_ARM_
2128                 if (varTypeIsFloating(returnType) && !compiler->opts.compUseSoftFP)
2129             {
2130                 returnReg = REG_FLOATRET;
2131             }
2132             else
2133             {
2134                 returnReg = REG_INTRET;
2135             }
2136
2137             if (call->gtRegNum != returnReg)
2138             {
2139 #ifdef _TARGET_ARM_
2140                 if (compiler->opts.compUseSoftFP && returnType == TYP_DOUBLE)
2141                 {
2142                     inst_RV_RV_RV(INS_vmov_i2d, call->gtRegNum, returnReg, genRegArgNext(returnReg), EA_8BYTE);
2143                 }
2144                 else if (compiler->opts.compUseSoftFP && returnType == TYP_FLOAT)
2145                 {
2146                     inst_RV_RV(INS_vmov_i2f, call->gtRegNum, returnReg, returnType);
2147                 }
2148                 else
2149 #endif
2150                 {
2151                     inst_RV_RV(ins_Copy(returnType), call->gtRegNum, returnReg, returnType);
2152                 }
2153             }
2154         }
2155
2156         genProduceReg(call);
2157     }
2158
2159     // If there is nothing next, that means the result is thrown away, so this value is not live.
2160     // However, for minopts or debuggable code, we keep it live to support managed return value debugging.
2161     if ((call->gtNext == nullptr) && !compiler->opts.MinOpts() && !compiler->opts.compDbgCode)
2162     {
2163         gcInfo.gcMarkRegSetNpt(RBM_INTRET);
2164     }
2165 }
2166
2167 // Produce code for a GT_JMP node.
2168 // The arguments of the caller needs to be transferred to the callee before exiting caller.
2169 // The actual jump to callee is generated as part of caller epilog sequence.
2170 // Therefore the codegen of GT_JMP is to ensure that the callee arguments are correctly setup.
2171 void CodeGen::genJmpMethod(GenTreePtr jmp)
2172 {
2173     assert(jmp->OperGet() == GT_JMP);
2174     assert(compiler->compJmpOpUsed);
2175
2176     // If no arguments, nothing to do
2177     if (compiler->info.compArgsCount == 0)
2178     {
2179         return;
2180     }
2181
2182     // Make sure register arguments are in their initial registers
2183     // and stack arguments are put back as well.
2184     unsigned   varNum;
2185     LclVarDsc* varDsc;
2186
2187     // First move any en-registered stack arguments back to the stack.
2188     // At the same time any reg arg not in correct reg is moved back to its stack location.
2189     //
2190     // We are not strictly required to spill reg args that are not in the desired reg for a jmp call
2191     // But that would require us to deal with circularity while moving values around.  Spilling
2192     // to stack makes the implementation simple, which is not a bad trade off given Jmp calls
2193     // are not frequent.
2194     for (varNum = 0; (varNum < compiler->info.compArgsCount); varNum++)
2195     {
2196         varDsc = compiler->lvaTable + varNum;
2197
2198         if (varDsc->lvPromoted)
2199         {
2200             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
2201
2202             unsigned fieldVarNum = varDsc->lvFieldLclStart;
2203             varDsc               = compiler->lvaTable + fieldVarNum;
2204         }
2205         noway_assert(varDsc->lvIsParam);
2206
2207         if (varDsc->lvIsRegArg && (varDsc->lvRegNum != REG_STK))
2208         {
2209             // Skip reg args which are already in its right register for jmp call.
2210             // If not, we will spill such args to their stack locations.
2211             //
2212             // If we need to generate a tail call profiler hook, then spill all
2213             // arg regs to free them up for the callback.
2214             if (!compiler->compIsProfilerHookNeeded() && (varDsc->lvRegNum == varDsc->lvArgReg))
2215                 continue;
2216         }
2217         else if (varDsc->lvRegNum == REG_STK)
2218         {
2219             // Skip args which are currently living in stack.
2220             continue;
2221         }
2222
2223         // If we came here it means either a reg argument not in the right register or
2224         // a stack argument currently living in a register.  In either case the following
2225         // assert should hold.
2226         assert(varDsc->lvRegNum != REG_STK);
2227         assert(varDsc->TypeGet() != TYP_STRUCT);
2228         var_types storeType = genActualType(varDsc->TypeGet());
2229         emitAttr  storeSize = emitActualTypeSize(storeType);
2230
2231         getEmitter()->emitIns_S_R(ins_Store(storeType), storeSize, varDsc->lvRegNum, varNum, 0);
2232         // Update lvRegNum life and GC info to indicate lvRegNum is dead and varDsc stack slot is going live.
2233         // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
2234         // Therefore manually update life of varDsc->lvRegNum.
2235         regMaskTP tempMask = genRegMask(varDsc->lvRegNum);
2236         regSet.RemoveMaskVars(tempMask);
2237         gcInfo.gcMarkRegSetNpt(tempMask);
2238         if (compiler->lvaIsGCTracked(varDsc))
2239         {
2240             VarSetOps::AddElemD(compiler, gcInfo.gcVarPtrSetCur, varNum);
2241         }
2242     }
2243
2244 #ifdef PROFILING_SUPPORTED
2245     // At this point all arg regs are free.
2246     // Emit tail call profiler callback.
2247     genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
2248 #endif
2249
2250     // Next move any un-enregistered register arguments back to their register.
2251     regMaskTP fixedIntArgMask = RBM_NONE;    // tracks the int arg regs occupying fixed args in case of a vararg method.
2252     unsigned  firstArgVarNum  = BAD_VAR_NUM; // varNum of the first argument in case of a vararg method.
2253     for (varNum = 0; (varNum < compiler->info.compArgsCount); varNum++)
2254     {
2255         varDsc = compiler->lvaTable + varNum;
2256         if (varDsc->lvPromoted)
2257         {
2258             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
2259
2260             unsigned fieldVarNum = varDsc->lvFieldLclStart;
2261             varDsc               = compiler->lvaTable + fieldVarNum;
2262         }
2263         noway_assert(varDsc->lvIsParam);
2264
2265         // Skip if arg not passed in a register.
2266         if (!varDsc->lvIsRegArg)
2267             continue;
2268
2269         // Register argument
2270         noway_assert(isRegParamType(genActualType(varDsc->TypeGet())));
2271
2272         // Is register argument already in the right register?
2273         // If not load it from its stack location.
2274         regNumber argReg     = varDsc->lvArgReg; // incoming arg register
2275         regNumber argRegNext = REG_NA;
2276
2277         if (varDsc->lvRegNum != argReg)
2278         {
2279             var_types loadType = TYP_UNDEF;
2280             if (varTypeIsStruct(varDsc))
2281             {
2282                 // Must be <= 16 bytes or else it wouldn't be passed in registers
2283                 noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= MAX_PASS_MULTIREG_BYTES);
2284                 loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]);
2285             }
2286             else
2287             {
2288                 loadType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet()));
2289             }
2290             emitAttr loadSize = emitActualTypeSize(loadType);
2291             getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argReg, varNum, 0);
2292
2293             // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live.
2294             // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
2295             // Therefore manually update life of argReg.  Note that GT_JMP marks the end of the basic block
2296             // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList().
2297             regSet.AddMaskVars(genRegMask(argReg));
2298             gcInfo.gcMarkRegPtrVal(argReg, loadType);
2299
2300             if (compiler->lvaIsMultiregStruct(varDsc))
2301             {
2302                 if (varDsc->lvIsHfa())
2303                 {
2304                     NYI_ARM("CodeGen::genJmpMethod with multireg HFA arg");
2305                     NYI_ARM64("CodeGen::genJmpMethod with multireg HFA arg");
2306                 }
2307
2308                 // Restore the second register.
2309                 argRegNext = genRegArgNext(argReg);
2310
2311                 loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]);
2312                 loadSize = emitActualTypeSize(loadType);
2313                 getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE);
2314
2315                 regSet.AddMaskVars(genRegMask(argRegNext));
2316                 gcInfo.gcMarkRegPtrVal(argRegNext, loadType);
2317             }
2318
2319             if (compiler->lvaIsGCTracked(varDsc))
2320             {
2321                 VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varNum);
2322             }
2323         }
2324
2325         // In case of a jmp call to a vararg method ensure only integer registers are passed.
2326         if (compiler->info.compIsVarArgs)
2327         {
2328             assert((genRegMask(argReg) & RBM_ARG_REGS) != RBM_NONE);
2329
2330             fixedIntArgMask |= genRegMask(argReg);
2331
2332             if (compiler->lvaIsMultiregStruct(varDsc))
2333             {
2334                 assert(argRegNext != REG_NA);
2335                 fixedIntArgMask |= genRegMask(argRegNext);
2336             }
2337
2338             if (argReg == REG_ARG_0)
2339             {
2340                 assert(firstArgVarNum == BAD_VAR_NUM);
2341                 firstArgVarNum = varNum;
2342             }
2343         }
2344     }
2345
2346     // Jmp call to a vararg method - if the method has fewer than fixed arguments that can be max size of reg,
2347     // load the remaining integer arg registers from the corresponding
2348     // shadow stack slots.  This is for the reason that we don't know the number and type
2349     // of non-fixed params passed by the caller, therefore we have to assume the worst case
2350     // of caller passing all integer arg regs that can be max size of reg.
2351     //
2352     // The caller could have passed gc-ref/byref type var args.  Since these are var args
2353     // the callee no way of knowing their gc-ness.  Therefore, mark the region that loads
2354     // remaining arg registers from shadow stack slots as non-gc interruptible.
2355     if (fixedIntArgMask != RBM_NONE)
2356     {
2357         assert(compiler->info.compIsVarArgs);
2358         assert(firstArgVarNum != BAD_VAR_NUM);
2359
2360         regMaskTP remainingIntArgMask = RBM_ARG_REGS & ~fixedIntArgMask;
2361         if (remainingIntArgMask != RBM_NONE)
2362         {
2363             getEmitter()->emitDisableGC();
2364             for (int argNum = 0, argOffset = 0; argNum < MAX_REG_ARG; ++argNum)
2365             {
2366                 regNumber argReg     = intArgRegs[argNum];
2367                 regMaskTP argRegMask = genRegMask(argReg);
2368
2369                 if ((remainingIntArgMask & argRegMask) != 0)
2370                 {
2371                     remainingIntArgMask &= ~argRegMask;
2372                     getEmitter()->emitIns_R_S(INS_ldr, EA_PTRSIZE, argReg, firstArgVarNum, argOffset);
2373                 }
2374
2375                 argOffset += REGSIZE_BYTES;
2376             }
2377             getEmitter()->emitEnableGC();
2378         }
2379     }
2380 }
2381
2382 //------------------------------------------------------------------------
2383 // genIntToIntCast: Generate code for an integer cast
2384 //
2385 // Arguments:
2386 //    treeNode - The GT_CAST node
2387 //
2388 // Return Value:
2389 //    None.
2390 //
2391 // Assumptions:
2392 //    The treeNode must have an assigned register.
2393 //    For a signed convert from byte, the source must be in a byte-addressable register.
2394 //    Neither the source nor target type can be a floating point type.
2395 //
2396 // TODO-ARM64-CQ: Allow castOp to be a contained node without an assigned register.
2397 //
2398 void CodeGen::genIntToIntCast(GenTreePtr treeNode)
2399 {
2400     assert(treeNode->OperGet() == GT_CAST);
2401
2402     GenTreePtr castOp = treeNode->gtCast.CastOp();
2403     emitter*   emit   = getEmitter();
2404
2405     var_types dstType     = treeNode->CastToType();
2406     var_types srcType     = genActualType(castOp->TypeGet());
2407     emitAttr  movSize     = emitActualTypeSize(dstType);
2408     bool      movRequired = false;
2409
2410 #ifdef _TARGET_ARM_
2411     if (varTypeIsLong(srcType))
2412     {
2413         genLongToIntCast(treeNode);
2414         return;
2415     }
2416 #endif // _TARGET_ARM_
2417
2418     regNumber targetReg = treeNode->gtRegNum;
2419     regNumber sourceReg = castOp->gtRegNum;
2420
2421     // For Long to Int conversion we will have a reserved integer register to hold the immediate mask
2422     regNumber tmpReg = (treeNode->AvailableTempRegCount() == 0) ? REG_NA : treeNode->GetSingleTempReg();
2423
2424     assert(genIsValidIntReg(targetReg));
2425     assert(genIsValidIntReg(sourceReg));
2426
2427     instruction ins = INS_invalid;
2428
2429     genConsumeReg(castOp);
2430     Lowering::CastInfo castInfo;
2431
2432     // Get information about the cast.
2433     Lowering::getCastDescription(treeNode, &castInfo);
2434
2435     if (castInfo.requiresOverflowCheck)
2436     {
2437         emitAttr cmpSize = EA_ATTR(genTypeSize(srcType));
2438
2439         if (castInfo.signCheckOnly)
2440         {
2441             // We only need to check for a negative value in sourceReg
2442             emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, 0);
2443             emitJumpKind jmpLT = genJumpKindForOper(GT_LT, CK_SIGNED);
2444             genJumpToThrowHlpBlk(jmpLT, SCK_OVERFLOW);
2445             noway_assert(genTypeSize(srcType) == 4 || genTypeSize(srcType) == 8);
2446             // This is only interesting case to ensure zero-upper bits.
2447             if ((srcType == TYP_INT) && (dstType == TYP_ULONG))
2448             {
2449                 // cast to TYP_ULONG:
2450                 // We use a mov with size=EA_4BYTE
2451                 // which will zero out the upper bits
2452                 movSize     = EA_4BYTE;
2453                 movRequired = true;
2454             }
2455         }
2456         else if (castInfo.unsignedSource || castInfo.unsignedDest)
2457         {
2458             // When we are converting from/to unsigned,
2459             // we only have to check for any bits set in 'typeMask'
2460
2461             noway_assert(castInfo.typeMask != 0);
2462 #if defined(_TARGET_ARM_)
2463             if (arm_Valid_Imm_For_Instr(INS_tst, castInfo.typeMask, INS_FLAGS_DONT_CARE))
2464             {
2465                 emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask);
2466             }
2467             else
2468             {
2469                 noway_assert(tmpReg != REG_NA);
2470                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMask);
2471                 emit->emitIns_R_R(INS_tst, cmpSize, sourceReg, tmpReg);
2472             }
2473 #elif defined(_TARGET_ARM64_)
2474             emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask);
2475 #endif // _TARGET_ARM*
2476             emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
2477             genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
2478         }
2479         else
2480         {
2481             // For a narrowing signed cast
2482             //
2483             // We must check the value is in a signed range.
2484
2485             // Compare with the MAX
2486
2487             noway_assert((castInfo.typeMin != 0) && (castInfo.typeMax != 0));
2488
2489 #if defined(_TARGET_ARM_)
2490             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE))
2491 #elif defined(_TARGET_ARM64_)
2492             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, cmpSize))
2493 #endif // _TARGET_*
2494             {
2495                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, castInfo.typeMax);
2496             }
2497             else
2498             {
2499                 noway_assert(tmpReg != REG_NA);
2500                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMax);
2501                 emit->emitIns_R_R(INS_cmp, cmpSize, sourceReg, tmpReg);
2502             }
2503
2504             emitJumpKind jmpGT = genJumpKindForOper(GT_GT, CK_SIGNED);
2505             genJumpToThrowHlpBlk(jmpGT, SCK_OVERFLOW);
2506
2507 // Compare with the MIN
2508
2509 #if defined(_TARGET_ARM_)
2510             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE))
2511 #elif defined(_TARGET_ARM64_)
2512             if (emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, cmpSize))
2513 #endif // _TARGET_*
2514             {
2515                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, castInfo.typeMin);
2516             }
2517             else
2518             {
2519                 noway_assert(tmpReg != REG_NA);
2520                 instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMin);
2521                 emit->emitIns_R_R(INS_cmp, cmpSize, sourceReg, tmpReg);
2522             }
2523
2524             emitJumpKind jmpLT = genJumpKindForOper(GT_LT, CK_SIGNED);
2525             genJumpToThrowHlpBlk(jmpLT, SCK_OVERFLOW);
2526         }
2527         ins = INS_mov;
2528     }
2529     else // Non-overflow checking cast.
2530     {
2531         if (genTypeSize(srcType) == genTypeSize(dstType))
2532         {
2533             ins = INS_mov;
2534         }
2535         else
2536         {
2537             var_types extendType = TYP_UNKNOWN;
2538
2539             if (genTypeSize(srcType) < genTypeSize(dstType))
2540             {
2541                 // If we need to treat a signed type as unsigned
2542                 if ((treeNode->gtFlags & GTF_UNSIGNED) != 0)
2543                 {
2544                     extendType = genUnsignedType(srcType);
2545                 }
2546                 else
2547                     extendType = srcType;
2548 #ifdef _TARGET_ARM_
2549                 movSize = emitTypeSize(extendType);
2550 #endif // _TARGET_ARM_
2551                 if (extendType == TYP_UINT)
2552                 {
2553 #ifdef _TARGET_ARM64_
2554                     // If we are casting from a smaller type to
2555                     // a larger type, then we need to make sure the
2556                     // higher 4 bytes are zero to gaurentee the correct value.
2557                     // Therefore using a mov with EA_4BYTE in place of EA_8BYTE
2558                     // will zero the upper bits
2559                     movSize = EA_4BYTE;
2560 #endif // _TARGET_ARM64_
2561                     movRequired = true;
2562                 }
2563             }
2564             else // (genTypeSize(srcType) > genTypeSize(dstType))
2565             {
2566                 // If we need to treat a signed type as unsigned
2567                 if ((treeNode->gtFlags & GTF_UNSIGNED) != 0)
2568                 {
2569                     extendType = genUnsignedType(dstType);
2570                 }
2571                 else
2572                     extendType = dstType;
2573 #if defined(_TARGET_ARM_)
2574                 movSize = emitTypeSize(extendType);
2575 #elif defined(_TARGET_ARM64_)
2576                 if (extendType == TYP_INT)
2577                 {
2578                     movSize = EA_8BYTE; // a sxtw instruction requires EA_8BYTE
2579                 }
2580 #endif // _TARGET_*
2581             }
2582
2583             ins = ins_Move_Extend(extendType, true);
2584         }
2585     }
2586
2587     // We should never be generating a load from memory instruction here!
2588     assert(!emit->emitInsIsLoad(ins));
2589
2590     if ((ins != INS_mov) || movRequired || (targetReg != sourceReg))
2591     {
2592         emit->emitIns_R_R(ins, movSize, targetReg, sourceReg);
2593     }
2594
2595     genProduceReg(treeNode);
2596 }
2597
2598 //------------------------------------------------------------------------
2599 // genFloatToFloatCast: Generate code for a cast between float and double
2600 //
2601 // Arguments:
2602 //    treeNode - The GT_CAST node
2603 //
2604 // Return Value:
2605 //    None.
2606 //
2607 // Assumptions:
2608 //    Cast is a non-overflow conversion.
2609 //    The treeNode must have an assigned register.
2610 //    The cast is between float and double.
2611 //
2612 void CodeGen::genFloatToFloatCast(GenTreePtr treeNode)
2613 {
2614     // float <--> double conversions are always non-overflow ones
2615     assert(treeNode->OperGet() == GT_CAST);
2616     assert(!treeNode->gtOverflow());
2617
2618     regNumber targetReg = treeNode->gtRegNum;
2619     assert(genIsValidFloatReg(targetReg));
2620
2621     GenTreePtr op1 = treeNode->gtOp.gtOp1;
2622     assert(!op1->isContained());               // Cannot be contained
2623     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
2624
2625     var_types dstType = treeNode->CastToType();
2626     var_types srcType = op1->TypeGet();
2627     assert(varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
2628
2629     genConsumeOperands(treeNode->AsOp());
2630
2631     // treeNode must be a reg
2632     assert(!treeNode->isContained());
2633
2634 #if defined(_TARGET_ARM_)
2635
2636     if (srcType != dstType)
2637     {
2638         instruction insVcvt = (srcType == TYP_FLOAT) ? INS_vcvt_f2d  // convert Float to Double
2639                                                      : INS_vcvt_d2f; // convert Double to Float
2640
2641         getEmitter()->emitIns_R_R(insVcvt, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2642     }
2643     else if (treeNode->gtRegNum != op1->gtRegNum)
2644     {
2645         getEmitter()->emitIns_R_R(INS_vmov, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2646     }
2647
2648 #elif defined(_TARGET_ARM64_)
2649
2650     if (srcType != dstType)
2651     {
2652         insOpts cvtOption = (srcType == TYP_FLOAT) ? INS_OPTS_S_TO_D  // convert Single to Double
2653                                                    : INS_OPTS_D_TO_S; // convert Double to Single
2654
2655         getEmitter()->emitIns_R_R(INS_fcvt, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum, cvtOption);
2656     }
2657     else if (treeNode->gtRegNum != op1->gtRegNum)
2658     {
2659         // If double to double cast or float to float cast. Emit a move instruction.
2660         getEmitter()->emitIns_R_R(INS_mov, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum);
2661     }
2662
2663 #endif // _TARGET_*
2664
2665     genProduceReg(treeNode);
2666 }
2667
2668 //------------------------------------------------------------------------
2669 // genCreateAndStoreGCInfo: Create and record GC Info for the function.
2670 //
2671 void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize,
2672                                       unsigned prologSize,
2673                                       unsigned epilogSize DEBUGARG(void* codePtr))
2674 {
2675     IAllocator*    allowZeroAlloc = new (compiler, CMK_GC) AllowZeroAllocator(compiler->getAllocatorGC());
2676     GcInfoEncoder* gcInfoEncoder  = new (compiler, CMK_GC)
2677         GcInfoEncoder(compiler->info.compCompHnd, compiler->info.compMethodInfo, allowZeroAlloc, NOMEM);
2678     assert(gcInfoEncoder != nullptr);
2679
2680     // Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
2681     gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
2682
2683     // We keep the call count for the second call to gcMakeRegPtrTable() below.
2684     unsigned callCnt = 0;
2685
2686     // First we figure out the encoder ID's for the stack slots and registers.
2687     gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
2688
2689     // Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
2690     gcInfoEncoder->FinalizeSlotIds();
2691
2692     // Now we can actually use those slot ID's to declare live ranges.
2693     gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
2694
2695 #ifdef _TARGET_ARM64_
2696
2697     if (compiler->opts.compDbgEnC)
2698     {
2699         // what we have to preserve is called the "frame header" (see comments in VM\eetwain.cpp)
2700         // which is:
2701         //  -return address
2702         //  -saved off RBP
2703         //  -saved 'this' pointer and bool for synchronized methods
2704
2705         // 4 slots for RBP + return address + RSI + RDI
2706         int preservedAreaSize = 4 * REGSIZE_BYTES;
2707
2708         if (compiler->info.compFlags & CORINFO_FLG_SYNCH)
2709         {
2710             if (!(compiler->info.compFlags & CORINFO_FLG_STATIC))
2711                 preservedAreaSize += REGSIZE_BYTES;
2712
2713             preservedAreaSize += 1; // bool for synchronized methods
2714         }
2715
2716         // Used to signal both that the method is compiled for EnC, and also the size of the block at the top of the
2717         // frame
2718         gcInfoEncoder->SetSizeOfEditAndContinuePreservedArea(preservedAreaSize);
2719     }
2720
2721 #endif // _TARGET_ARM64_
2722
2723     gcInfoEncoder->Build();
2724
2725     // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
2726     // let's save the values anyway for debugging purposes
2727     compiler->compInfoBlkAddr = gcInfoEncoder->Emit();
2728     compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface
2729 }
2730
2731 //-------------------------------------------------------------------------------------------
2732 // genJumpKindsForTree:  Determine the number and kinds of conditional branches
2733 //                       necessary to implement the given GT_CMP node
2734 //
2735 // Arguments:
2736 //   cmpTree           - (input) The GenTree node that is used to set the Condition codes
2737 //                     - The GenTree Relop node that was used to set the Condition codes
2738 //   jmpKind[2]        - (output) One or two conditional branch instructions
2739 //   jmpToTrueLabel[2] - (output) On Arm64 both branches will always branch to the true label
2740 //
2741 // Return Value:
2742 //    Sets the proper values into the array elements of jmpKind[] and jmpToTrueLabel[]
2743 //
2744 // Assumptions:
2745 //    At least one conditional branch instruction will be returned.
2746 //    Typically only one conditional branch is needed
2747 //     and the second jmpKind[] value is set to EJ_NONE
2748 //
2749 void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2])
2750 {
2751     // On ARM both branches will always branch to the true label
2752     jmpToTrueLabel[0] = true;
2753     jmpToTrueLabel[1] = true;
2754
2755     // For integer comparisons just use genJumpKindForOper
2756     if (!varTypeIsFloating(cmpTree->gtOp.gtOp1))
2757     {
2758         CompareKind compareKind = ((cmpTree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
2759         jmpKind[0]              = genJumpKindForOper(cmpTree->gtOper, compareKind);
2760         jmpKind[1]              = EJ_NONE;
2761     }
2762     else // We have a Floating Point Compare operation
2763     {
2764         assert(cmpTree->OperIsCompare());
2765
2766         // For details on this mapping, see the ARM Condition Code table
2767         // at section A8.3   in the ARMv7 architecture manual or
2768         // at section C1.2.3 in the ARMV8 architecture manual.
2769
2770         // We must check the GTF_RELOP_NAN_UN to find out
2771         // if we need to branch when we have a NaN operand.
2772         //
2773         if ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) != 0)
2774         {
2775             // Must branch if we have an NaN, unordered
2776             switch (cmpTree->gtOper)
2777             {
2778                 case GT_EQ:
2779                     jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's)
2780                     jmpKind[1] = EJ_vs; // branch or set when we have a NaN
2781                     break;
2782
2783                 case GT_NE:
2784                     jmpKind[0] = EJ_ne; // branch or set when not equal (or have NaN's)
2785                     jmpKind[1] = EJ_NONE;
2786                     break;
2787
2788                 case GT_LT:
2789                     jmpKind[0] = EJ_lt; // branch or set when less than (or have NaN's)
2790                     jmpKind[1] = EJ_NONE;
2791                     break;
2792
2793                 case GT_LE:
2794                     jmpKind[0] = EJ_le; // branch or set when less than or equal (or have NaN's)
2795                     jmpKind[1] = EJ_NONE;
2796                     break;
2797
2798                 case GT_GT:
2799                     jmpKind[0] = EJ_hi; // branch or set when greater than (or have NaN's)
2800                     jmpKind[1] = EJ_NONE;
2801                     break;
2802
2803                 case GT_GE:
2804                     jmpKind[0] = EJ_hs; // branch or set when greater than or equal (or have NaN's)
2805                     jmpKind[1] = EJ_NONE;
2806                     break;
2807
2808                 default:
2809                     unreached();
2810             }
2811         }
2812         else // ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) == 0)
2813         {
2814             // Do not branch if we have an NaN, unordered
2815             switch (cmpTree->gtOper)
2816             {
2817                 case GT_EQ:
2818                     jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's)
2819                     jmpKind[1] = EJ_NONE;
2820                     break;
2821
2822                 case GT_NE:
2823                     jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's)
2824                     jmpKind[1] = EJ_lo; // branch or set when less than (and no NaN's)
2825                     break;
2826
2827                 case GT_LT:
2828                     jmpKind[0] = EJ_lo; // branch or set when less than (and no NaN's)
2829                     jmpKind[1] = EJ_NONE;
2830                     break;
2831
2832                 case GT_LE:
2833                     jmpKind[0] = EJ_ls; // branch or set when less than or equal (and no NaN's)
2834                     jmpKind[1] = EJ_NONE;
2835                     break;
2836
2837                 case GT_GT:
2838                     jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's)
2839                     jmpKind[1] = EJ_NONE;
2840                     break;
2841
2842                 case GT_GE:
2843                     jmpKind[0] = EJ_ge; // branch or set when greater than or equal (and no NaN's)
2844                     jmpKind[1] = EJ_NONE;
2845                     break;
2846
2847                 default:
2848                     unreached();
2849             }
2850         }
2851     }
2852 }
2853
2854 //------------------------------------------------------------------------
2855 // genCodeForJumpTrue: Generates code for jmpTrue statement.
2856 //
2857 // Arguments:
2858 //    tree - The GT_JTRUE tree node.
2859 //
2860 // Return Value:
2861 //    None
2862 //
2863 void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
2864 {
2865     GenTree* cmp = tree->gtOp.gtOp1;
2866     assert(cmp->OperIsCompare());
2867     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
2868
2869     // Get the "kind" and type of the comparison.  Note that whether it is an unsigned cmp
2870     // is governed by a flag NOT by the inherent type of the node
2871     emitJumpKind jumpKind[2];
2872     bool         branchToTrueLabel[2];
2873     genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
2874     assert(jumpKind[0] != EJ_NONE);
2875
2876     // On ARM the branches will always branch to the true label
2877     assert(branchToTrueLabel[0]);
2878     inst_JMP(jumpKind[0], compiler->compCurBB->bbJumpDest);
2879
2880     if (jumpKind[1] != EJ_NONE)
2881     {
2882         // the second conditional branch always has to be to the true label
2883         assert(branchToTrueLabel[1]);
2884         inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
2885     }
2886 }
2887
2888 #if defined(_TARGET_ARM_)
2889
2890 //------------------------------------------------------------------------
2891 // genCodeForJcc: Produce code for a GT_JCC node.
2892 //
2893 // Arguments:
2894 //    tree - the node
2895 //
2896 void CodeGen::genCodeForJcc(GenTreeCC* tree)
2897 {
2898     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
2899
2900     CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
2901     emitJumpKind jumpKind    = genJumpKindForOper(tree->gtCondition, compareKind);
2902
2903     inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
2904 }
2905
2906 //------------------------------------------------------------------------
2907 // genCodeForSetcc: Generates code for a GT_SETCC node.
2908 //
2909 // Arguments:
2910 //    setcc - the GT_SETCC node
2911 //
2912 // Assumptions:
2913 //    The condition represents an integer comparison. This code doesn't
2914 //    have the necessary logic to deal with floating point comparisons,
2915 //    in fact it doesn't even know if the comparison is integer or floating
2916 //    point because SETCC nodes do not have any operands.
2917 //
2918
2919 void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
2920 {
2921     regNumber    dstReg      = setcc->gtRegNum;
2922     CompareKind  compareKind = setcc->IsUnsigned() ? CK_UNSIGNED : CK_SIGNED;
2923     emitJumpKind jumpKind    = genJumpKindForOper(setcc->gtCondition, compareKind);
2924
2925     assert(genIsValidIntReg(dstReg));
2926     // Make sure nobody is setting GTF_RELOP_NAN_UN on this node as it is ignored.
2927     assert((setcc->gtFlags & GTF_RELOP_NAN_UN) == 0);
2928
2929     // Emit code like that:
2930     //   ...
2931     //   bgt True
2932     //   movs rD, #0
2933     //   b Next
2934     // True:
2935     //   movs rD, #1
2936     // Next:
2937     //   ...
2938
2939     BasicBlock* labelTrue = genCreateTempLabel();
2940     getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind), labelTrue);
2941
2942     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(setcc->TypeGet()), dstReg, 0);
2943
2944     BasicBlock* labelNext = genCreateTempLabel();
2945     getEmitter()->emitIns_J(INS_b, labelNext);
2946
2947     genDefineTempLabel(labelTrue);
2948     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(setcc->TypeGet()), dstReg, 1);
2949     genDefineTempLabel(labelNext);
2950
2951     genProduceReg(setcc);
2952 }
2953
2954 #endif // defined(_TARGET_ARM_)
2955
2956 //------------------------------------------------------------------------
2957 // genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
2958 //
2959 // Arguments:
2960 //    tree - the node
2961 //
2962 void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
2963 {
2964     assert(blkOp->OperIs(GT_STORE_OBJ, GT_STORE_DYN_BLK, GT_STORE_BLK));
2965
2966     if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
2967     {
2968         assert(blkOp->AsObj()->gtGcPtrCount != 0);
2969         genCodeForCpObj(blkOp->AsObj());
2970         return;
2971     }
2972
2973     if (blkOp->gtBlkOpGcUnsafe)
2974     {
2975         getEmitter()->emitDisableGC();
2976     }
2977     bool isCopyBlk = blkOp->OperIsCopyBlkOp();
2978
2979     switch (blkOp->gtBlkOpKind)
2980     {
2981         case GenTreeBlk::BlkOpKindHelper:
2982             if (isCopyBlk)
2983             {
2984                 genCodeForCpBlk(blkOp);
2985             }
2986             else
2987             {
2988                 genCodeForInitBlk(blkOp);
2989             }
2990             break;
2991
2992         case GenTreeBlk::BlkOpKindUnroll:
2993             if (isCopyBlk)
2994             {
2995                 genCodeForCpBlkUnroll(blkOp);
2996             }
2997             else
2998             {
2999                 genCodeForInitBlkUnroll(blkOp);
3000             }
3001             break;
3002
3003         default:
3004             unreached();
3005     }
3006
3007     if (blkOp->gtBlkOpGcUnsafe)
3008     {
3009         getEmitter()->emitEnableGC();
3010     }
3011 }
3012
3013 //------------------------------------------------------------------------
3014 // genScaledAdd: A helper for genLeaInstruction.
3015 //
3016 void CodeGen::genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale)
3017 {
3018     emitter* emit = getEmitter();
3019 #if defined(_TARGET_ARM_)
3020     emit->emitIns_R_R_R_I(INS_add, attr, targetReg, baseReg, indexReg, scale, INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
3021 #elif defined(_TARGET_ARM64_)
3022     emit->emitIns_R_R_R_I(INS_add, attr, targetReg, baseReg, indexReg, scale, INS_OPTS_LSL);
3023 #endif
3024 }
3025
3026 //------------------------------------------------------------------------
3027 // genLeaInstruction: Produce code for a GT_LEA node.
3028 //
3029 // Arguments:
3030 //    lea - the node
3031 //
3032 void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
3033 {
3034     genConsumeOperands(lea);
3035     emitter* emit   = getEmitter();
3036     emitAttr size   = emitTypeSize(lea);
3037     unsigned offset = lea->gtOffset;
3038
3039     // In ARM we can only load addresses of the form:
3040     //
3041     // [Base + index*scale]
3042     // [Base + Offset]
3043     // [Literal] (PC-Relative)
3044     //
3045     // So for the case of a LEA node of the form [Base + Index*Scale + Offset] we will generate:
3046     // destReg = baseReg + indexReg * scale;
3047     // destReg = destReg + offset;
3048     //
3049     // TODO-ARM64-CQ: The purpose of the GT_LEA node is to directly reflect a single target architecture
3050     //             addressing mode instruction.  Currently we're 'cheating' by producing one or more
3051     //             instructions to generate the addressing mode so we need to modify lowering to
3052     //             produce LEAs that are a 1:1 relationship to the ARM64 architecture.
3053     if (lea->Base() && lea->Index())
3054     {
3055         GenTree* memBase = lea->Base();
3056         GenTree* index   = lea->Index();
3057         unsigned offset  = lea->gtOffset;
3058
3059         DWORD lsl;
3060
3061         assert(isPow2(lea->gtScale));
3062         BitScanForward(&lsl, lea->gtScale);
3063
3064         assert(lsl <= 4);
3065
3066         if (offset != 0)
3067         {
3068             regNumber tmpReg = lea->GetSingleTempReg();
3069
3070             if (emitter::emitIns_valid_imm_for_add(offset))
3071             {
3072                 if (lsl > 0)
3073                 {
3074                     // Generate code to set tmpReg = base + index*scale
3075                     genScaledAdd(size, tmpReg, memBase->gtRegNum, index->gtRegNum, lsl);
3076                 }
3077                 else // no scale
3078                 {
3079                     // Generate code to set tmpReg = base + index
3080                     emit->emitIns_R_R_R(INS_add, size, tmpReg, memBase->gtRegNum, index->gtRegNum);
3081                 }
3082
3083                 // Then compute target reg from [tmpReg + offset]
3084                 emit->emitIns_R_R_I(INS_add, size, lea->gtRegNum, tmpReg, offset);
3085             }
3086             else // large offset
3087             {
3088                 // First load/store tmpReg with the large offset constant
3089                 instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
3090                 // Then add the base register
3091                 //      rd = rd + base
3092                 emit->emitIns_R_R_R(INS_add, size, tmpReg, tmpReg, memBase->gtRegNum);
3093
3094                 noway_assert(tmpReg != index->gtRegNum);
3095
3096                 // Then compute target reg from [tmpReg + index*scale]
3097                 genScaledAdd(size, lea->gtRegNum, tmpReg, index->gtRegNum, lsl);
3098             }
3099         }
3100         else
3101         {
3102             if (lsl > 0)
3103             {
3104                 // Then compute target reg from [base + index*scale]
3105                 genScaledAdd(size, lea->gtRegNum, memBase->gtRegNum, index->gtRegNum, lsl);
3106             }
3107             else
3108             {
3109                 // Then compute target reg from [base + index]
3110                 emit->emitIns_R_R_R(INS_add, size, lea->gtRegNum, memBase->gtRegNum, index->gtRegNum);
3111             }
3112         }
3113     }
3114     else if (lea->Base())
3115     {
3116         GenTree* memBase = lea->Base();
3117
3118         if (emitter::emitIns_valid_imm_for_add(offset))
3119         {
3120             if (offset != 0)
3121             {
3122                 // Then compute target reg from [memBase + offset]
3123                 emit->emitIns_R_R_I(INS_add, size, lea->gtRegNum, memBase->gtRegNum, offset);
3124             }
3125             else // offset is zero
3126             {
3127                 emit->emitIns_R_R(INS_mov, size, lea->gtRegNum, memBase->gtRegNum);
3128             }
3129         }
3130         else
3131         {
3132             // We require a tmpReg to hold the offset
3133             regNumber tmpReg = lea->GetSingleTempReg();
3134
3135             // First load tmpReg with the large offset constant
3136             instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
3137
3138             // Then compute target reg from [memBase + tmpReg]
3139             emit->emitIns_R_R_R(INS_add, size, lea->gtRegNum, memBase->gtRegNum, tmpReg);
3140         }
3141     }
3142     else if (lea->Index())
3143     {
3144         // If we encounter a GT_LEA node without a base it means it came out
3145         // when attempting to optimize an arbitrary arithmetic expression during lower.
3146         // This is currently disabled in ARM64 since we need to adjust lower to account
3147         // for the simpler instructions ARM64 supports.
3148         // TODO-ARM64-CQ:  Fix this and let LEA optimize arithmetic trees too.
3149         assert(!"We shouldn't see a baseless address computation during CodeGen for ARM64");
3150     }
3151
3152     genProduceReg(lea);
3153 }
3154
3155 //------------------------------------------------------------------------
3156 // isStructReturn: Returns whether the 'treeNode' is returning a struct.
3157 //
3158 // Arguments:
3159 //    treeNode - The tree node to evaluate whether is a struct return.
3160 //
3161 // Return Value:
3162 //    Returns true if the 'treeNode" is a GT_RETURN node of type struct.
3163 //    Otherwise returns false.
3164 //
3165 bool CodeGen::isStructReturn(GenTreePtr treeNode)
3166 {
3167     // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN.
3168     // For the GT_RET_FILT, the return is always
3169     // a bool or a void, for the end of a finally block.
3170     noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
3171
3172     return varTypeIsStruct(treeNode);
3173 }
3174
3175 //------------------------------------------------------------------------
3176 // genStructReturn: Generates code for returning a struct.
3177 //
3178 // Arguments:
3179 //    treeNode - The GT_RETURN tree node.
3180 //
3181 // Return Value:
3182 //    None
3183 //
3184 // Assumption:
3185 //    op1 of GT_RETURN node is either GT_LCL_VAR or multi-reg GT_CALL
3186 void CodeGen::genStructReturn(GenTreePtr treeNode)
3187 {
3188     assert(treeNode->OperGet() == GT_RETURN);
3189     assert(isStructReturn(treeNode));
3190     GenTreePtr op1 = treeNode->gtGetOp1();
3191
3192     if (op1->OperGet() == GT_LCL_VAR)
3193     {
3194         GenTreeLclVarCommon* lclVar  = op1->AsLclVarCommon();
3195         LclVarDsc*           varDsc  = &(compiler->lvaTable[lclVar->gtLclNum]);
3196         var_types            lclType = genActualType(varDsc->TypeGet());
3197
3198         // Currently only multireg TYP_STRUCT types such as HFA's(ARM32, ARM64) and 16-byte structs(ARM64) are supported
3199         // In the future we could have FEATURE_SIMD types like TYP_SIMD16
3200         assert(lclType == TYP_STRUCT);
3201         assert(varDsc->lvIsMultiRegRet);
3202
3203         ReturnTypeDesc retTypeDesc;
3204         unsigned       regCount;
3205
3206         retTypeDesc.InitializeStructReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle());
3207         regCount = retTypeDesc.GetReturnRegCount();
3208
3209         assert(regCount >= 2);
3210         assert(op1->isContained());
3211
3212         // Copy var on stack into ABI return registers
3213         // TODO: It could be optimized by reducing two float loading to one double
3214         int offset = 0;
3215         for (unsigned i = 0; i < regCount; ++i)
3216         {
3217             var_types type = retTypeDesc.GetReturnRegType(i);
3218             regNumber reg  = retTypeDesc.GetABIReturnReg(i);
3219             getEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), reg, lclVar->gtLclNum, offset);
3220             offset += genTypeSize(type);
3221         }
3222     }
3223     else // op1 must be multi-reg GT_CALL
3224     {
3225 #ifdef _TARGET_ARM_
3226         NYI_ARM("struct return from multi-reg GT_CALL");
3227 #endif
3228         assert(op1->IsMultiRegCall() || op1->IsCopyOrReloadOfMultiRegCall());
3229
3230         genConsumeRegs(op1);
3231
3232         GenTree*     actualOp1 = op1->gtSkipReloadOrCopy();
3233         GenTreeCall* call      = actualOp1->AsCall();
3234
3235         ReturnTypeDesc* pRetTypeDesc;
3236         unsigned        regCount;
3237         unsigned        matchingCount = 0;
3238
3239         pRetTypeDesc = call->GetReturnTypeDesc();
3240         regCount     = pRetTypeDesc->GetReturnRegCount();
3241
3242         var_types regType[MAX_RET_REG_COUNT];
3243         regNumber returnReg[MAX_RET_REG_COUNT];
3244         regNumber allocatedReg[MAX_RET_REG_COUNT];
3245         regMaskTP srcRegsMask       = 0;
3246         regMaskTP dstRegsMask       = 0;
3247         bool      needToShuffleRegs = false; // Set to true if we have to move any registers
3248
3249         for (unsigned i = 0; i < regCount; ++i)
3250         {
3251             regType[i]   = pRetTypeDesc->GetReturnRegType(i);
3252             returnReg[i] = pRetTypeDesc->GetABIReturnReg(i);
3253
3254             regNumber reloadReg = REG_NA;
3255             if (op1->IsCopyOrReload())
3256             {
3257                 // GT_COPY/GT_RELOAD will have valid reg for those positions
3258                 // that need to be copied or reloaded.
3259                 reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i);
3260             }
3261
3262             if (reloadReg != REG_NA)
3263             {
3264                 allocatedReg[i] = reloadReg;
3265             }
3266             else
3267             {
3268                 allocatedReg[i] = call->GetRegNumByIdx(i);
3269             }
3270
3271             if (returnReg[i] == allocatedReg[i])
3272             {
3273                 matchingCount++;
3274             }
3275             else // We need to move this value
3276             {
3277                 // We want to move the value from allocatedReg[i] into returnReg[i]
3278                 // so record these two registers in the src and dst masks
3279                 //
3280                 srcRegsMask |= genRegMask(allocatedReg[i]);
3281                 dstRegsMask |= genRegMask(returnReg[i]);
3282
3283                 needToShuffleRegs = true;
3284             }
3285         }
3286
3287         if (needToShuffleRegs)
3288         {
3289             assert(matchingCount < regCount);
3290
3291             unsigned  remainingRegCount = regCount - matchingCount;
3292             regMaskTP extraRegMask      = treeNode->gtRsvdRegs;
3293
3294             while (remainingRegCount > 0)
3295             {
3296                 // set 'available' to the 'dst' registers that are not currently holding 'src' registers
3297                 //
3298                 regMaskTP availableMask = dstRegsMask & ~srcRegsMask;
3299
3300                 regMaskTP dstMask;
3301                 regNumber srcReg;
3302                 regNumber dstReg;
3303                 var_types curType   = TYP_UNKNOWN;
3304                 regNumber freeUpReg = REG_NA;
3305
3306                 if (availableMask == 0)
3307                 {
3308                     // Circular register dependencies
3309                     // So just free up the lowest register in dstRegsMask by moving it to the 'extra' register
3310
3311                     assert(dstRegsMask == srcRegsMask);         // this has to be true for us to reach here
3312                     assert(extraRegMask != 0);                  // we require an 'extra' register
3313                     assert((extraRegMask & ~dstRegsMask) != 0); // it can't be part of dstRegsMask
3314
3315                     availableMask = extraRegMask & ~dstRegsMask;
3316
3317                     regMaskTP srcMask = genFindLowestBit(srcRegsMask);
3318                     freeUpReg         = genRegNumFromMask(srcMask);
3319                 }
3320
3321                 dstMask = genFindLowestBit(availableMask);
3322                 dstReg  = genRegNumFromMask(dstMask);
3323                 srcReg  = REG_NA;
3324
3325                 if (freeUpReg != REG_NA)
3326                 {
3327                     // We will free up the srcReg by moving it to dstReg which is an extra register
3328                     //
3329                     srcReg = freeUpReg;
3330
3331                     // Find the 'srcReg' and set 'curType', change allocatedReg[] to dstReg
3332                     // and add the new register mask bit to srcRegsMask
3333                     //
3334                     for (unsigned i = 0; i < regCount; ++i)
3335                     {
3336                         if (allocatedReg[i] == srcReg)
3337                         {
3338                             curType         = regType[i];
3339                             allocatedReg[i] = dstReg;
3340                             srcRegsMask |= genRegMask(dstReg);
3341                         }
3342                     }
3343                 }
3344                 else // The normal case
3345                 {
3346                     // Find the 'srcReg' and set 'curType'
3347                     //
3348                     for (unsigned i = 0; i < regCount; ++i)
3349                     {
3350                         if (returnReg[i] == dstReg)
3351                         {
3352                             srcReg  = allocatedReg[i];
3353                             curType = regType[i];
3354                         }
3355                     }
3356                     // After we perform this move we will have one less registers to setup
3357                     remainingRegCount--;
3358                 }
3359                 assert(curType != TYP_UNKNOWN);
3360
3361                 inst_RV_RV(ins_Copy(curType), dstReg, srcReg, curType);
3362
3363                 // Clear the appropriate bits in srcRegsMask and dstRegsMask
3364                 srcRegsMask &= ~genRegMask(srcReg);
3365                 dstRegsMask &= ~genRegMask(dstReg);
3366
3367             } // while (remainingRegCount > 0)
3368
3369         } // (needToShuffleRegs)
3370
3371     } // op1 must be multi-reg GT_CALL
3372 }
3373 #endif // _TARGET_ARMARCH_
3374
3375 #endif // !LEGACY_BACKEND