Merge pull request #11083 from AndyAyersMS/FixNonDevUseOfCheckProjects
[platform/upstream/coreclr.git] / src / jit / codegenarm.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 Code Generator                                 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_ARM_
21 #include "codegen.h"
22 #include "lower.h"
23 #include "gcinfo.h"
24 #include "emit.h"
25
26 //------------------------------------------------------------------------
27 // genCallFinally: Generate a call to the finally block.
28 //
29 BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
30 {
31     BasicBlock* bbFinallyRet = nullptr;
32
33     // We don't have retless calls, since we use the BBJ_ALWAYS to point at a NOP pad where
34     // we would have otherwise created retless calls.
35     assert(block->isBBCallAlwaysPair());
36
37     assert(block->bbNext != NULL);
38     assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
39     assert(block->bbNext->bbJumpDest != NULL);
40     assert(block->bbNext->bbJumpDest->bbFlags & BBF_FINALLY_TARGET);
41
42     bbFinallyRet = block->bbNext->bbJumpDest;
43     bbFinallyRet->bbFlags |= BBF_JMP_TARGET;
44
45     // Load the address where the finally funclet should return into LR.
46     // The funclet prolog/epilog will do "push {lr}" / "pop {pc}" to do the return.
47     getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
48     getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
49
50     // Jump to the finally BB
51     inst_JMP(EJ_jmp, block->bbJumpDest);
52
53     // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the
54     // jump target using bbJumpDest - that is already used to point
55     // to the finally block. So just skip past the BBJ_ALWAYS unless the
56     // block is RETLESS.
57     assert(!(block->bbFlags & BBF_RETLESS_CALL));
58     assert(block->isBBCallAlwaysPair());
59     return block->bbNext;
60 }
61
62 //------------------------------------------------------------------------
63 // genEHCatchRet:
64 void CodeGen::genEHCatchRet(BasicBlock* block)
65 {
66     getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_INTRET);
67     getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_INTRET);
68 }
69
70 //------------------------------------------------------------------------
71 // instGen_Set_Reg_To_Imm: Move an immediate value into an integer register.
72 //
73 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
74 {
75     // reg cannot be a FP register
76     assert(!genIsValidFloatReg(reg));
77
78     if (!compiler->opts.compReloc)
79     {
80         size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
81     }
82
83     if (EA_IS_RELOC(size))
84     {
85         getEmitter()->emitIns_R_I(INS_movw, size, reg, imm);
86         getEmitter()->emitIns_R_I(INS_movt, size, reg, imm);
87     }
88     else if (imm == 0)
89     {
90         instGen_Set_Reg_To_Zero(size, reg, flags);
91     }
92     else
93     {
94         if (arm_Valid_Imm_For_Mov(imm))
95         {
96             getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
97         }
98         else // We have to use a movw/movt pair of instructions
99         {
100             ssize_t imm_lo16 = (imm & 0xffff);
101             ssize_t imm_hi16 = (imm >> 16) & 0xffff;
102
103             assert(arm_Valid_Imm_For_Mov(imm_lo16));
104             assert(imm_hi16 != 0);
105
106             getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
107
108             // If we've got a low register, the high word is all bits set,
109             // and the high bit of the low word is set, we can sign extend
110             // halfword and save two bytes of encoding. This can happen for
111             // small magnitude negative numbers 'n' for -32768 <= n <= -1.
112
113             if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
114             {
115                 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
116             }
117             else
118             {
119                 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
120             }
121
122             if (flags == INS_FLAGS_SET)
123                 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
124         }
125     }
126
127     regTracker.rsTrackRegIntCns(reg, imm);
128 }
129
130 //------------------------------------------------------------------------
131 // genSetRegToConst: Generate code to set a register 'targetReg' of type 'targetType'
132 //    to the constant specified by the constant (GT_CNS_INT or GT_CNS_DBL) in 'tree'.
133 //
134 // Notes:
135 //    This does not call genProduceReg() on the target register.
136 //
137 void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTreePtr tree)
138 {
139     switch (tree->gtOper)
140     {
141         case GT_CNS_INT:
142         {
143             // relocatable values tend to come down as a CNS_INT of native int type
144             // so the line between these two opcodes is kind of blurry
145             GenTreeIntConCommon* con    = tree->AsIntConCommon();
146             ssize_t              cnsVal = con->IconValue();
147
148             bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
149             if (needReloc)
150             {
151                 instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
152                 regTracker.rsTrackRegTrash(targetReg);
153             }
154             else
155             {
156                 genSetRegToIcon(targetReg, cnsVal, targetType);
157             }
158         }
159         break;
160
161         case GT_CNS_DBL:
162         {
163             GenTreeDblCon* dblConst   = tree->AsDblCon();
164             double         constValue = dblConst->gtDblCon.gtDconVal;
165             // TODO-ARM-CQ: Do we have a faster/smaller way to generate 0.0 in thumb2 ISA ?
166             if (targetType == TYP_FLOAT)
167             {
168                 // Get a temp integer register
169                 regNumber tmpReg = tree->GetSingleTempReg();
170
171                 float f = forceCastToFloat(constValue);
172                 genSetRegToIcon(tmpReg, *((int*)(&f)));
173                 getEmitter()->emitIns_R_R(INS_vmov_i2f, EA_4BYTE, targetReg, tmpReg);
174             }
175             else
176             {
177                 assert(targetType == TYP_DOUBLE);
178
179                 unsigned* cv = (unsigned*)&constValue;
180
181                 // Get two temp integer registers
182                 regNumber tmpReg1 = tree->ExtractTempReg();
183                 regNumber tmpReg2 = tree->GetSingleTempReg();
184
185                 genSetRegToIcon(tmpReg1, cv[0]);
186                 genSetRegToIcon(tmpReg2, cv[1]);
187
188                 getEmitter()->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, tmpReg1, tmpReg2);
189             }
190         }
191         break;
192
193         default:
194             unreached();
195     }
196 }
197
198 //------------------------------------------------------------------------
199 // genCodeForBinary: Generate code for many binary arithmetic operators
200 // This method is expected to have called genConsumeOperands() before calling it.
201 //
202 // Arguments:
203 //    treeNode - The binary operation for which we are generating code.
204 //
205 // Return Value:
206 //    None.
207 //
208 // Notes:
209 //    Mul and div are not handled here.
210 //    See the assert below for the operators that are handled.
211
212 void CodeGen::genCodeForBinary(GenTree* treeNode)
213 {
214     const genTreeOps oper       = treeNode->OperGet();
215     regNumber        targetReg  = treeNode->gtRegNum;
216     var_types        targetType = treeNode->TypeGet();
217     emitter*         emit       = getEmitter();
218
219     assert(oper == GT_ADD || oper == GT_SUB || oper == GT_ADD_LO || oper == GT_ADD_HI || oper == GT_SUB_LO ||
220            oper == GT_SUB_HI || oper == GT_OR || oper == GT_XOR || oper == GT_AND);
221
222     if ((oper == GT_ADD || oper == GT_SUB || oper == GT_ADD_HI || oper == GT_SUB_HI) && treeNode->gtOverflow())
223     {
224         // This is also checked in the importer.
225         NYI("Overflow not yet implemented");
226     }
227
228     GenTreePtr op1 = treeNode->gtGetOp1();
229     GenTreePtr op2 = treeNode->gtGetOp2();
230
231     instruction ins = genGetInsForOper(oper, targetType);
232
233     // The arithmetic node must be sitting in a register (since it's not contained)
234     noway_assert(targetReg != REG_NA);
235
236     if ((oper == GT_ADD_LO || oper == GT_SUB_LO))
237     {
238         // During decomposition, all operands become reg
239         assert(!op1->isContained() && !op2->isContained());
240         emit->emitIns_R_R_R(ins, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum, op2->gtRegNum,
241                             INS_FLAGS_SET);
242     }
243     else
244     {
245         regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2);
246         assert(r == targetReg);
247     }
248
249     genProduceReg(treeNode);
250 }
251
252 //------------------------------------------------------------------------
253 // genReturn: Generates code for return statement.
254 //            In case of struct return, delegates to the genStructReturn method.
255 //
256 // Arguments:
257 //    treeNode - The GT_RETURN or GT_RETFILT tree node.
258 //
259 // Return Value:
260 //    None
261 //
262 void CodeGen::genReturn(GenTreePtr treeNode)
263 {
264     assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
265     GenTreePtr op1        = treeNode->gtGetOp1();
266     var_types  targetType = treeNode->TypeGet();
267
268 #ifdef DEBUG
269     if (targetType == TYP_VOID)
270     {
271         assert(op1 == nullptr);
272     }
273 #endif
274
275     if (treeNode->TypeGet() == TYP_LONG)
276     {
277         assert(op1 != nullptr);
278         noway_assert(op1->OperGet() == GT_LONG);
279         GenTree* loRetVal = op1->gtGetOp1();
280         GenTree* hiRetVal = op1->gtGetOp2();
281         noway_assert((loRetVal->gtRegNum != REG_NA) && (hiRetVal->gtRegNum != REG_NA));
282
283         genConsumeReg(loRetVal);
284         genConsumeReg(hiRetVal);
285         if (loRetVal->gtRegNum != REG_LNGRET_LO)
286         {
287             inst_RV_RV(ins_Copy(targetType), REG_LNGRET_LO, loRetVal->gtRegNum, TYP_INT);
288         }
289         if (hiRetVal->gtRegNum != REG_LNGRET_HI)
290         {
291             inst_RV_RV(ins_Copy(targetType), REG_LNGRET_HI, hiRetVal->gtRegNum, TYP_INT);
292         }
293     }
294     else
295     {
296         if (varTypeIsStruct(treeNode))
297         {
298             NYI_ARM("struct return");
299         }
300         else if (targetType != TYP_VOID)
301         {
302             assert(op1 != nullptr);
303             noway_assert(op1->gtRegNum != REG_NA);
304
305             // !! NOTE !! genConsumeReg will clear op1 as GC ref after it has
306             // consumed a reg for the operand. This is because the variable
307             // is dead after return. But we are issuing more instructions
308             // like "profiler leave callback" after this consumption. So
309             // if you are issuing more instructions after this point,
310             // remember to keep the variable live up until the new method
311             // exit point where it is actually dead.
312             genConsumeReg(op1);
313
314             regNumber retReg = varTypeIsFloating(treeNode) ? REG_FLOATRET : REG_INTRET;
315             if (op1->gtRegNum != retReg)
316             {
317                 inst_RV_RV(ins_Move_Extend(targetType, true), retReg, op1->gtRegNum, targetType);
318             }
319         }
320     }
321 }
322
323 //------------------------------------------------------------------------
324 // genCodeForTreeNode Generate code for a single node in the tree.
325 //
326 // Preconditions:
327 //    All operands have been evaluated.
328 //
329 void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
330 {
331     regNumber targetReg  = treeNode->gtRegNum;
332     var_types targetType = treeNode->TypeGet();
333     emitter*  emit       = getEmitter();
334
335 #ifdef DEBUG
336     lastConsumedNode = nullptr;
337     if (compiler->verbose)
338     {
339         unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
340         compiler->gtDispLIRNode(treeNode, "Generating: ");
341     }
342 #endif
343
344     // contained nodes are part of their parents for codegen purposes
345     // ex : immediates, most LEAs
346     if (treeNode->isContained())
347     {
348         return;
349     }
350
351     switch (treeNode->gtOper)
352     {
353         case GT_LCLHEAP:
354             genLclHeap(treeNode);
355             break;
356
357         case GT_CNS_INT:
358         case GT_CNS_DBL:
359             genSetRegToConst(targetReg, targetType, treeNode);
360             genProduceReg(treeNode);
361             break;
362
363         case GT_NOT:
364             assert(!varTypeIsFloating(targetType));
365
366             __fallthrough;
367
368         case GT_NEG:
369         {
370             instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
371
372             // The arithmetic node must be sitting in a register (since it's not contained)
373             assert(!treeNode->isContained());
374             // The dst can only be a register.
375             assert(targetReg != REG_NA);
376
377             GenTreePtr operand = treeNode->gtGetOp1();
378             assert(!operand->isContained());
379             // The src must be a register.
380             regNumber operandReg = genConsumeReg(operand);
381
382             if (ins == INS_vneg)
383             {
384                 getEmitter()->emitIns_R_R(ins, emitTypeSize(treeNode), targetReg, operandReg);
385             }
386             else
387             {
388                 getEmitter()->emitIns_R_R_I(ins, emitTypeSize(treeNode), targetReg, operandReg, 0);
389             }
390         }
391             genProduceReg(treeNode);
392             break;
393
394         case GT_OR:
395         case GT_XOR:
396         case GT_AND:
397             assert(varTypeIsIntegralOrI(treeNode));
398             __fallthrough;
399
400         case GT_ADD_LO:
401         case GT_ADD_HI:
402         case GT_SUB_LO:
403         case GT_SUB_HI:
404         case GT_ADD:
405         case GT_SUB:
406             genConsumeOperands(treeNode->AsOp());
407             genCodeForBinary(treeNode);
408             break;
409
410         case GT_MUL:
411         {
412             genConsumeOperands(treeNode->AsOp());
413
414             const genTreeOps oper = treeNode->OperGet();
415             if (treeNode->gtOverflow())
416             {
417                 // This is also checked in the importer.
418                 NYI("Overflow not yet implemented");
419             }
420
421             GenTreePtr  op1 = treeNode->gtGetOp1();
422             GenTreePtr  op2 = treeNode->gtGetOp2();
423             instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
424
425             // The arithmetic node must be sitting in a register (since it's not contained)
426             noway_assert(targetReg != REG_NA);
427
428             regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2);
429             assert(r == targetReg);
430         }
431             genProduceReg(treeNode);
432             break;
433
434         case GT_LSH:
435         case GT_RSH:
436         case GT_RSZ:
437         case GT_ROR:
438             genCodeForShift(treeNode);
439             break;
440
441         case GT_LSH_HI:
442         case GT_RSH_LO:
443             genCodeForShiftLong(treeNode);
444             break;
445
446         case GT_CAST:
447             // Cast is never contained (?)
448             noway_assert(targetReg != REG_NA);
449
450             if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
451             {
452                 // Casts float/double <--> double/float
453                 genFloatToFloatCast(treeNode);
454             }
455             else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
456             {
457                 // Casts float/double --> int32/int64
458                 genFloatToIntCast(treeNode);
459             }
460             else if (varTypeIsFloating(targetType))
461             {
462                 // Casts int32/uint32/int64/uint64 --> float/double
463                 genIntToFloatCast(treeNode);
464             }
465             else
466             {
467                 // Casts int <--> int
468                 genIntToIntCast(treeNode);
469             }
470             // The per-case functions call genProduceReg()
471             break;
472
473         case GT_LCL_VAR:
474         {
475             GenTreeLclVarCommon* lcl = treeNode->AsLclVarCommon();
476             // lcl_vars are not defs
477             assert((treeNode->gtFlags & GTF_VAR_DEF) == 0);
478
479             bool isRegCandidate = compiler->lvaTable[lcl->gtLclNum].lvIsRegCandidate();
480
481             if (isRegCandidate && !(treeNode->gtFlags & GTF_VAR_DEATH))
482             {
483                 assert((treeNode->InReg()) || (treeNode->gtFlags & GTF_SPILLED));
484             }
485
486             // If this is a register candidate that has been spilled, genConsumeReg() will
487             // reload it at the point of use.  Otherwise, if it's not in a register, we load it here.
488
489             if (!treeNode->InReg() && !(treeNode->gtFlags & GTF_SPILLED))
490             {
491                 assert(!isRegCandidate);
492                 emit->emitIns_R_S(ins_Load(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode->gtRegNum,
493                                   lcl->gtLclNum, 0);
494                 genProduceReg(treeNode);
495             }
496         }
497         break;
498
499         case GT_LCL_FLD_ADDR:
500         case GT_LCL_VAR_ADDR:
501         {
502             // Address of a local var.  This by itself should never be allocated a register.
503             // If it is worth storing the address in a register then it should be cse'ed into
504             // a temp and that would be allocated a register.
505             noway_assert(targetType == TYP_BYREF);
506             noway_assert(!treeNode->InReg());
507
508             inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
509         }
510             genProduceReg(treeNode);
511             break;
512
513         case GT_LCL_FLD:
514         {
515             NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported");
516             NYI_IF(treeNode->gtRegNum == REG_NA, "GT_LCL_FLD: load local field not into a register is not supported");
517
518             emitAttr size   = emitTypeSize(targetType);
519             unsigned offs   = treeNode->gtLclFld.gtLclOffs;
520             unsigned varNum = treeNode->gtLclVarCommon.gtLclNum;
521             assert(varNum < compiler->lvaCount);
522
523             emit->emitIns_R_S(ins_Move_Extend(targetType, treeNode->InReg()), size, targetReg, varNum, offs);
524         }
525             genProduceReg(treeNode);
526             break;
527
528         case GT_STORE_LCL_FLD:
529         {
530             noway_assert(targetType != TYP_STRUCT);
531
532             // record the offset
533             unsigned offset = treeNode->gtLclFld.gtLclOffs;
534
535             // We must have a stack store with GT_STORE_LCL_FLD
536             noway_assert(!treeNode->InReg());
537             noway_assert(targetReg == REG_NA);
538
539             GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
540             unsigned             varNum  = varNode->gtLclNum;
541             assert(varNum < compiler->lvaCount);
542             LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
543
544             // Ensure that lclVar nodes are typed correctly.
545             assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
546
547             GenTreePtr  data = treeNode->gtOp.gtOp1->gtEffectiveVal();
548             instruction ins  = ins_Store(targetType);
549             emitAttr    attr = emitTypeSize(targetType);
550             if (data->isContainedIntOrIImmed())
551             {
552                 assert(data->IsIntegralConst(0));
553                 NYI_ARM("st.lclFld contained operand");
554             }
555             else
556             {
557                 assert(!data->isContained());
558                 genConsumeReg(data);
559                 emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
560             }
561
562             genUpdateLife(varNode);
563             varDsc->lvRegNum = REG_STK;
564         }
565         break;
566
567         case GT_STORE_LCL_VAR:
568         {
569             GenTreeLclVarCommon* varNode = treeNode->AsLclVarCommon();
570
571             unsigned varNum = varNode->gtLclNum;
572             assert(varNum < compiler->lvaCount);
573             LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
574             unsigned   offset = 0;
575
576             // Ensure that lclVar nodes are typed correctly.
577             assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
578
579             GenTreePtr data = treeNode->gtOp.gtOp1->gtEffectiveVal();
580
581             // var = call, where call returns a multi-reg return value
582             // case is handled separately.
583             if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
584             {
585                 genMultiRegCallStoreToLocal(treeNode);
586                 break;
587             }
588             else
589             {
590                 if (treeNode->TypeGet() == TYP_LONG)
591                 {
592                     genStoreLongLclVar(treeNode);
593                     break;
594                 }
595
596                 genConsumeRegs(data);
597
598                 regNumber dataReg = REG_NA;
599                 if (data->isContainedIntOrIImmed())
600                 {
601                     assert(data->IsIntegralConst(0));
602                     NYI_ARM("st.lclVar contained operand");
603                 }
604                 else
605                 {
606                     assert(!data->isContained());
607                     dataReg = data->gtRegNum;
608                 }
609                 assert(dataReg != REG_NA);
610
611                 if (targetReg == REG_NA) // store into stack based LclVar
612                 {
613                     inst_set_SV_var(varNode);
614
615                     instruction ins  = ins_Store(targetType);
616                     emitAttr    attr = emitTypeSize(targetType);
617
618                     emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
619
620                     genUpdateLife(varNode);
621
622                     varDsc->lvRegNum = REG_STK;
623                 }
624                 else // store into register (i.e move into register)
625                 {
626                     if (dataReg != targetReg)
627                     {
628                         // Assign into targetReg when dataReg (from op1) is not the same register
629                         inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
630                     }
631                     genProduceReg(treeNode);
632                 }
633             }
634         }
635         break;
636
637         case GT_RETFILT:
638             // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
639             // the return register, if it's not already there. The processing is the same as GT_RETURN.
640             if (targetType != TYP_VOID)
641             {
642                 // For filters, the IL spec says the result is type int32. Further, the only specified legal values
643                 // are 0 or 1, with the use of other values "undefined".
644                 assert(targetType == TYP_INT);
645             }
646
647             __fallthrough;
648
649         case GT_RETURN:
650             genReturn(treeNode);
651             break;
652
653         case GT_LEA:
654         {
655             // if we are here, it is the case where there is an LEA that cannot
656             // be folded into a parent instruction
657             GenTreeAddrMode* lea = treeNode->AsAddrMode();
658             genLeaInstruction(lea);
659         }
660         // genLeaInstruction calls genProduceReg()
661         break;
662
663         case GT_IND:
664             genConsumeAddress(treeNode->AsIndir()->Addr());
665             emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
666             genProduceReg(treeNode);
667             break;
668
669         case GT_MOD:
670         case GT_UDIV:
671         case GT_UMOD:
672             // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
673             // helper call by front-end.  Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
674             // on float/double args.
675             noway_assert(!varTypeIsFloating(treeNode));
676             __fallthrough;
677
678         case GT_DIV:
679         {
680             genConsumeOperands(treeNode->AsOp());
681
682             noway_assert(targetReg != REG_NA);
683
684             GenTreePtr  dst    = treeNode;
685             GenTreePtr  src1   = treeNode->gtGetOp1();
686             GenTreePtr  src2   = treeNode->gtGetOp2();
687             instruction ins    = genGetInsForOper(treeNode->OperGet(), targetType);
688             emitAttr    attr   = emitTypeSize(treeNode);
689             regNumber   result = REG_NA;
690
691             // dst can only be a reg
692             assert(!dst->isContained());
693
694             // src can be only reg
695             assert(!src1->isContained() || !src2->isContained());
696
697             if (varTypeIsFloating(targetType))
698             {
699                 // Floating point divide never raises an exception
700
701                 emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
702             }
703             else // an signed integer divide operation
704             {
705                 // TODO-ARM-Bug: handle zero division exception.
706
707                 emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
708             }
709
710             genProduceReg(treeNode);
711         }
712         break;
713
714         case GT_INTRINSIC:
715         {
716             genIntrinsic(treeNode);
717         }
718         break;
719
720         case GT_EQ:
721         case GT_NE:
722         case GT_LT:
723         case GT_LE:
724         case GT_GE:
725         case GT_GT:
726         {
727             // TODO-ARM-CQ: Check if we can use the currently set flags.
728             // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register
729             //         (signed < or >= where targetReg != REG_NA)
730
731             GenTreeOp* tree = treeNode->AsOp();
732             GenTreePtr op1  = tree->gtOp1->gtEffectiveVal();
733             GenTreePtr op2  = tree->gtOp2->gtEffectiveVal();
734
735             genConsumeIfReg(op1);
736             genConsumeIfReg(op2);
737
738             instruction ins = INS_cmp;
739             emitAttr    cmpAttr;
740             if (varTypeIsFloating(op1))
741             {
742                 assert(op1->TypeGet() == op2->TypeGet());
743                 ins     = INS_vcmp;
744                 cmpAttr = emitTypeSize(op1->TypeGet());
745                 emit->emitInsBinary(ins, cmpAttr, op1, op2);
746                 // vmrs with register 0xf has special meaning of transferring flags
747                 emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15);
748             }
749             else if (varTypeIsLong(op1))
750             {
751 #ifdef DEBUG
752                 // The result of an unlowered long compare on a 32-bit target must either be
753                 // a) materialized into a register, or
754                 // b) unused.
755                 //
756                 // A long compare that has a result that is used but not materialized into a register should
757                 // have been handled by Lowering::LowerCompare.
758
759                 LIR::Use use;
760                 assert((treeNode->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(treeNode, &use));
761 #endif
762                 genCompareLong(treeNode);
763                 break;
764             }
765             else
766             {
767                 var_types op1Type = op1->TypeGet();
768                 var_types op2Type = op2->TypeGet();
769                 assert(!varTypeIsFloating(op2Type));
770                 ins = INS_cmp;
771                 if (op1Type == op2Type)
772                 {
773                     cmpAttr = emitTypeSize(op1Type);
774                 }
775                 else
776                 {
777                     var_types cmpType    = TYP_INT;
778                     bool      op1Is64Bit = (varTypeIsLong(op1Type) || op1Type == TYP_REF);
779                     bool      op2Is64Bit = (varTypeIsLong(op2Type) || op2Type == TYP_REF);
780                     NYI_IF(op1Is64Bit || op2Is64Bit, "Long compare");
781                     assert(!op1->isUsedFromMemory() || op1Type == op2Type);
782                     assert(!op2->isUsedFromMemory() || op1Type == op2Type);
783                     cmpAttr = emitTypeSize(cmpType);
784                 }
785                 emit->emitInsBinary(ins, cmpAttr, op1, op2);
786             }
787
788             // Are we evaluating this into a register?
789             if (targetReg != REG_NA)
790             {
791                 genSetRegToCond(targetReg, tree);
792                 genProduceReg(tree);
793             }
794         }
795         break;
796
797         case GT_JTRUE:
798         {
799             GenTree* cmp = treeNode->gtOp.gtOp1->gtEffectiveVal();
800             assert(cmp->OperIsCompare());
801             assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
802
803             // Get the "kind" and type of the comparison.  Note that whether it is an unsigned cmp
804             // is governed by a flag NOT by the inherent type of the node
805             // TODO-ARM-CQ: Check if we can use the currently set flags.
806             CompareKind compareKind = ((cmp->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
807
808             emitJumpKind jmpKind   = genJumpKindForOper(cmp->gtOper, compareKind);
809             BasicBlock*  jmpTarget = compiler->compCurBB->bbJumpDest;
810
811             inst_JMP(jmpKind, jmpTarget);
812         }
813         break;
814
815         case GT_JCC:
816         {
817             GenTreeJumpCC* jcc = treeNode->AsJumpCC();
818
819             assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
820
821             CompareKind  compareKind = ((jcc->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
822             emitJumpKind jumpKind    = genJumpKindForOper(jcc->gtCondition, compareKind);
823
824             inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
825         }
826         break;
827
828         case GT_RETURNTRAP:
829         {
830             // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
831             // based on the contents of 'data'
832
833             GenTree* data = treeNode->gtOp.gtOp1->gtEffectiveVal();
834             genConsumeIfReg(data);
835             GenTreeIntCon cns = intForm(TYP_INT, 0);
836             emit->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
837
838             BasicBlock* skipLabel = genCreateTempLabel();
839
840             emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
841             inst_JMP(jmpEqual, skipLabel);
842             // emit the call to the EE-helper that stops for GC (or other reasons)
843
844             genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
845             genDefineTempLabel(skipLabel);
846         }
847         break;
848
849         case GT_STOREIND:
850         {
851             GenTreeStoreInd* storeInd   = treeNode->AsStoreInd();
852             GenTree*         data       = storeInd->Data();
853             GenTree*         addr       = storeInd->Addr();
854             var_types        targetType = storeInd->TypeGet();
855
856             assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
857
858             GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(treeNode, data);
859             if (writeBarrierForm != GCInfo::WBF_NoBarrier)
860             {
861                 // data and addr must be in registers.
862                 // Consume both registers so that any copies of interfering
863                 // registers are taken care of.
864                 genConsumeOperands(storeInd->AsOp());
865
866 #if NOGC_WRITE_BARRIERS
867                 NYI_ARM("NOGC_WRITE_BARRIERS");
868 #else
869                 // At this point, we should not have any interference.
870                 // That is, 'data' must not be in REG_ARG_0,
871                 //  as that is where 'addr' must go.
872                 noway_assert(data->gtRegNum != REG_ARG_0);
873
874                 // addr goes in REG_ARG_0
875                 if (addr->gtRegNum != REG_ARG_0)
876                 {
877                     inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
878                 }
879
880                 // data goes in REG_ARG_1
881                 if (data->gtRegNum != REG_ARG_1)
882                 {
883                     inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
884                 }
885 #endif // NOGC_WRITE_BARRIERS
886
887                 genGCWriteBarrier(storeInd, writeBarrierForm);
888             }
889             else // A normal store, not a WriteBarrier store
890             {
891                 bool reverseOps  = ((storeInd->gtFlags & GTF_REVERSE_OPS) != 0);
892                 bool dataIsUnary = false;
893
894                 // We must consume the operands in the proper execution order,
895                 // so that liveness is updated appropriately.
896                 if (!reverseOps)
897                 {
898                     genConsumeAddress(addr);
899                 }
900
901                 if (!data->isContained())
902                 {
903                     genConsumeRegs(data);
904                 }
905
906                 if (reverseOps)
907                 {
908                     genConsumeAddress(addr);
909                 }
910
911                 emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(storeInd), data->gtRegNum,
912                                          treeNode->AsIndir());
913             }
914         }
915         break;
916
917         case GT_COPY:
918             // This is handled at the time we call genConsumeReg() on the GT_COPY
919             break;
920
921         case GT_LIST:
922         case GT_FIELD_LIST:
923         case GT_ARGPLACE:
924             // Nothing to do
925             break;
926
927         case GT_PUTARG_STK:
928             genPutArgStk(treeNode->AsPutArgStk());
929             break;
930
931         case GT_PUTARG_REG:
932         {
933             NYI_IF(targetType == TYP_STRUCT, "GT_PUTARG_REG: struct support not implemented");
934
935             // commas show up here commonly, as part of a nullchk operation
936             GenTree* op1 = treeNode->gtOp.gtOp1->gtEffectiveVal();
937             // If child node is not already in the register we need, move it
938             genConsumeReg(op1);
939             if (treeNode->gtRegNum != op1->gtRegNum)
940             {
941                 inst_RV_RV(ins_Move_Extend(targetType, true), treeNode->gtRegNum, op1->gtRegNum, targetType);
942             }
943         }
944             genProduceReg(treeNode);
945             break;
946
947         case GT_CALL:
948             genCallInstruction(treeNode->AsCall());
949             break;
950
951         case GT_LOCKADD:
952         case GT_XCHG:
953         case GT_XADD:
954             genLockedInstructions(treeNode->AsOp());
955             break;
956
957         case GT_MEMORYBARRIER:
958             instGen_MemoryBarrier();
959             break;
960
961         case GT_CMPXCHG:
962         {
963             NYI("GT_CMPXCHG");
964         }
965             genProduceReg(treeNode);
966             break;
967
968         case GT_RELOAD:
969             // do nothing - reload is just a marker.
970             // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
971             // into the register specified in this node.
972             break;
973
974         case GT_NOP:
975             break;
976
977         case GT_NO_OP:
978             if (treeNode->gtFlags & GTF_NO_OP_NO)
979             {
980                 noway_assert(!"GTF_NO_OP_NO should not be set");
981             }
982             else
983             {
984                 instGen(INS_nop);
985             }
986             break;
987
988         case GT_ARR_BOUNDS_CHECK:
989             genRangeCheck(treeNode);
990             break;
991
992         case GT_PHYSREG:
993             if (treeNode->gtRegNum != treeNode->AsPhysReg()->gtSrcReg)
994             {
995                 inst_RV_RV(INS_mov, treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg, targetType);
996
997                 genTransferRegGCState(treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg);
998             }
999             break;
1000
1001         case GT_PHYSREGDST:
1002             break;
1003
1004         case GT_NULLCHECK:
1005         {
1006             assert(!treeNode->gtOp.gtOp1->isContained());
1007             regNumber addrReg = genConsumeReg(treeNode->gtOp.gtOp1);
1008             emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
1009         }
1010         break;
1011
1012         case GT_CATCH_ARG:
1013
1014             noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
1015
1016             /* Catch arguments get passed in a register. genCodeForBBlist()
1017                would have marked it as holding a GC object, but not used. */
1018
1019             noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
1020             genConsumeReg(treeNode);
1021             break;
1022
1023         case GT_PINVOKE_PROLOG:
1024             noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
1025
1026             // the runtime side requires the codegen here to be consistent
1027             emit->emitDisableRandomNops();
1028             break;
1029
1030         case GT_LABEL:
1031             genPendingCallLabel       = genCreateTempLabel();
1032             treeNode->gtLabel.gtLabBB = genPendingCallLabel;
1033             emit->emitIns_J_R(INS_adr, EA_PTRSIZE, genPendingCallLabel, treeNode->gtRegNum);
1034             break;
1035
1036         case GT_CLS_VAR_ADDR:
1037             emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
1038             genProduceReg(treeNode);
1039             break;
1040
1041         case GT_STORE_DYN_BLK:
1042         case GT_STORE_BLK:
1043             genCodeForStoreBlk(treeNode->AsBlk());
1044             break;
1045
1046         case GT_JMPTABLE:
1047             genJumpTable(treeNode);
1048             break;
1049
1050         case GT_SWITCH_TABLE:
1051             genTableBasedSwitch(treeNode);
1052             break;
1053
1054         case GT_ARR_INDEX:
1055             genCodeForArrIndex(treeNode->AsArrIndex());
1056             break;
1057
1058         case GT_ARR_OFFSET:
1059             genCodeForArrOffset(treeNode->AsArrOffs());
1060             break;
1061
1062         case GT_IL_OFFSET:
1063             // Do nothing; these nodes are simply markers for debug info.
1064             break;
1065
1066         default:
1067         {
1068 #ifdef DEBUG
1069             char message[256];
1070             _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
1071                         GenTree::NodeName(treeNode->OperGet()));
1072             NYIRAW(message);
1073 #else
1074             NYI("unimplemented node");
1075 #endif
1076         }
1077         break;
1078     }
1079 }
1080
1081 //------------------------------------------------------------------------
1082 // genLockedInstructions: Generate code for the locked operations.
1083 //
1084 // Notes:
1085 //    Handles GT_LOCKADD, GT_XCHG, GT_XADD nodes.
1086 //
1087 void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
1088 {
1089     NYI("genLockedInstructions");
1090 }
1091
1092 //--------------------------------------------------------------------------------------
1093 // genLclHeap: Generate code for localloc
1094 //
1095 // Description:
1096 //      There are 2 ways depending from build version to generate code for localloc:
1097 //          1) For debug build where memory should be initialized we generate loop
1098 //             which invoke push {tmpReg} N times.
1099 //          2) Fore /o build  However, we tickle the pages to ensure that SP is always
1100 //             valid and is in sync with the "stack guard page". Amount of iteration
1101 //             is N/PAGE_SIZE.
1102 //
1103 // Comments:
1104 //      There can be some optimization:
1105 //          1) It's not needed to generate loop for zero size allocation
1106 //          2) For small allocation (less than 4 store) we unroll loop
1107 //          3) For allocation less than PAGE_SIZE and when it's not needed to initialize
1108 //             memory to zero, we can just increment SP.
1109 //
1110 // Notes: Size N should be aligned to STACK_ALIGN before any allocation
1111 //
1112 void CodeGen::genLclHeap(GenTreePtr tree)
1113 {
1114     assert(tree->OperGet() == GT_LCLHEAP);
1115
1116     GenTreePtr size = tree->gtOp.gtOp1;
1117     noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
1118
1119     // Result of localloc will be returned in regCnt.
1120     // Also it used as temporary register in code generation
1121     // for storing allocation size
1122     regNumber   regCnt          = tree->gtRegNum;
1123     regNumber   pspSymReg       = REG_NA;
1124     var_types   type            = genActualType(size->gtType);
1125     emitAttr    easz            = emitTypeSize(type);
1126     BasicBlock* endLabel        = nullptr;
1127     BasicBlock* loop            = nullptr;
1128     unsigned    stackAdjustment = 0;
1129
1130 #ifdef DEBUG
1131     // Verify ESP
1132     if (compiler->opts.compStackCheckOnRet)
1133     {
1134         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
1135                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
1136                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
1137         getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
1138
1139         BasicBlock*  esp_check = genCreateTempLabel();
1140         emitJumpKind jmpEqual  = genJumpKindForOper(GT_EQ, CK_SIGNED);
1141         inst_JMP(jmpEqual, esp_check);
1142         getEmitter()->emitIns(INS_BREAKPOINT);
1143         genDefineTempLabel(esp_check);
1144     }
1145 #endif
1146
1147     noway_assert(isFramePointerUsed()); // localloc requires Frame Pointer to be established since SP changes
1148     noway_assert(genStackLevel == 0);   // Can't have anything on the stack
1149
1150     // Whether method has PSPSym.
1151     bool hasPspSym;
1152 #if FEATURE_EH_FUNCLETS
1153     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
1154 #else
1155     hasPspSym = false;
1156 #endif
1157
1158     // Check to 0 size allocations
1159     // size_t amount = 0;
1160     if (size->IsCnsIntOrI())
1161     {
1162         // If size is a constant, then it must be contained.
1163         assert(size->isContained());
1164
1165         // If amount is zero then return null in regCnt
1166         size_t amount = size->gtIntCon.gtIconVal;
1167         if (amount == 0)
1168         {
1169             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
1170             goto BAILOUT;
1171         }
1172     }
1173     else
1174     {
1175         // If 0 bail out by returning null in regCnt
1176         genConsumeRegAndCopy(size, regCnt);
1177         endLabel = genCreateTempLabel();
1178         getEmitter()->emitIns_R_R(INS_TEST, easz, regCnt, regCnt);
1179         emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1180         inst_JMP(jmpEqual, endLabel);
1181     }
1182
1183     stackAdjustment = 0;
1184 #if FEATURE_EH_FUNCLETS
1185     // If we have PSPsym, then need to re-locate it after localloc.
1186     if (hasPspSym)
1187     {
1188         stackAdjustment += STACK_ALIGN;
1189
1190         // Save a copy of PSPSym
1191         pspSymReg = tree->ExtractTempReg();
1192         getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
1193     }
1194 #endif
1195
1196 #if FEATURE_FIXED_OUT_ARGS
1197     // If we have an outgoing arg area then we must adjust the SP by popping off the
1198     // outgoing arg area. We will restore it right before we return from this method.
1199     if (compiler->lvaOutgoingArgSpaceSize > 0)
1200     {
1201         assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain
1202                                                                         // aligned
1203         inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
1204         stackAdjustment += compiler->lvaOutgoingArgSpaceSize;
1205     }
1206 #endif
1207
1208     // Put aligned allocation size to regCnt
1209     if (size->IsCnsIntOrI())
1210     {
1211         // 'amount' is the total number of bytes to localloc to properly STACK_ALIGN
1212         size_t amount = size->gtIntCon.gtIconVal;
1213         amount        = AlignUp(amount, STACK_ALIGN);
1214
1215         // For small allocations we will generate up to four stp instructions
1216         size_t cntStackAlignedWidthItems = (amount >> STACK_ALIGN_SHIFT);
1217         if (cntStackAlignedWidthItems <= 4)
1218         {
1219             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
1220
1221             while (cntStackAlignedWidthItems != 0)
1222             {
1223                 inst_IV(INS_push, (unsigned)genRegMask(regCnt));
1224                 cntStackAlignedWidthItems -= 1;
1225             }
1226
1227             goto ALLOC_DONE;
1228         }
1229         else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
1230         {
1231             // Since the size is a page or less, simply adjust the SP value
1232             // The SP might already be in the guard page, must touch it BEFORE
1233             // the alloc, not after.
1234             getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regCnt, REG_SP, 0);
1235             inst_RV_IV(INS_sub, REG_SP, amount, EA_PTRSIZE);
1236             goto ALLOC_DONE;
1237         }
1238
1239         // regCnt will be the total number of bytes to locAlloc
1240         genSetRegToIcon(regCnt, amount, ((int)amount == amount) ? TYP_INT : TYP_LONG);
1241     }
1242     else
1243     {
1244         // Round up the number of bytes to allocate to a STACK_ALIGN boundary.
1245         inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
1246         inst_RV_IV(INS_AND, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
1247     }
1248
1249     // Allocation
1250     if (compiler->info.compInitMem)
1251     {
1252         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
1253         // Since we have to zero out the allocated memory AND ensure that RSP is always valid
1254         // by tickling the pages, we will just push 0's on the stack.
1255
1256         regNumber regTmp = tree->ExtractTempReg();
1257         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regTmp);
1258
1259         // Loop:
1260         BasicBlock* loop = genCreateTempLabel();
1261         genDefineTempLabel(loop);
1262
1263         noway_assert(STACK_ALIGN == 8);
1264         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
1265         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
1266
1267         // If not done, loop
1268         // Note that regCnt is the number of bytes to stack allocate.
1269         assert(genIsValidIntReg(regCnt));
1270         getEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, regCnt, STACK_ALIGN, INS_FLAGS_SET);
1271         emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
1272         inst_JMP(jmpNotEqual, loop);
1273     }
1274     else
1275     {
1276         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
1277         //
1278         // We don't need to zero out the allocated memory. However, we do have
1279         // to tickle the pages to ensure that SP is always valid and is
1280         // in sync with the "stack guard page".  Note that in the worst
1281         // case SP is on the last byte of the guard page.  Thus you must
1282         // touch SP+0 first not SP+0x1000.
1283         //
1284         // Another subtlety is that you don't want SP to be exactly on the
1285         // boundary of the guard page because PUSH is predecrement, thus
1286         // call setup would not touch the guard page but just beyond it
1287         //
1288         // Note that we go through a few hoops so that SP never points to
1289         // illegal pages at any time during the ticking process
1290         //
1291         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
1292         //       jb    Loop                    // result is smaller than orignial SP (no wrap around)
1293         //       mov   regCnt, #0              // Overflow, pick lowest possible value
1294         //
1295         //  Loop:
1296         //       ldr   regTmp, [SP + 0]        // tickle the page - read from the page
1297         //       sub   regTmp, SP, PAGE_SIZE   // decrement SP by PAGE_SIZE
1298         //       cmp   regTmp, regCnt
1299         //       jb    Done
1300         //       mov   SP, regTmp
1301         //       j     Loop
1302         //
1303         //  Done:
1304         //       mov   SP, regCnt
1305         //
1306
1307         // Setup the regTmp
1308         regNumber regTmp = tree->ExtractTempReg();
1309
1310         BasicBlock* loop = genCreateTempLabel();
1311         BasicBlock* done = genCreateTempLabel();
1312
1313         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
1314         getEmitter()->emitIns_R_R_R(INS_sub, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt, INS_FLAGS_SET);
1315
1316         inst_JMP(EJ_vc, loop); // branch if the V flag is not set
1317
1318         // Ups... Overflow, set regCnt to lowest possible value
1319         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
1320
1321         genDefineTempLabel(loop);
1322
1323         // tickle the page - Read from the updated SP - this triggers a page fault when on the guard page
1324         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regTmp, REG_SPBASE, 0);
1325
1326         // decrement SP by PAGE_SIZE
1327         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());
1328
1329         getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
1330         emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
1331         inst_JMP(jmpLTU, done);
1332
1333         // Update SP to be at the next page of stack that we will tickle
1334         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
1335
1336         // Jump to loop and tickle new stack address
1337         inst_JMP(EJ_jmp, loop);
1338
1339         // Done with stack tickle loop
1340         genDefineTempLabel(done);
1341
1342         // Now just move the final value to SP
1343         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
1344     }
1345
1346 ALLOC_DONE:
1347     // Re-adjust SP to allocate PSPSym and out-going arg area
1348     if (stackAdjustment != 0)
1349     {
1350         assert((stackAdjustment % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
1351         assert(stackAdjustment > 0);
1352         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, (int)stackAdjustment);
1353
1354 #if FEATURE_EH_FUNCLETS
1355         // Write PSPSym to its new location.
1356         if (hasPspSym)
1357         {
1358             assert(genIsValidIntReg(pspSymReg));
1359             getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
1360         }
1361 #endif
1362         // Return the stackalloc'ed address in result register.
1363         // regCnt = RSP + stackAdjustment.
1364         getEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, regCnt, REG_SPBASE, (int)stackAdjustment);
1365     }
1366     else // stackAdjustment == 0
1367     {
1368         // Move the final value of SP to regCnt
1369         inst_RV_RV(INS_mov, regCnt, REG_SPBASE);
1370     }
1371
1372 BAILOUT:
1373     if (endLabel != nullptr)
1374         genDefineTempLabel(endLabel);
1375
1376     // Write the lvaLocAllocSPvar stack frame slot
1377     if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
1378     {
1379         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaLocAllocSPvar, 0);
1380     }
1381
1382 #if STACK_PROBES
1383     if (compiler->opts.compNeedStackProbes)
1384     {
1385         genGenerateStackProbe();
1386     }
1387 #endif
1388
1389 #ifdef DEBUG
1390     // Update new ESP
1391     if (compiler->opts.compStackCheckOnRet)
1392     {
1393         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
1394                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
1395                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
1396         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaReturnEspCheck, 0);
1397     }
1398 #endif
1399
1400     genProduceReg(tree);
1401 }
1402
1403 //------------------------------------------------------------------------
1404 // genTableBasedSwitch: generate code for a switch statement based on a table of ip-relative offsets
1405 //
1406 void CodeGen::genTableBasedSwitch(GenTree* treeNode)
1407 {
1408     genConsumeOperands(treeNode->AsOp());
1409     regNumber idxReg  = treeNode->gtOp.gtOp1->gtRegNum;
1410     regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
1411
1412     getEmitter()->emitIns_R_ARX(INS_ldr, EA_4BYTE, REG_PC, baseReg, idxReg, TARGET_POINTER_SIZE, 0);
1413 }
1414
1415 //------------------------------------------------------------------------
1416 // genJumpTable: emits the table and an instruction to get the address of the first element
1417 //
1418 void CodeGen::genJumpTable(GenTree* treeNode)
1419 {
1420     noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
1421     assert(treeNode->OperGet() == GT_JMPTABLE);
1422
1423     unsigned     jumpCount = compiler->compCurBB->bbJumpSwt->bbsCount;
1424     BasicBlock** jumpTable = compiler->compCurBB->bbJumpSwt->bbsDstTab;
1425     unsigned     jmpTabBase;
1426
1427     jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCount, false);
1428
1429     JITDUMP("\n      J_M%03u_DS%02u LABEL   DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
1430
1431     for (unsigned i = 0; i < jumpCount; i++)
1432     {
1433         BasicBlock* target = *jumpTable++;
1434         noway_assert(target->bbFlags & BBF_JMP_TARGET);
1435
1436         JITDUMP("            DD      L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
1437
1438         getEmitter()->emitDataGenData(i, target);
1439     }
1440
1441     getEmitter()->emitDataGenEnd();
1442
1443     getEmitter()->emitIns_R_D(INS_movw, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
1444     getEmitter()->emitIns_R_D(INS_movt, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
1445
1446     genProduceReg(treeNode);
1447 }
1448
1449 //------------------------------------------------------------------------
1450 // genGetInsForOper: Return instruction encoding of the operation tree.
1451 //
1452 instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
1453 {
1454     instruction ins;
1455
1456     if (varTypeIsFloating(type))
1457         return CodeGen::ins_MathOp(oper, type);
1458
1459     switch (oper)
1460     {
1461         case GT_ADD:
1462             ins = INS_add;
1463             break;
1464         case GT_AND:
1465             ins = INS_AND;
1466             break;
1467         case GT_MUL:
1468             ins = INS_MUL;
1469             break;
1470         case GT_DIV:
1471             ins = INS_sdiv;
1472             break;
1473         case GT_LSH:
1474             ins = INS_SHIFT_LEFT_LOGICAL;
1475             break;
1476         case GT_NEG:
1477             ins = INS_rsb;
1478             break;
1479         case GT_NOT:
1480             ins = INS_NOT;
1481             break;
1482         case GT_OR:
1483             ins = INS_OR;
1484             break;
1485         case GT_RSH:
1486             ins = INS_SHIFT_RIGHT_ARITHM;
1487             break;
1488         case GT_RSZ:
1489             ins = INS_SHIFT_RIGHT_LOGICAL;
1490             break;
1491         case GT_SUB:
1492             ins = INS_sub;
1493             break;
1494         case GT_XOR:
1495             ins = INS_XOR;
1496             break;
1497         case GT_ROR:
1498             ins = INS_ror;
1499             break;
1500         case GT_ADD_LO:
1501             ins = INS_add;
1502             break;
1503         case GT_ADD_HI:
1504             ins = INS_adc;
1505             break;
1506         case GT_SUB_LO:
1507             ins = INS_sub;
1508             break;
1509         case GT_SUB_HI:
1510             ins = INS_sbc;
1511             break;
1512         case GT_LSH_HI:
1513             ins = INS_SHIFT_LEFT_LOGICAL;
1514             break;
1515         case GT_RSH_LO:
1516             ins = INS_SHIFT_RIGHT_LOGICAL;
1517             break;
1518         default:
1519             unreached();
1520             break;
1521     }
1522     return ins;
1523 }
1524
1525 // Generates CpBlk code by performing a loop unroll
1526 // Preconditions:
1527 //  The size argument of the CpBlk node is a constant and <= 64 bytes.
1528 //  This may seem small but covers >95% of the cases in several framework assemblies.
1529 void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode)
1530 {
1531     NYI_ARM("genCodeForCpBlkUnroll");
1532 }
1533
1534 // Generate code for InitBlk by performing a loop unroll
1535 // Preconditions:
1536 //   a) Both the size and fill byte value are integer constants.
1537 //   b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
1538 void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
1539 {
1540     NYI_ARM("genCodeForInitBlkUnroll");
1541 }
1542
1543 void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
1544 {
1545     if (blkOp->gtBlkOpGcUnsafe)
1546     {
1547         getEmitter()->emitDisableGC();
1548     }
1549     bool isCopyBlk = blkOp->OperIsCopyBlkOp();
1550
1551     switch (blkOp->gtBlkOpKind)
1552     {
1553         case GenTreeBlk::BlkOpKindHelper:
1554             if (isCopyBlk)
1555             {
1556                 genCodeForCpBlk(blkOp);
1557             }
1558             else
1559             {
1560                 genCodeForInitBlk(blkOp);
1561             }
1562             break;
1563         case GenTreeBlk::BlkOpKindUnroll:
1564             if (isCopyBlk)
1565             {
1566                 genCodeForCpBlkUnroll(blkOp);
1567             }
1568             else
1569             {
1570                 genCodeForInitBlkUnroll(blkOp);
1571             }
1572             break;
1573         default:
1574             unreached();
1575     }
1576     if (blkOp->gtBlkOpGcUnsafe)
1577     {
1578         getEmitter()->emitEnableGC();
1579     }
1580 }
1581
1582 //------------------------------------------------------------------------
1583 // genCodeForShiftLong: Generates the code sequence for a GenTree node that
1584 // represents a three operand bit shift or rotate operation (<<Hi, >>Lo).
1585 //
1586 // Arguments:
1587 //    tree - the bit shift node (that specifies the type of bit shift to perform).
1588 //
1589 // Assumptions:
1590 //    a) All GenTrees are register allocated.
1591 //    b) The shift-by-amount in tree->gtOp.gtOp2 is a contained constant
1592 //
1593 void CodeGen::genCodeForShiftLong(GenTreePtr tree)
1594 {
1595     // Only the non-RMW case here.
1596     genTreeOps oper = tree->OperGet();
1597     assert(oper == GT_LSH_HI || oper == GT_RSH_LO);
1598
1599     GenTree* operand = tree->gtOp.gtOp1;
1600     assert(operand->OperGet() == GT_LONG);
1601     assert(operand->gtOp.gtOp1->isUsedFromReg());
1602     assert(operand->gtOp.gtOp2->isUsedFromReg());
1603
1604     GenTree* operandLo = operand->gtGetOp1();
1605     GenTree* operandHi = operand->gtGetOp2();
1606
1607     regNumber regLo = operandLo->gtRegNum;
1608     regNumber regHi = operandHi->gtRegNum;
1609
1610     genConsumeOperands(tree->AsOp());
1611
1612     var_types   targetType = tree->TypeGet();
1613     instruction ins        = genGetInsForOper(oper, targetType);
1614
1615     GenTreePtr shiftBy = tree->gtGetOp2();
1616
1617     assert(shiftBy->isContainedIntOrIImmed());
1618
1619     unsigned int count = shiftBy->AsIntConCommon()->IconValue();
1620
1621     regNumber regResult = (oper == GT_LSH_HI) ? regHi : regLo;
1622
1623     if (regResult != tree->gtRegNum)
1624     {
1625         inst_RV_RV(INS_mov, tree->gtRegNum, regResult, targetType);
1626     }
1627
1628     if (oper == GT_LSH_HI)
1629     {
1630         inst_RV_SH(ins, EA_4BYTE, tree->gtRegNum, count);
1631         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regLo, 32 - count,
1632                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
1633     }
1634     else
1635     {
1636         assert(oper == GT_RSH_LO);
1637         inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, tree->gtRegNum, count);
1638         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regHi, 32 - count,
1639                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
1640     }
1641
1642     genProduceReg(tree);
1643 }
1644
1645 //------------------------------------------------------------------------
1646 // genLeaInstruction: Produce code for a GT_LEA subnode.
1647 //
1648 void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
1649 {
1650     emitAttr size = emitTypeSize(lea);
1651     genConsumeOperands(lea);
1652
1653     if (lea->Base() && lea->Index())
1654     {
1655         regNumber baseReg  = lea->Base()->gtRegNum;
1656         regNumber indexReg = lea->Index()->gtRegNum;
1657         getEmitter()->emitIns_R_ARX(INS_lea, size, lea->gtRegNum, baseReg, indexReg, lea->gtScale, lea->gtOffset);
1658     }
1659     else if (lea->Base())
1660     {
1661         regNumber baseReg = lea->Base()->gtRegNum;
1662         getEmitter()->emitIns_R_AR(INS_lea, size, lea->gtRegNum, baseReg, lea->gtOffset);
1663     }
1664     else if (lea->Index())
1665     {
1666         assert(!"Should we see a baseless address computation during CodeGen for ARM32?");
1667     }
1668
1669     genProduceReg(lea);
1670 }
1671
1672 //------------------------------------------------------------------------
1673 // genCompareLong: Generate code for comparing two longs when the result of the compare
1674 // is manifested in a register.
1675 //
1676 // Arguments:
1677 //    treeNode - the compare tree
1678 //
1679 // Return Value:
1680 //    None.
1681 //
1682 // Comments:
1683 // For long compares, we need to compare the high parts of operands first, then the low parts.
1684 // If the high compare is false, we do not need to compare the low parts. For less than and
1685 // greater than, if the high compare is true, we can assume the entire compare is true.
1686 //
1687 void CodeGen::genCompareLong(GenTreePtr treeNode)
1688 {
1689     assert(treeNode->OperIsCompare());
1690
1691     GenTreeOp* tree = treeNode->AsOp();
1692     GenTreePtr op1  = tree->gtOp1;
1693     GenTreePtr op2  = tree->gtOp2;
1694
1695     assert(varTypeIsLong(op1->TypeGet()));
1696     assert(varTypeIsLong(op2->TypeGet()));
1697
1698     regNumber targetReg = treeNode->gtRegNum;
1699
1700     genConsumeOperands(tree);
1701
1702     GenTreePtr loOp1 = op1->gtGetOp1();
1703     GenTreePtr hiOp1 = op1->gtGetOp2();
1704     GenTreePtr loOp2 = op2->gtGetOp1();
1705     GenTreePtr hiOp2 = op2->gtGetOp2();
1706
1707     // Create compare for the high parts
1708     instruction ins     = INS_cmp;
1709     var_types   cmpType = TYP_INT;
1710     emitAttr    cmpAttr = emitTypeSize(cmpType);
1711
1712     // Emit the compare instruction
1713     getEmitter()->emitInsBinary(ins, cmpAttr, hiOp1, hiOp2);
1714
1715     // If the result is not being materialized in a register, we're done.
1716     if (targetReg == REG_NA)
1717     {
1718         return;
1719     }
1720
1721     BasicBlock* labelTrue  = genCreateTempLabel();
1722     BasicBlock* labelFalse = genCreateTempLabel();
1723     BasicBlock* labelNext  = genCreateTempLabel();
1724
1725     genJccLongHi(tree->gtOper, labelTrue, labelFalse, tree->IsUnsigned());
1726     getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
1727     genJccLongLo(tree->gtOper, labelTrue, labelFalse);
1728
1729     genDefineTempLabel(labelFalse);
1730     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), tree->gtRegNum, 0);
1731     getEmitter()->emitIns_J(INS_b, labelNext);
1732
1733     genDefineTempLabel(labelTrue);
1734     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), tree->gtRegNum, 1);
1735
1736     genDefineTempLabel(labelNext);
1737
1738     genProduceReg(tree);
1739 }
1740
1741 void CodeGen::genJccLongHi(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse, bool isUnsigned)
1742 {
1743     if (cmp != GT_NE)
1744     {
1745         jumpFalse->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
1746     }
1747
1748     switch (cmp)
1749     {
1750         case GT_EQ:
1751             inst_JMP(EJ_ne, jumpFalse);
1752             break;
1753
1754         case GT_NE:
1755             inst_JMP(EJ_ne, jumpTrue);
1756             break;
1757
1758         case GT_LT:
1759         case GT_LE:
1760             if (isUnsigned)
1761             {
1762                 inst_JMP(EJ_hi, jumpFalse);
1763                 inst_JMP(EJ_lo, jumpTrue);
1764             }
1765             else
1766             {
1767                 inst_JMP(EJ_gt, jumpFalse);
1768                 inst_JMP(EJ_lt, jumpTrue);
1769             }
1770             break;
1771
1772         case GT_GE:
1773         case GT_GT:
1774             if (isUnsigned)
1775             {
1776                 inst_JMP(EJ_lo, jumpFalse);
1777                 inst_JMP(EJ_hi, jumpTrue);
1778             }
1779             else
1780             {
1781                 inst_JMP(EJ_lt, jumpFalse);
1782                 inst_JMP(EJ_gt, jumpTrue);
1783             }
1784             break;
1785
1786         default:
1787             noway_assert(!"expected a comparison operator");
1788     }
1789 }
1790
1791 void CodeGen::genJccLongLo(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse)
1792 {
1793     switch (cmp)
1794     {
1795         case GT_EQ:
1796             inst_JMP(EJ_eq, jumpTrue);
1797             break;
1798
1799         case GT_NE:
1800             inst_JMP(EJ_ne, jumpTrue);
1801             break;
1802
1803         case GT_LT:
1804             inst_JMP(EJ_lo, jumpTrue);
1805             break;
1806
1807         case GT_LE:
1808             inst_JMP(EJ_ls, jumpTrue);
1809             break;
1810
1811         case GT_GE:
1812             inst_JMP(EJ_hs, jumpTrue);
1813             break;
1814
1815         case GT_GT:
1816             inst_JMP(EJ_hi, jumpTrue);
1817             break;
1818
1819         default:
1820             noway_assert(!"expected comparison");
1821     }
1822 }
1823
1824 //------------------------------------------------------------------------
1825 // genSetRegToCond: Generate code to materialize a condition into a register.
1826 //
1827 // Arguments:
1828 //   dstReg - The target register to set to 1 or 0
1829 //   tree - The GenTree Relop node that was used to set the Condition codes
1830 //
1831 // Return Value: none
1832 //
1833 // Preconditions:
1834 //    The condition codes must already have been appropriately set.
1835 //
1836 void CodeGen::genSetRegToCond(regNumber dstReg, GenTreePtr tree)
1837 {
1838     // Emit code like that:
1839     //   ...
1840     //   bgt True
1841     //   movs rD, #0
1842     //   b Next
1843     // True:
1844     //   movs rD, #1
1845     // Next:
1846     //   ...
1847
1848     CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
1849     emitJumpKind jmpKind     = genJumpKindForOper(tree->gtOper, compareKind);
1850
1851     BasicBlock* labelTrue = genCreateTempLabel();
1852     getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmpKind), labelTrue);
1853
1854     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);
1855
1856     BasicBlock* labelNext = genCreateTempLabel();
1857     getEmitter()->emitIns_J(INS_b, labelNext);
1858
1859     genDefineTempLabel(labelTrue);
1860     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
1861     genDefineTempLabel(labelNext);
1862 }
1863
1864 //------------------------------------------------------------------------
1865 // genLongToIntCast: Generate code for long to int casts.
1866 //
1867 // Arguments:
1868 //    cast - The GT_CAST node
1869 //
1870 // Return Value:
1871 //    None.
1872 //
1873 // Assumptions:
1874 //    The cast node and its sources (via GT_LONG) must have been assigned registers.
1875 //    The destination cannot be a floating point type or a small integer type.
1876 //
1877 void CodeGen::genLongToIntCast(GenTree* cast)
1878 {
1879     assert(cast->OperGet() == GT_CAST);
1880
1881     GenTree* src = cast->gtGetOp1();
1882     noway_assert(src->OperGet() == GT_LONG);
1883
1884     genConsumeRegs(src);
1885
1886     var_types srcType  = ((cast->gtFlags & GTF_UNSIGNED) != 0) ? TYP_ULONG : TYP_LONG;
1887     var_types dstType  = cast->CastToType();
1888     regNumber loSrcReg = src->gtGetOp1()->gtRegNum;
1889     regNumber hiSrcReg = src->gtGetOp2()->gtRegNum;
1890     regNumber dstReg   = cast->gtRegNum;
1891
1892     assert((dstType == TYP_INT) || (dstType == TYP_UINT));
1893     assert(genIsValidIntReg(loSrcReg));
1894     assert(genIsValidIntReg(hiSrcReg));
1895     assert(genIsValidIntReg(dstReg));
1896
1897     if (cast->gtOverflow())
1898     {
1899         //
1900         // Generate an overflow check for [u]long to [u]int casts:
1901         //
1902         // long  -> int  - check if the upper 33 bits are all 0 or all 1
1903         //
1904         // ulong -> int  - check if the upper 33 bits are all 0
1905         //
1906         // long  -> uint - check if the upper 32 bits are all 0
1907         // ulong -> uint - check if the upper 32 bits are all 0
1908         //
1909
1910         if ((srcType == TYP_LONG) && (dstType == TYP_INT))
1911         {
1912             BasicBlock* allOne  = genCreateTempLabel();
1913             BasicBlock* success = genCreateTempLabel();
1914
1915             inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1916             emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1917             inst_JMP(JmpNegative, allOne);
1918             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1919             emitJumpKind jmpNotEqualL = genJumpKindForOper(GT_NE, CK_LOGICAL);
1920             genJumpToThrowHlpBlk(jmpNotEqualL, SCK_OVERFLOW);
1921             inst_JMP(EJ_jmp, success);
1922
1923             genDefineTempLabel(allOne);
1924             inst_RV_IV(INS_cmp, hiSrcReg, -1, EA_4BYTE);
1925             emitJumpKind jmpNotEqualS = genJumpKindForOper(GT_NE, CK_SIGNED);
1926             genJumpToThrowHlpBlk(jmpNotEqualS, SCK_OVERFLOW);
1927
1928             genDefineTempLabel(success);
1929         }
1930         else
1931         {
1932             if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
1933             {
1934                 inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1935                 emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1936                 genJumpToThrowHlpBlk(JmpNegative, SCK_OVERFLOW);
1937             }
1938
1939             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1940             emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_LOGICAL);
1941             genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
1942         }
1943     }
1944
1945     if (dstReg != loSrcReg)
1946     {
1947         inst_RV_RV(INS_mov, dstReg, loSrcReg, TYP_INT, EA_4BYTE);
1948     }
1949
1950     genProduceReg(cast);
1951 }
1952
1953 //------------------------------------------------------------------------
1954 // genIntToFloatCast: Generate code to cast an int/long to float/double
1955 //
1956 // Arguments:
1957 //    treeNode - The GT_CAST node
1958 //
1959 // Return Value:
1960 //    None.
1961 //
1962 // Assumptions:
1963 //    Cast is a non-overflow conversion.
1964 //    The treeNode must have an assigned register.
1965 //    SrcType= int32/uint32/int64/uint64 and DstType=float/double.
1966 //
1967 void CodeGen::genIntToFloatCast(GenTreePtr treeNode)
1968 {
1969     // int --> float/double conversions are always non-overflow ones
1970     assert(treeNode->OperGet() == GT_CAST);
1971     assert(!treeNode->gtOverflow());
1972
1973     regNumber targetReg = treeNode->gtRegNum;
1974     assert(genIsValidFloatReg(targetReg));
1975
1976     GenTreePtr op1 = treeNode->gtOp.gtOp1;
1977     assert(!op1->isContained());             // Cannot be contained
1978     assert(genIsValidIntReg(op1->gtRegNum)); // Must be a valid int reg.
1979
1980     var_types dstType = treeNode->CastToType();
1981     var_types srcType = op1->TypeGet();
1982     assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
1983
1984     // force the srcType to unsigned if GT_UNSIGNED flag is set
1985     if (treeNode->gtFlags & GTF_UNSIGNED)
1986     {
1987         srcType = genUnsignedType(srcType);
1988     }
1989
1990     // We should never see a srcType whose size is neither EA_4BYTE or EA_8BYTE
1991     // For conversions from small types (byte/sbyte/int16/uint16) to float/double,
1992     // we expect the front-end or lowering phase to have generated two levels of cast.
1993     //
1994     emitAttr srcSize = EA_ATTR(genTypeSize(srcType));
1995     noway_assert((srcSize == EA_4BYTE) || (srcSize == EA_8BYTE));
1996
1997     instruction insVcvt = INS_invalid;
1998
1999     if (dstType == TYP_DOUBLE)
2000     {
2001         if (srcSize == EA_4BYTE)
2002         {
2003             insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2d : INS_vcvt_i2d;
2004         }
2005         else
2006         {
2007             assert(srcSize == EA_8BYTE);
2008             NYI_ARM("Casting int64/uint64 to double in genIntToFloatCast");
2009         }
2010     }
2011     else
2012     {
2013         assert(dstType == TYP_FLOAT);
2014         if (srcSize == EA_4BYTE)
2015         {
2016             insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2f : INS_vcvt_i2f;
2017         }
2018         else
2019         {
2020             assert(srcSize == EA_8BYTE);
2021             NYI_ARM("Casting int64/uint64 to float in genIntToFloatCast");
2022         }
2023     }
2024
2025     genConsumeOperands(treeNode->AsOp());
2026
2027     assert(insVcvt != INS_invalid);
2028     getEmitter()->emitIns_R_R(INS_vmov_i2f, srcSize, treeNode->gtRegNum, op1->gtRegNum);
2029     getEmitter()->emitIns_R_R(insVcvt, srcSize, treeNode->gtRegNum, treeNode->gtRegNum);
2030
2031     genProduceReg(treeNode);
2032 }
2033
2034 //------------------------------------------------------------------------
2035 // genFloatToIntCast: Generate code to cast float/double to int/long
2036 //
2037 // Arguments:
2038 //    treeNode - The GT_CAST node
2039 //
2040 // Return Value:
2041 //    None.
2042 //
2043 // Assumptions:
2044 //    Cast is a non-overflow conversion.
2045 //    The treeNode must have an assigned register.
2046 //    SrcType=float/double and DstType= int32/uint32/int64/uint64
2047 //
2048 void CodeGen::genFloatToIntCast(GenTreePtr treeNode)
2049 {
2050     // we don't expect to see overflow detecting float/double --> int type conversions here
2051     // as they should have been converted into helper calls by front-end.
2052     assert(treeNode->OperGet() == GT_CAST);
2053     assert(!treeNode->gtOverflow());
2054
2055     regNumber targetReg = treeNode->gtRegNum;
2056     assert(genIsValidIntReg(targetReg)); // Must be a valid int reg.
2057
2058     GenTreePtr op1 = treeNode->gtOp.gtOp1;
2059     assert(!op1->isContained());               // Cannot be contained
2060     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
2061
2062     var_types dstType = treeNode->CastToType();
2063     var_types srcType = op1->TypeGet();
2064     assert(varTypeIsFloating(srcType) && !varTypeIsFloating(dstType));
2065
2066     // We should never see a dstType whose size is neither EA_4BYTE or EA_8BYTE
2067     // For conversions to small types (byte/sbyte/int16/uint16) from float/double,
2068     // we expect the front-end or lowering phase to have generated two levels of cast.
2069     //
2070     emitAttr dstSize = EA_ATTR(genTypeSize(dstType));
2071     noway_assert((dstSize == EA_4BYTE) || (dstSize == EA_8BYTE));
2072
2073     instruction insVcvt = INS_invalid;
2074
2075     if (srcType == TYP_DOUBLE)
2076     {
2077         if (dstSize == EA_4BYTE)
2078         {
2079             insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_d2u : INS_vcvt_d2i;
2080         }
2081         else
2082         {
2083             assert(dstSize == EA_8BYTE);
2084             NYI_ARM("Casting double to int64/uint64 in genIntToFloatCast");
2085         }
2086     }
2087     else
2088     {
2089         assert(srcType == TYP_FLOAT);
2090         if (dstSize == EA_4BYTE)
2091         {
2092             insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_f2u : INS_vcvt_f2i;
2093         }
2094         else
2095         {
2096             assert(dstSize == EA_8BYTE);
2097             NYI_ARM("Casting float to int64/uint64 in genIntToFloatCast");
2098         }
2099     }
2100
2101     genConsumeOperands(treeNode->AsOp());
2102
2103     assert(insVcvt != INS_invalid);
2104     getEmitter()->emitIns_R_R(insVcvt, dstSize, op1->gtRegNum, op1->gtRegNum);
2105     getEmitter()->emitIns_R_R(INS_vmov_f2i, dstSize, treeNode->gtRegNum, op1->gtRegNum);
2106
2107     genProduceReg(treeNode);
2108 }
2109
2110 //------------------------------------------------------------------------
2111 // genEmitHelperCall: Emit a call to a helper function.
2112 //
2113 void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
2114 {
2115     // Can we call the helper function directly
2116
2117     void *addr = NULL, **pAddr = NULL;
2118
2119 #if defined(DEBUG) && defined(PROFILING_SUPPORTED)
2120     // Don't ask VM if it hasn't requested ELT hooks
2121     if (!compiler->compProfilerHookNeeded && compiler->opts.compJitELTHookEnabled &&
2122         (helper == CORINFO_HELP_PROF_FCN_ENTER || helper == CORINFO_HELP_PROF_FCN_LEAVE ||
2123          helper == CORINFO_HELP_PROF_FCN_TAILCALL))
2124     {
2125         addr = compiler->compProfilerMethHnd;
2126     }
2127     else
2128 #endif
2129     {
2130         addr = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, (void**)&pAddr);
2131     }
2132
2133     if (!addr || !arm_Valid_Imm_For_BL((ssize_t)addr))
2134     {
2135         if (callTargetReg == REG_NA)
2136         {
2137             // If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
2138             // this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
2139             callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
2140         }
2141
2142         // Load the address into a register and call through a register
2143         if (addr)
2144         {
2145             instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, callTargetReg, (ssize_t)addr);
2146         }
2147         else
2148         {
2149             getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, callTargetReg, (ssize_t)pAddr);
2150             regTracker.rsTrackRegTrash(callTargetReg);
2151         }
2152
2153         getEmitter()->emitIns_Call(emitter::EC_INDIR_R, compiler->eeFindHelper(helper),
2154                                    INDEBUG_LDISASM_COMMA(nullptr) NULL, // addr
2155                                    argSize, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
2156                                    gcInfo.gcRegByrefSetCur,
2157                                    BAD_IL_OFFSET, // ilOffset
2158                                    callTargetReg, // ireg
2159                                    REG_NA, 0, 0,  // xreg, xmul, disp
2160                                    false,         // isJump
2161                                    emitter::emitNoGChelper(helper),
2162                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
2163     }
2164     else
2165     {
2166         getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, compiler->eeFindHelper(helper),
2167                                    INDEBUG_LDISASM_COMMA(nullptr) addr, argSize, retSize, gcInfo.gcVarPtrSetCur,
2168                                    gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
2169                                    0,     /* ilOffset, ireg, xreg, xmul, disp */
2170                                    false, /* isJump */
2171                                    emitter::emitNoGChelper(helper),
2172                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
2173     }
2174
2175     regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
2176     regTracker.rsTrashRegsForGCInterruptability();
2177 }
2178
2179 //------------------------------------------------------------------------
2180 // genStoreLongLclVar: Generate code to store a non-enregistered long lclVar
2181 //
2182 // Arguments:
2183 //    treeNode - A TYP_LONG lclVar node.
2184 //
2185 // Return Value:
2186 //    None.
2187 //
2188 // Assumptions:
2189 //    'treeNode' must be a TYP_LONG lclVar node for a lclVar that has NOT been promoted.
2190 //    Its operand must be a GT_LONG node.
2191 //
2192 void CodeGen::genStoreLongLclVar(GenTree* treeNode)
2193 {
2194     emitter* emit = getEmitter();
2195
2196     GenTreeLclVarCommon* lclNode = treeNode->AsLclVarCommon();
2197     unsigned             lclNum  = lclNode->gtLclNum;
2198     LclVarDsc*           varDsc  = &(compiler->lvaTable[lclNum]);
2199     assert(varDsc->TypeGet() == TYP_LONG);
2200     assert(!varDsc->lvPromoted);
2201     GenTreePtr op1 = treeNode->gtOp.gtOp1;
2202     noway_assert(op1->OperGet() == GT_LONG || op1->OperGet() == GT_MUL_LONG);
2203     genConsumeRegs(op1);
2204
2205     if (op1->OperGet() == GT_LONG)
2206     {
2207         // Definitions of register candidates will have been lowered to 2 int lclVars.
2208         assert(!treeNode->InReg());
2209
2210         GenTreePtr loVal = op1->gtGetOp1();
2211         GenTreePtr hiVal = op1->gtGetOp2();
2212
2213         // NYI: Contained immediates.
2214         NYI_IF((loVal->gtRegNum == REG_NA) || (hiVal->gtRegNum == REG_NA),
2215                "Store of long lclVar with contained immediate");
2216
2217         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, loVal->gtRegNum, lclNum, 0);
2218         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, hiVal->gtRegNum, lclNum, genTypeSize(TYP_INT));
2219     }
2220     else if (op1->OperGet() == GT_MUL_LONG)
2221     {
2222         assert((op1->gtFlags & GTF_MUL_64RSLT) != 0);
2223
2224         // Stack store
2225         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_LO, lclNum, 0);
2226         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_HI, lclNum,
2227                                   genTypeSize(TYP_INT));
2228     }
2229 }
2230
2231 #endif // _TARGET_ARM_
2232
2233 #endif // !LEGACY_BACKEND