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