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