Merge pull request #11713 from mskvortsov/Ckfinite
[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_MUL || oper == GT_ADD_LO || oper == GT_ADD_HI ||
220            oper == GT_SUB_LO || oper == GT_SUB_HI || oper == GT_OR || oper == GT_XOR || oper == GT_AND);
221
222     GenTreePtr op1 = treeNode->gtGetOp1();
223     GenTreePtr op2 = treeNode->gtGetOp2();
224
225     instruction ins = genGetInsForOper(oper, targetType);
226
227     // The arithmetic node must be sitting in a register (since it's not contained)
228     noway_assert(targetReg != REG_NA);
229
230     if ((oper == GT_ADD_LO || oper == GT_SUB_LO))
231     {
232         // During decomposition, all operands become reg
233         assert(!op1->isContained() && !op2->isContained());
234         emit->emitIns_R_R_R(ins, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum, op2->gtRegNum,
235                             INS_FLAGS_SET);
236     }
237     else
238     {
239         regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2);
240         assert(r == targetReg);
241     }
242
243     genProduceReg(treeNode);
244 }
245
246 //------------------------------------------------------------------------
247 // genReturn: Generates code for return statement.
248 //            In case of struct return, delegates to the genStructReturn method.
249 //
250 // Arguments:
251 //    treeNode - The GT_RETURN or GT_RETFILT tree node.
252 //
253 // Return Value:
254 //    None
255 //
256 void CodeGen::genReturn(GenTreePtr treeNode)
257 {
258     assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
259     GenTreePtr op1        = treeNode->gtGetOp1();
260     var_types  targetType = treeNode->TypeGet();
261
262     // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
263     // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
264     // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
265     assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
266
267 #ifdef DEBUG
268     if (targetType == TYP_VOID)
269     {
270         assert(op1 == nullptr);
271     }
272 #endif
273
274     if (treeNode->TypeGet() == TYP_LONG)
275     {
276         assert(op1 != nullptr);
277         noway_assert(op1->OperGet() == GT_LONG);
278         GenTree* loRetVal = op1->gtGetOp1();
279         GenTree* hiRetVal = op1->gtGetOp2();
280         noway_assert((loRetVal->gtRegNum != REG_NA) && (hiRetVal->gtRegNum != REG_NA));
281
282         genConsumeReg(loRetVal);
283         genConsumeReg(hiRetVal);
284         if (loRetVal->gtRegNum != REG_LNGRET_LO)
285         {
286             inst_RV_RV(ins_Copy(targetType), REG_LNGRET_LO, loRetVal->gtRegNum, TYP_INT);
287         }
288         if (hiRetVal->gtRegNum != REG_LNGRET_HI)
289         {
290             inst_RV_RV(ins_Copy(targetType), REG_LNGRET_HI, hiRetVal->gtRegNum, TYP_INT);
291         }
292     }
293     else
294     {
295         if (varTypeIsStruct(treeNode))
296         {
297             NYI_ARM("struct return");
298         }
299         else if (targetType != TYP_VOID)
300         {
301             assert(op1 != nullptr);
302             noway_assert(op1->gtRegNum != REG_NA);
303
304             // !! NOTE !! genConsumeReg will clear op1 as GC ref after it has
305             // consumed a reg for the operand. This is because the variable
306             // is dead after return. But we are issuing more instructions
307             // like "profiler leave callback" after this consumption. So
308             // if you are issuing more instructions after this point,
309             // remember to keep the variable live up until the new method
310             // exit point where it is actually dead.
311             genConsumeReg(op1);
312
313             regNumber retReg = varTypeIsFloating(treeNode) ? REG_FLOATRET : REG_INTRET;
314             if (op1->gtRegNum != retReg)
315             {
316                 inst_RV_RV(ins_Move_Extend(targetType, true), retReg, op1->gtRegNum, targetType);
317             }
318         }
319     }
320 }
321
322 //------------------------------------------------------------------------
323 // genLockedInstructions: Generate code for the locked operations.
324 //
325 // Notes:
326 //    Handles GT_LOCKADD, GT_XCHG, GT_XADD nodes.
327 //
328 void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
329 {
330     NYI("genLockedInstructions");
331 }
332
333 //--------------------------------------------------------------------------------------
334 // genLclHeap: Generate code for localloc
335 //
336 // Description:
337 //      There are 2 ways depending from build version to generate code for localloc:
338 //          1) For debug build where memory should be initialized we generate loop
339 //             which invoke push {tmpReg} N times.
340 //          2) Fore /o build  However, we tickle the pages to ensure that SP is always
341 //             valid and is in sync with the "stack guard page". Amount of iteration
342 //             is N/PAGE_SIZE.
343 //
344 // Comments:
345 //      There can be some optimization:
346 //          1) It's not needed to generate loop for zero size allocation
347 //          2) For small allocation (less than 4 store) we unroll loop
348 //          3) For allocation less than PAGE_SIZE and when it's not needed to initialize
349 //             memory to zero, we can just increment SP.
350 //
351 // Notes: Size N should be aligned to STACK_ALIGN before any allocation
352 //
353 void CodeGen::genLclHeap(GenTreePtr tree)
354 {
355     assert(tree->OperGet() == GT_LCLHEAP);
356
357     GenTreePtr size = tree->gtOp.gtOp1;
358     noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
359
360     // Result of localloc will be returned in regCnt.
361     // Also it used as temporary register in code generation
362     // for storing allocation size
363     regNumber   regCnt          = tree->gtRegNum;
364     regNumber   pspSymReg       = REG_NA;
365     var_types   type            = genActualType(size->gtType);
366     emitAttr    easz            = emitTypeSize(type);
367     BasicBlock* endLabel        = nullptr;
368     BasicBlock* loop            = nullptr;
369     unsigned    stackAdjustment = 0;
370
371 #ifdef DEBUG
372     // Verify ESP
373     if (compiler->opts.compStackCheckOnRet)
374     {
375         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
376                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
377                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
378         getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
379
380         BasicBlock*  esp_check = genCreateTempLabel();
381         emitJumpKind jmpEqual  = genJumpKindForOper(GT_EQ, CK_SIGNED);
382         inst_JMP(jmpEqual, esp_check);
383         getEmitter()->emitIns(INS_BREAKPOINT);
384         genDefineTempLabel(esp_check);
385     }
386 #endif
387
388     noway_assert(isFramePointerUsed()); // localloc requires Frame Pointer to be established since SP changes
389     noway_assert(genStackLevel == 0);   // Can't have anything on the stack
390
391     // Whether method has PSPSym.
392     bool hasPspSym;
393 #if FEATURE_EH_FUNCLETS
394     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
395 #else
396     hasPspSym = false;
397 #endif
398
399     // Check to 0 size allocations
400     // size_t amount = 0;
401     if (size->IsCnsIntOrI())
402     {
403         // If size is a constant, then it must be contained.
404         assert(size->isContained());
405
406         // If amount is zero then return null in regCnt
407         size_t amount = size->gtIntCon.gtIconVal;
408         if (amount == 0)
409         {
410             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
411             goto BAILOUT;
412         }
413     }
414     else
415     {
416         // If 0 bail out by returning null in regCnt
417         genConsumeRegAndCopy(size, regCnt);
418         endLabel = genCreateTempLabel();
419         getEmitter()->emitIns_R_R(INS_TEST, easz, regCnt, regCnt);
420         emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
421         inst_JMP(jmpEqual, endLabel);
422     }
423
424     stackAdjustment = 0;
425 #if FEATURE_EH_FUNCLETS
426     // If we have PSPsym, then need to re-locate it after localloc.
427     if (hasPspSym)
428     {
429         stackAdjustment += STACK_ALIGN;
430
431         // Save a copy of PSPSym
432         pspSymReg = tree->ExtractTempReg();
433         getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
434     }
435 #endif
436
437 #if FEATURE_FIXED_OUT_ARGS
438     // If we have an outgoing arg area then we must adjust the SP by popping off the
439     // outgoing arg area. We will restore it right before we return from this method.
440     if (compiler->lvaOutgoingArgSpaceSize > 0)
441     {
442         assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain
443                                                                         // aligned
444         inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
445         stackAdjustment += compiler->lvaOutgoingArgSpaceSize;
446     }
447 #endif
448
449     // Put aligned allocation size to regCnt
450     if (size->IsCnsIntOrI())
451     {
452         // 'amount' is the total number of bytes to localloc to properly STACK_ALIGN
453         size_t amount = size->gtIntCon.gtIconVal;
454         amount        = AlignUp(amount, STACK_ALIGN);
455
456         // For small allocations we will generate up to four stp instructions
457         size_t cntStackAlignedWidthItems = (amount >> STACK_ALIGN_SHIFT);
458         if (cntStackAlignedWidthItems <= 4)
459         {
460             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
461
462             while (cntStackAlignedWidthItems != 0)
463             {
464                 inst_IV(INS_push, (unsigned)genRegMask(regCnt));
465                 cntStackAlignedWidthItems -= 1;
466             }
467
468             goto ALLOC_DONE;
469         }
470         else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
471         {
472             // Since the size is a page or less, simply adjust the SP value
473             // The SP might already be in the guard page, must touch it BEFORE
474             // the alloc, not after.
475             getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regCnt, REG_SP, 0);
476             inst_RV_IV(INS_sub, REG_SP, amount, EA_PTRSIZE);
477             goto ALLOC_DONE;
478         }
479
480         // regCnt will be the total number of bytes to locAlloc
481         genSetRegToIcon(regCnt, amount, ((int)amount == amount) ? TYP_INT : TYP_LONG);
482     }
483     else
484     {
485         // Round up the number of bytes to allocate to a STACK_ALIGN boundary.
486         inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
487         inst_RV_IV(INS_AND, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
488     }
489
490     // Allocation
491     if (compiler->info.compInitMem)
492     {
493         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
494         // Since we have to zero out the allocated memory AND ensure that RSP is always valid
495         // by tickling the pages, we will just push 0's on the stack.
496
497         regNumber regTmp = tree->ExtractTempReg();
498         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regTmp);
499
500         // Loop:
501         BasicBlock* loop = genCreateTempLabel();
502         genDefineTempLabel(loop);
503
504         noway_assert(STACK_ALIGN == 8);
505         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
506         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
507
508         // If not done, loop
509         // Note that regCnt is the number of bytes to stack allocate.
510         assert(genIsValidIntReg(regCnt));
511         getEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, regCnt, STACK_ALIGN, INS_FLAGS_SET);
512         emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
513         inst_JMP(jmpNotEqual, loop);
514     }
515     else
516     {
517         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
518         //
519         // We don't need to zero out the allocated memory. However, we do have
520         // to tickle the pages to ensure that SP is always valid and is
521         // in sync with the "stack guard page".  Note that in the worst
522         // case SP is on the last byte of the guard page.  Thus you must
523         // touch SP+0 first not SP+0x1000.
524         //
525         // Another subtlety is that you don't want SP to be exactly on the
526         // boundary of the guard page because PUSH is predecrement, thus
527         // call setup would not touch the guard page but just beyond it
528         //
529         // Note that we go through a few hoops so that SP never points to
530         // illegal pages at any time during the ticking process
531         //
532         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
533         //       jb    Loop                    // result is smaller than orignial SP (no wrap around)
534         //       mov   regCnt, #0              // Overflow, pick lowest possible value
535         //
536         //  Loop:
537         //       ldr   regTmp, [SP + 0]        // tickle the page - read from the page
538         //       sub   regTmp, SP, PAGE_SIZE   // decrement SP by PAGE_SIZE
539         //       cmp   regTmp, regCnt
540         //       jb    Done
541         //       mov   SP, regTmp
542         //       j     Loop
543         //
544         //  Done:
545         //       mov   SP, regCnt
546         //
547
548         // Setup the regTmp
549         regNumber regTmp = tree->ExtractTempReg();
550
551         BasicBlock* loop = genCreateTempLabel();
552         BasicBlock* done = genCreateTempLabel();
553
554         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
555         getEmitter()->emitIns_R_R_R(INS_sub, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt, INS_FLAGS_SET);
556
557         inst_JMP(EJ_vc, loop); // branch if the V flag is not set
558
559         // Ups... Overflow, set regCnt to lowest possible value
560         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
561
562         genDefineTempLabel(loop);
563
564         // tickle the page - Read from the updated SP - this triggers a page fault when on the guard page
565         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regTmp, REG_SPBASE, 0);
566
567         // decrement SP by PAGE_SIZE
568         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());
569
570         getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
571         emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
572         inst_JMP(jmpLTU, done);
573
574         // Update SP to be at the next page of stack that we will tickle
575         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
576
577         // Jump to loop and tickle new stack address
578         inst_JMP(EJ_jmp, loop);
579
580         // Done with stack tickle loop
581         genDefineTempLabel(done);
582
583         // Now just move the final value to SP
584         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
585     }
586
587 ALLOC_DONE:
588     // Re-adjust SP to allocate PSPSym and out-going arg area
589     if (stackAdjustment != 0)
590     {
591         assert((stackAdjustment % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
592         assert(stackAdjustment > 0);
593         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, (int)stackAdjustment);
594
595 #if FEATURE_EH_FUNCLETS
596         // Write PSPSym to its new location.
597         if (hasPspSym)
598         {
599             assert(genIsValidIntReg(pspSymReg));
600             getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
601         }
602 #endif
603         // Return the stackalloc'ed address in result register.
604         // regCnt = RSP + stackAdjustment.
605         getEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, regCnt, REG_SPBASE, (int)stackAdjustment);
606     }
607     else // stackAdjustment == 0
608     {
609         // Move the final value of SP to regCnt
610         inst_RV_RV(INS_mov, regCnt, REG_SPBASE);
611     }
612
613 BAILOUT:
614     if (endLabel != nullptr)
615         genDefineTempLabel(endLabel);
616
617     // Write the lvaLocAllocSPvar stack frame slot
618     if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
619     {
620         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaLocAllocSPvar, 0);
621     }
622
623 #if STACK_PROBES
624     if (compiler->opts.compNeedStackProbes)
625     {
626         genGenerateStackProbe();
627     }
628 #endif
629
630 #ifdef DEBUG
631     // Update new ESP
632     if (compiler->opts.compStackCheckOnRet)
633     {
634         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
635                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
636                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
637         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaReturnEspCheck, 0);
638     }
639 #endif
640
641     genProduceReg(tree);
642 }
643
644 //------------------------------------------------------------------------
645 // genTableBasedSwitch: generate code for a switch statement based on a table of ip-relative offsets
646 //
647 void CodeGen::genTableBasedSwitch(GenTree* treeNode)
648 {
649     genConsumeOperands(treeNode->AsOp());
650     regNumber idxReg  = treeNode->gtOp.gtOp1->gtRegNum;
651     regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
652
653     getEmitter()->emitIns_R_ARX(INS_ldr, EA_4BYTE, REG_PC, baseReg, idxReg, TARGET_POINTER_SIZE, 0);
654 }
655
656 //------------------------------------------------------------------------
657 // genJumpTable: emits the table and an instruction to get the address of the first element
658 //
659 void CodeGen::genJumpTable(GenTree* treeNode)
660 {
661     noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
662     assert(treeNode->OperGet() == GT_JMPTABLE);
663
664     unsigned     jumpCount = compiler->compCurBB->bbJumpSwt->bbsCount;
665     BasicBlock** jumpTable = compiler->compCurBB->bbJumpSwt->bbsDstTab;
666     unsigned     jmpTabBase;
667
668     jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCount, false);
669
670     JITDUMP("\n      J_M%03u_DS%02u LABEL   DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
671
672     for (unsigned i = 0; i < jumpCount; i++)
673     {
674         BasicBlock* target = *jumpTable++;
675         noway_assert(target->bbFlags & BBF_JMP_TARGET);
676
677         JITDUMP("            DD      L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
678
679         getEmitter()->emitDataGenData(i, target);
680     }
681
682     getEmitter()->emitDataGenEnd();
683
684     getEmitter()->emitIns_R_D(INS_movw, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
685     getEmitter()->emitIns_R_D(INS_movt, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
686
687     genProduceReg(treeNode);
688 }
689
690 //------------------------------------------------------------------------
691 // genGetInsForOper: Return instruction encoding of the operation tree.
692 //
693 instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
694 {
695     instruction ins;
696
697     if (varTypeIsFloating(type))
698         return CodeGen::ins_MathOp(oper, type);
699
700     switch (oper)
701     {
702         case GT_ADD:
703             ins = INS_add;
704             break;
705         case GT_AND:
706             ins = INS_AND;
707             break;
708         case GT_MUL:
709             ins = INS_MUL;
710             break;
711         case GT_DIV:
712             ins = INS_sdiv;
713             break;
714         case GT_LSH:
715             ins = INS_SHIFT_LEFT_LOGICAL;
716             break;
717         case GT_NEG:
718             ins = INS_rsb;
719             break;
720         case GT_NOT:
721             ins = INS_NOT;
722             break;
723         case GT_OR:
724             ins = INS_OR;
725             break;
726         case GT_RSH:
727             ins = INS_SHIFT_RIGHT_ARITHM;
728             break;
729         case GT_RSZ:
730             ins = INS_SHIFT_RIGHT_LOGICAL;
731             break;
732         case GT_SUB:
733             ins = INS_sub;
734             break;
735         case GT_XOR:
736             ins = INS_XOR;
737             break;
738         case GT_ROR:
739             ins = INS_ror;
740             break;
741         case GT_ADD_LO:
742             ins = INS_add;
743             break;
744         case GT_ADD_HI:
745             ins = INS_adc;
746             break;
747         case GT_SUB_LO:
748             ins = INS_sub;
749             break;
750         case GT_SUB_HI:
751             ins = INS_sbc;
752             break;
753         case GT_LSH_HI:
754             ins = INS_SHIFT_LEFT_LOGICAL;
755             break;
756         case GT_RSH_LO:
757             ins = INS_SHIFT_RIGHT_LOGICAL;
758             break;
759         default:
760             unreached();
761             break;
762     }
763     return ins;
764 }
765
766 // Generates CpBlk code by performing a loop unroll
767 // Preconditions:
768 //  The size argument of the CpBlk node is a constant and <= 64 bytes.
769 //  This may seem small but covers >95% of the cases in several framework assemblies.
770 void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode)
771 {
772     NYI_ARM("genCodeForCpBlkUnroll");
773 }
774
775 // Generate code for InitBlk by performing a loop unroll
776 // Preconditions:
777 //   a) Both the size and fill byte value are integer constants.
778 //   b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
779 void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
780 {
781     NYI_ARM("genCodeForInitBlkUnroll");
782 }
783
784 //------------------------------------------------------------------------
785 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
786 //
787 // Arguments:
788 //    tree - the node
789 //
790 void CodeGen::genCodeForNegNot(GenTree* tree)
791 {
792     assert(tree->OperIs(GT_NEG, GT_NOT));
793
794     var_types targetType = tree->TypeGet();
795
796     assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
797
798     regNumber   targetReg = tree->gtRegNum;
799     instruction ins       = genGetInsForOper(tree->OperGet(), targetType);
800
801     // The arithmetic node must be sitting in a register (since it's not contained)
802     assert(!tree->isContained());
803     // The dst can only be a register.
804     assert(targetReg != REG_NA);
805
806     GenTreePtr operand = tree->gtGetOp1();
807     assert(!operand->isContained());
808     // The src must be a register.
809     regNumber operandReg = genConsumeReg(operand);
810
811     if (ins == INS_vneg)
812     {
813         getEmitter()->emitIns_R_R(ins, emitTypeSize(tree), targetReg, operandReg);
814     }
815     else
816     {
817         getEmitter()->emitIns_R_R_I(ins, emitTypeSize(tree), targetReg, operandReg, 0);
818     }
819
820     genProduceReg(tree);
821 }
822
823 // Generate code for CpObj nodes wich copy structs that have interleaved
824 // GC pointers.
825 // For this case we'll generate a sequence of loads/stores in the case of struct
826 // slots that don't contain GC pointers.  The generated code will look like:
827 // ldr tempReg, [R13, #8]
828 // str tempReg, [R14, #8]
829 //
830 // In the case of a GC-Pointer we'll call the ByRef write barrier helper
831 // who happens to use the same registers as the previous call to maintain
832 // the same register requirements and register killsets:
833 // bl CORINFO_HELP_ASSIGN_BYREF
834 //
835 // So finally an example would look like this:
836 // ldr tempReg, [R13, #8]
837 // str tempReg, [R14, #8]
838 // bl CORINFO_HELP_ASSIGN_BYREF
839 // ldr tempReg, [R13, #8]
840 // str tempReg, [R14, #8]
841 // bl CORINFO_HELP_ASSIGN_BYREF
842 // ldr tempReg, [R13, #8]
843 // str tempReg, [R14, #8]
844 void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
845 {
846     GenTreePtr dstAddr       = cpObjNode->Addr();
847     GenTreePtr source        = cpObjNode->Data();
848     var_types  srcAddrType   = TYP_BYREF;
849     bool       sourceIsLocal = false;
850     regNumber  dstReg        = REG_NA;
851     regNumber  srcReg        = REG_NA;
852
853     assert(source->isContained());
854     if (source->gtOper == GT_IND)
855     {
856         GenTree* srcAddr = source->gtGetOp1();
857         assert(!srcAddr->isContained());
858         srcAddrType = srcAddr->TypeGet();
859     }
860     else
861     {
862         noway_assert(source->IsLocal());
863         sourceIsLocal = true;
864     }
865
866     bool dstOnStack = dstAddr->OperIsLocalAddr();
867
868 #ifdef DEBUG
869     assert(!dstAddr->isContained());
870
871     // This GenTree node has data about GC pointers, this means we're dealing
872     // with CpObj.
873     assert(cpObjNode->gtGcPtrCount > 0);
874 #endif // DEBUG
875
876     // Consume the operands and get them into the right registers.
877     // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing").
878     genConsumeBlockOp(cpObjNode, REG_WRITE_BARRIER_DST_BYREF, REG_WRITE_BARRIER_SRC_BYREF, REG_NA);
879     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
880     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());
881
882     // Temp register used to perform the sequence of loads and stores.
883     regNumber tmpReg = cpObjNode->ExtractTempReg();
884     assert(genIsValidIntReg(tmpReg));
885
886     unsigned slots = cpObjNode->gtSlots;
887     emitter* emit  = getEmitter();
888
889     BYTE* gcPtrs = cpObjNode->gtGcPtrs;
890
891     // If we can prove it's on the stack we don't need to use the write barrier.
892     emitAttr attr = EA_PTRSIZE;
893     if (dstOnStack)
894     {
895         for (unsigned i = 0; i < slots; ++i)
896         {
897             if (gcPtrs[i] == GCT_GCREF)
898                 attr = EA_GCREF;
899             else if (gcPtrs[i] == GCT_BYREF)
900                 attr = EA_BYREF;
901             emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
902                                 INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
903             emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
904                                 INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
905         }
906     }
907     else
908     {
909         unsigned gcPtrCount = cpObjNode->gtGcPtrCount;
910
911         unsigned i = 0;
912         while (i < slots)
913         {
914             switch (gcPtrs[i])
915             {
916                 case TYPE_GC_NONE:
917                     emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
918                                         INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
919                     emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
920                                         INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
921                     break;
922
923                 default:
924                     // In the case of a GC-Pointer we'll call the ByRef write barrier helper
925                     genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
926
927                     gcPtrCount--;
928                     break;
929             }
930             ++i;
931         }
932         assert(gcPtrCount == 0);
933     }
934
935     // Clear the gcInfo for registers of source and dest.
936     // While we normally update GC info prior to the last instruction that uses them,
937     // these actually live into the helper call.
938     gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF);
939 }
940
941 //------------------------------------------------------------------------
942 // genCodeForShiftLong: Generates the code sequence for a GenTree node that
943 // represents a three operand bit shift or rotate operation (<<Hi, >>Lo).
944 //
945 // Arguments:
946 //    tree - the bit shift node (that specifies the type of bit shift to perform).
947 //
948 // Assumptions:
949 //    a) All GenTrees are register allocated.
950 //    b) The shift-by-amount in tree->gtOp.gtOp2 is a contained constant
951 //
952 void CodeGen::genCodeForShiftLong(GenTreePtr tree)
953 {
954     // Only the non-RMW case here.
955     genTreeOps oper = tree->OperGet();
956     assert(oper == GT_LSH_HI || oper == GT_RSH_LO);
957
958     GenTree* operand = tree->gtOp.gtOp1;
959     assert(operand->OperGet() == GT_LONG);
960     assert(operand->gtOp.gtOp1->isUsedFromReg());
961     assert(operand->gtOp.gtOp2->isUsedFromReg());
962
963     GenTree* operandLo = operand->gtGetOp1();
964     GenTree* operandHi = operand->gtGetOp2();
965
966     regNumber regLo = operandLo->gtRegNum;
967     regNumber regHi = operandHi->gtRegNum;
968
969     genConsumeOperands(tree->AsOp());
970
971     var_types   targetType = tree->TypeGet();
972     instruction ins        = genGetInsForOper(oper, targetType);
973
974     GenTreePtr shiftBy = tree->gtGetOp2();
975
976     assert(shiftBy->isContainedIntOrIImmed());
977
978     unsigned int count = shiftBy->AsIntConCommon()->IconValue();
979
980     regNumber regResult = (oper == GT_LSH_HI) ? regHi : regLo;
981
982     if (regResult != tree->gtRegNum)
983     {
984         inst_RV_RV(INS_mov, tree->gtRegNum, regResult, targetType);
985     }
986
987     if (oper == GT_LSH_HI)
988     {
989         inst_RV_SH(ins, EA_4BYTE, tree->gtRegNum, count);
990         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regLo, 32 - count,
991                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
992     }
993     else
994     {
995         assert(oper == GT_RSH_LO);
996         inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, tree->gtRegNum, count);
997         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regHi, 32 - count,
998                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
999     }
1000
1001     genProduceReg(tree);
1002 }
1003
1004 //------------------------------------------------------------------------
1005 // genCodeForLclVar: Produce code for a GT_LCL_VAR node.
1006 //
1007 // Arguments:
1008 //    tree - the GT_LCL_VAR node
1009 //
1010 void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
1011 {
1012     // lcl_vars are not defs
1013     assert((tree->gtFlags & GTF_VAR_DEF) == 0);
1014
1015     bool isRegCandidate = compiler->lvaTable[tree->gtLclNum].lvIsRegCandidate();
1016
1017     if (isRegCandidate && !(tree->gtFlags & GTF_VAR_DEATH))
1018     {
1019         assert((tree->InReg()) || (tree->gtFlags & GTF_SPILLED));
1020     }
1021
1022     // If this is a register candidate that has been spilled, genConsumeReg() will
1023     // reload it at the point of use.  Otherwise, if it's not in a register, we load it here.
1024
1025     if (!tree->InReg() && !(tree->gtFlags & GTF_SPILLED))
1026     {
1027         assert(!isRegCandidate);
1028         getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), emitTypeSize(tree), tree->gtRegNum, tree->gtLclNum, 0);
1029         genProduceReg(tree);
1030     }
1031 }
1032
1033 //------------------------------------------------------------------------
1034 // genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
1035 //
1036 // Arguments:
1037 //    tree - the GT_STORE_LCL_FLD node
1038 //
1039 void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
1040 {
1041     var_types targetType = tree->TypeGet();
1042     regNumber targetReg  = tree->gtRegNum;
1043     emitter*  emit       = getEmitter();
1044
1045     noway_assert(targetType != TYP_STRUCT);
1046
1047     // record the offset
1048     unsigned offset = tree->gtLclOffs;
1049
1050     // We must have a stack store with GT_STORE_LCL_FLD
1051     noway_assert(!tree->InReg());
1052     noway_assert(targetReg == REG_NA);
1053
1054     unsigned varNum = tree->gtLclNum;
1055     assert(varNum < compiler->lvaCount);
1056     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1057
1058     // Ensure that lclVar nodes are typed correctly.
1059     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1060
1061     GenTreePtr  data = tree->gtOp1->gtEffectiveVal();
1062     instruction ins  = ins_Store(targetType);
1063     emitAttr    attr = emitTypeSize(targetType);
1064     if (data->isContainedIntOrIImmed())
1065     {
1066         assert(data->IsIntegralConst(0));
1067         NYI_ARM("st.lclFld contained operand");
1068     }
1069     else
1070     {
1071         assert(!data->isContained());
1072         genConsumeReg(data);
1073         emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
1074     }
1075
1076     genUpdateLife(tree);
1077     varDsc->lvRegNum = REG_STK;
1078 }
1079
1080 //------------------------------------------------------------------------
1081 // genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
1082 //
1083 // Arguments:
1084 //    tree - the GT_STORE_LCL_VAR node
1085 //
1086 void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
1087 {
1088     var_types targetType = tree->TypeGet();
1089     regNumber targetReg  = tree->gtRegNum;
1090     emitter*  emit       = getEmitter();
1091
1092     unsigned varNum = tree->gtLclNum;
1093     assert(varNum < compiler->lvaCount);
1094     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1095
1096     // Ensure that lclVar nodes are typed correctly.
1097     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1098
1099     GenTreePtr data = tree->gtOp1->gtEffectiveVal();
1100
1101     // var = call, where call returns a multi-reg return value
1102     // case is handled separately.
1103     if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
1104     {
1105         genMultiRegCallStoreToLocal(tree);
1106     }
1107     else if (tree->TypeGet() == TYP_LONG)
1108     {
1109         genStoreLongLclVar(tree);
1110     }
1111     else
1112     {
1113         genConsumeRegs(data);
1114
1115         regNumber dataReg = REG_NA;
1116         if (data->isContainedIntOrIImmed())
1117         {
1118             assert(data->IsIntegralConst(0));
1119             NYI_ARM("st.lclVar contained operand");
1120         }
1121         else
1122         {
1123             assert(!data->isContained());
1124             dataReg = data->gtRegNum;
1125         }
1126         assert(dataReg != REG_NA);
1127
1128         if (targetReg == REG_NA) // store into stack based LclVar
1129         {
1130             inst_set_SV_var(tree);
1131
1132             instruction ins  = ins_Store(targetType);
1133             emitAttr    attr = emitTypeSize(targetType);
1134
1135             emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
1136
1137             genUpdateLife(tree);
1138
1139             varDsc->lvRegNum = REG_STK;
1140         }
1141         else // store into register (i.e move into register)
1142         {
1143             if (dataReg != targetReg)
1144             {
1145                 // Assign into targetReg when dataReg (from op1) is not the same register
1146                 inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
1147             }
1148             genProduceReg(tree);
1149         }
1150     }
1151 }
1152
1153 //------------------------------------------------------------------------
1154 // genLeaInstruction: Produce code for a GT_LEA subnode.
1155 //
1156 void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
1157 {
1158     emitAttr size = emitTypeSize(lea);
1159     genConsumeOperands(lea);
1160
1161     if (lea->Base() && lea->Index())
1162     {
1163         regNumber baseReg  = lea->Base()->gtRegNum;
1164         regNumber indexReg = lea->Index()->gtRegNum;
1165         getEmitter()->emitIns_R_ARX(INS_lea, size, lea->gtRegNum, baseReg, indexReg, lea->gtScale, lea->gtOffset);
1166     }
1167     else if (lea->Base())
1168     {
1169         regNumber baseReg = lea->Base()->gtRegNum;
1170         getEmitter()->emitIns_R_AR(INS_lea, size, lea->gtRegNum, baseReg, lea->gtOffset);
1171     }
1172     else if (lea->Index())
1173     {
1174         assert(!"Should we see a baseless address computation during CodeGen for ARM32?");
1175     }
1176
1177     genProduceReg(lea);
1178 }
1179
1180 //------------------------------------------------------------------------
1181 // genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
1182 //
1183 // Arguments:
1184 //    tree - the node
1185 //
1186 void CodeGen::genCodeForDivMod(GenTreeOp* tree)
1187 {
1188     assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
1189
1190     // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
1191     // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
1192     // on float/double args.
1193     noway_assert(tree->OperIs(GT_DIV) || !varTypeIsFloating(tree));
1194
1195     var_types targetType = tree->TypeGet();
1196     regNumber targetReg  = tree->gtRegNum;
1197     emitter*  emit       = getEmitter();
1198
1199     genConsumeOperands(tree);
1200
1201     noway_assert(targetReg != REG_NA);
1202
1203     GenTreePtr  dst    = tree;
1204     GenTreePtr  src1   = tree->gtGetOp1();
1205     GenTreePtr  src2   = tree->gtGetOp2();
1206     instruction ins    = genGetInsForOper(tree->OperGet(), targetType);
1207     emitAttr    attr   = emitTypeSize(tree);
1208     regNumber   result = REG_NA;
1209
1210     // dst can only be a reg
1211     assert(!dst->isContained());
1212
1213     // src can be only reg
1214     assert(!src1->isContained() || !src2->isContained());
1215
1216     if (varTypeIsFloating(targetType))
1217     {
1218         // Floating point divide never raises an exception
1219
1220         emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1221     }
1222     else // an signed integer divide operation
1223     {
1224         // TODO-ARM-Bug: handle zero division exception.
1225
1226         emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1227     }
1228
1229     genProduceReg(tree);
1230 }
1231
1232 //------------------------------------------------------------------------
1233 // genCkfinite: Generate code for ckfinite opcode.
1234 //
1235 // Arguments:
1236 //    treeNode - The GT_CKFINITE node
1237 //
1238 // Return Value:
1239 //    None.
1240 //
1241 // Assumptions:
1242 //    GT_CKFINITE node has reserved an internal register.
1243 //
1244 void CodeGen::genCkfinite(GenTreePtr treeNode)
1245 {
1246     assert(treeNode->OperGet() == GT_CKFINITE);
1247
1248     emitter*  emit       = getEmitter();
1249     var_types targetType = treeNode->TypeGet();
1250     regNumber intReg     = treeNode->GetSingleTempReg();
1251     regNumber fpReg      = genConsumeReg(treeNode->gtOp.gtOp1);
1252     regNumber targetReg  = treeNode->gtRegNum;
1253
1254     // Extract and sign-extend the exponent into an integer register
1255     if (targetType == TYP_FLOAT)
1256     {
1257         emit->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, intReg, fpReg);
1258         emit->emitIns_R_R_I_I(INS_sbfx, EA_4BYTE, intReg, intReg, 23, 8);
1259     }
1260     else
1261     {
1262         assert(targetType == TYP_DOUBLE);
1263         emit->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, intReg, REG_NEXT(fpReg));
1264         emit->emitIns_R_R_I_I(INS_sbfx, EA_4BYTE, intReg, intReg, 20, 11);
1265     }
1266
1267     // If exponent is all 1's, throw ArithmeticException
1268     emit->emitIns_R_I(INS_add, EA_4BYTE, intReg, 1, INS_FLAGS_SET);
1269     genJumpToThrowHlpBlk(EJ_eq, SCK_ARITH_EXCPN);
1270
1271     // If it's a finite value, copy it to targetReg
1272     if (targetReg != fpReg)
1273     {
1274         emit->emitIns_R_R(ins_Copy(targetType), emitTypeSize(treeNode), targetReg, fpReg);
1275     }
1276     genProduceReg(treeNode);
1277 }
1278
1279 //------------------------------------------------------------------------
1280 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
1281 //
1282 // Arguments:
1283 //    tree - the node
1284 //
1285 void CodeGen::genCodeForCompare(GenTreeOp* tree)
1286 {
1287     // TODO-ARM-CQ: Check if we can use the currently set flags.
1288     // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register
1289     //         (signed < or >= where targetReg != REG_NA)
1290
1291     GenTreePtr op1     = tree->gtOp1->gtEffectiveVal();
1292     GenTreePtr op2     = tree->gtOp2->gtEffectiveVal();
1293     var_types  op1Type = op1->TypeGet();
1294     var_types  op2Type = op2->TypeGet();
1295
1296     if (varTypeIsLong(op1Type))
1297     {
1298 #ifdef DEBUG
1299         // The result of an unlowered long compare on a 32-bit target must either be
1300         // a) materialized into a register, or
1301         // b) unused.
1302         //
1303         // A long compare that has a result that is used but not materialized into a register should
1304         // have been handled by Lowering::LowerCompare.
1305
1306         LIR::Use use;
1307         assert((tree->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(tree, &use));
1308 #endif
1309         genCompareLong(tree);
1310     }
1311     else
1312     {
1313         assert(!varTypeIsLong(op2Type));
1314
1315         regNumber targetReg = tree->gtRegNum;
1316         emitter*  emit      = getEmitter();
1317
1318         genConsumeIfReg(op1);
1319         genConsumeIfReg(op2);
1320
1321         if (varTypeIsFloating(op1Type))
1322         {
1323             assert(op1Type == op2Type);
1324             emit->emitInsBinary(INS_vcmp, emitTypeSize(op1Type), op1, op2);
1325             // vmrs with register 0xf has special meaning of transferring flags
1326             emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15);
1327         }
1328         else
1329         {
1330             assert(!varTypeIsFloating(op2Type));
1331             var_types cmpType = (op1Type == op2Type) ? op1Type : TYP_INT;
1332             emit->emitInsBinary(INS_cmp, emitTypeSize(cmpType), op1, op2);
1333         }
1334
1335         // Are we evaluating this into a register?
1336         if (targetReg != REG_NA)
1337         {
1338             genSetRegToCond(targetReg, tree);
1339             genProduceReg(tree);
1340         }
1341     }
1342 }
1343
1344 //------------------------------------------------------------------------
1345 // genCodeForJcc: Produce code for a GT_JCC node.
1346 //
1347 // Arguments:
1348 //    tree - the node
1349 //
1350 void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
1351 {
1352     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
1353
1354     CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
1355     emitJumpKind jumpKind    = genJumpKindForOper(tree->gtCondition, compareKind);
1356
1357     inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
1358 }
1359
1360 //------------------------------------------------------------------------
1361 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
1362 //
1363 // Arguments:
1364 //    tree - the GT_RETURNTRAP node
1365 //
1366 void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
1367 {
1368     assert(tree->OperGet() == GT_RETURNTRAP);
1369
1370     // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
1371     // based on the contents of 'data'
1372
1373     GenTree* data = tree->gtOp1->gtEffectiveVal();
1374     genConsumeIfReg(data);
1375     GenTreeIntCon cns = intForm(TYP_INT, 0);
1376     getEmitter()->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
1377
1378     BasicBlock* skipLabel = genCreateTempLabel();
1379
1380     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1381     inst_JMP(jmpEqual, skipLabel);
1382     // emit the call to the EE-helper that stops for GC (or other reasons)
1383
1384     genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
1385     genDefineTempLabel(skipLabel);
1386 }
1387
1388 //------------------------------------------------------------------------
1389 // genCodeForStoreInd: Produce code for a GT_STOREIND node.
1390 //
1391 // Arguments:
1392 //    tree - the GT_STOREIND node
1393 //
1394 void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
1395 {
1396     GenTree*  data       = tree->Data();
1397     GenTree*  addr       = tree->Addr();
1398     var_types targetType = tree->TypeGet();
1399     emitter*  emit       = getEmitter();
1400
1401     assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
1402
1403     GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
1404     if (writeBarrierForm != GCInfo::WBF_NoBarrier)
1405     {
1406         // data and addr must be in registers.
1407         // Consume both registers so that any copies of interfering
1408         // registers are taken care of.
1409         genConsumeOperands(tree);
1410
1411 #if NOGC_WRITE_BARRIERS
1412         NYI_ARM("NOGC_WRITE_BARRIERS");
1413 #else
1414         // At this point, we should not have any interference.
1415         // That is, 'data' must not be in REG_ARG_0,
1416         //  as that is where 'addr' must go.
1417         noway_assert(data->gtRegNum != REG_ARG_0);
1418
1419         // addr goes in REG_ARG_0
1420         if (addr->gtRegNum != REG_ARG_0)
1421         {
1422             inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
1423         }
1424
1425         // data goes in REG_ARG_1
1426         if (data->gtRegNum != REG_ARG_1)
1427         {
1428             inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
1429         }
1430 #endif // NOGC_WRITE_BARRIERS
1431
1432         genGCWriteBarrier(tree, writeBarrierForm);
1433     }
1434     else // A normal store, not a WriteBarrier store
1435     {
1436         bool dataIsUnary = false;
1437
1438         // We must consume the operands in the proper execution order,
1439         // so that liveness is updated appropriately.
1440         genConsumeAddress(addr);
1441
1442         if (!data->isContained())
1443         {
1444             genConsumeRegs(data);
1445         }
1446
1447         emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(tree), data->gtRegNum, tree);
1448     }
1449 }
1450
1451 //------------------------------------------------------------------------
1452 // genCompareLong: Generate code for comparing two longs when the result of the compare
1453 // is manifested in a register.
1454 //
1455 // Arguments:
1456 //    treeNode - the compare tree
1457 //
1458 // Return Value:
1459 //    None.
1460 //
1461 // Comments:
1462 // For long compares, we need to compare the high parts of operands first, then the low parts.
1463 // If the high compare is false, we do not need to compare the low parts. For less than and
1464 // greater than, if the high compare is true, we can assume the entire compare is true.
1465 //
1466 void CodeGen::genCompareLong(GenTreePtr treeNode)
1467 {
1468     assert(treeNode->OperIsCompare());
1469
1470     GenTreeOp* tree = treeNode->AsOp();
1471     GenTreePtr op1  = tree->gtOp1;
1472     GenTreePtr op2  = tree->gtOp2;
1473
1474     assert(varTypeIsLong(op1->TypeGet()));
1475     assert(varTypeIsLong(op2->TypeGet()));
1476
1477     regNumber targetReg = treeNode->gtRegNum;
1478
1479     genConsumeOperands(tree);
1480
1481     GenTreePtr loOp1 = op1->gtGetOp1();
1482     GenTreePtr hiOp1 = op1->gtGetOp2();
1483     GenTreePtr loOp2 = op2->gtGetOp1();
1484     GenTreePtr hiOp2 = op2->gtGetOp2();
1485
1486     // Create compare for the high parts
1487     instruction ins     = INS_cmp;
1488     var_types   cmpType = TYP_INT;
1489     emitAttr    cmpAttr = emitTypeSize(cmpType);
1490
1491     // Emit the compare instruction
1492     getEmitter()->emitInsBinary(ins, cmpAttr, hiOp1, hiOp2);
1493
1494     // If the result is not being materialized in a register, we're done.
1495     if (targetReg == REG_NA)
1496     {
1497         return;
1498     }
1499
1500     BasicBlock* labelTrue  = genCreateTempLabel();
1501     BasicBlock* labelFalse = genCreateTempLabel();
1502     BasicBlock* labelNext  = genCreateTempLabel();
1503
1504     genJccLongHi(tree->gtOper, labelTrue, labelFalse, tree->IsUnsigned());
1505     getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
1506     genJccLongLo(tree->gtOper, labelTrue, labelFalse);
1507
1508     genDefineTempLabel(labelFalse);
1509     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), tree->gtRegNum, 0);
1510     getEmitter()->emitIns_J(INS_b, labelNext);
1511
1512     genDefineTempLabel(labelTrue);
1513     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), tree->gtRegNum, 1);
1514
1515     genDefineTempLabel(labelNext);
1516
1517     genProduceReg(tree);
1518 }
1519
1520 void CodeGen::genJccLongHi(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse, bool isUnsigned)
1521 {
1522     if (cmp != GT_NE)
1523     {
1524         jumpFalse->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
1525     }
1526
1527     switch (cmp)
1528     {
1529         case GT_EQ:
1530             inst_JMP(EJ_ne, jumpFalse);
1531             break;
1532
1533         case GT_NE:
1534             inst_JMP(EJ_ne, jumpTrue);
1535             break;
1536
1537         case GT_LT:
1538         case GT_LE:
1539             if (isUnsigned)
1540             {
1541                 inst_JMP(EJ_hi, jumpFalse);
1542                 inst_JMP(EJ_lo, jumpTrue);
1543             }
1544             else
1545             {
1546                 inst_JMP(EJ_gt, jumpFalse);
1547                 inst_JMP(EJ_lt, jumpTrue);
1548             }
1549             break;
1550
1551         case GT_GE:
1552         case GT_GT:
1553             if (isUnsigned)
1554             {
1555                 inst_JMP(EJ_lo, jumpFalse);
1556                 inst_JMP(EJ_hi, jumpTrue);
1557             }
1558             else
1559             {
1560                 inst_JMP(EJ_lt, jumpFalse);
1561                 inst_JMP(EJ_gt, jumpTrue);
1562             }
1563             break;
1564
1565         default:
1566             noway_assert(!"expected a comparison operator");
1567     }
1568 }
1569
1570 void CodeGen::genJccLongLo(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse)
1571 {
1572     switch (cmp)
1573     {
1574         case GT_EQ:
1575             inst_JMP(EJ_eq, jumpTrue);
1576             break;
1577
1578         case GT_NE:
1579             inst_JMP(EJ_ne, jumpTrue);
1580             break;
1581
1582         case GT_LT:
1583             inst_JMP(EJ_lo, jumpTrue);
1584             break;
1585
1586         case GT_LE:
1587             inst_JMP(EJ_ls, jumpTrue);
1588             break;
1589
1590         case GT_GE:
1591             inst_JMP(EJ_hs, jumpTrue);
1592             break;
1593
1594         case GT_GT:
1595             inst_JMP(EJ_hi, jumpTrue);
1596             break;
1597
1598         default:
1599             noway_assert(!"expected comparison");
1600     }
1601 }
1602
1603 //------------------------------------------------------------------------
1604 // genSetRegToCond: Generate code to materialize a condition into a register.
1605 //
1606 // Arguments:
1607 //   dstReg - The target register to set to 1 or 0
1608 //   tree - The GenTree Relop node that was used to set the Condition codes
1609 //
1610 // Return Value: none
1611 //
1612 // Preconditions:
1613 //    The condition codes must already have been appropriately set.
1614 //
1615 void CodeGen::genSetRegToCond(regNumber dstReg, GenTreePtr tree)
1616 {
1617     // Emit code like that:
1618     //   ...
1619     //   bgt True
1620     //   movs rD, #0
1621     //   b Next
1622     // True:
1623     //   movs rD, #1
1624     // Next:
1625     //   ...
1626
1627     CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
1628     emitJumpKind jmpKind     = genJumpKindForOper(tree->gtOper, compareKind);
1629
1630     BasicBlock* labelTrue = genCreateTempLabel();
1631     getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmpKind), labelTrue);
1632
1633     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);
1634
1635     BasicBlock* labelNext = genCreateTempLabel();
1636     getEmitter()->emitIns_J(INS_b, labelNext);
1637
1638     genDefineTempLabel(labelTrue);
1639     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
1640     genDefineTempLabel(labelNext);
1641 }
1642
1643 //------------------------------------------------------------------------
1644 // genLongToIntCast: Generate code for long to int casts.
1645 //
1646 // Arguments:
1647 //    cast - The GT_CAST node
1648 //
1649 // Return Value:
1650 //    None.
1651 //
1652 // Assumptions:
1653 //    The cast node and its sources (via GT_LONG) must have been assigned registers.
1654 //    The destination cannot be a floating point type or a small integer type.
1655 //
1656 void CodeGen::genLongToIntCast(GenTree* cast)
1657 {
1658     assert(cast->OperGet() == GT_CAST);
1659
1660     GenTree* src = cast->gtGetOp1();
1661     noway_assert(src->OperGet() == GT_LONG);
1662
1663     genConsumeRegs(src);
1664
1665     var_types srcType  = ((cast->gtFlags & GTF_UNSIGNED) != 0) ? TYP_ULONG : TYP_LONG;
1666     var_types dstType  = cast->CastToType();
1667     regNumber loSrcReg = src->gtGetOp1()->gtRegNum;
1668     regNumber hiSrcReg = src->gtGetOp2()->gtRegNum;
1669     regNumber dstReg   = cast->gtRegNum;
1670
1671     assert((dstType == TYP_INT) || (dstType == TYP_UINT));
1672     assert(genIsValidIntReg(loSrcReg));
1673     assert(genIsValidIntReg(hiSrcReg));
1674     assert(genIsValidIntReg(dstReg));
1675
1676     if (cast->gtOverflow())
1677     {
1678         //
1679         // Generate an overflow check for [u]long to [u]int casts:
1680         //
1681         // long  -> int  - check if the upper 33 bits are all 0 or all 1
1682         //
1683         // ulong -> int  - check if the upper 33 bits are all 0
1684         //
1685         // long  -> uint - check if the upper 32 bits are all 0
1686         // ulong -> uint - check if the upper 32 bits are all 0
1687         //
1688
1689         if ((srcType == TYP_LONG) && (dstType == TYP_INT))
1690         {
1691             BasicBlock* allOne  = genCreateTempLabel();
1692             BasicBlock* success = genCreateTempLabel();
1693
1694             inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1695             emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1696             inst_JMP(JmpNegative, allOne);
1697             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1698             emitJumpKind jmpNotEqualL = genJumpKindForOper(GT_NE, CK_LOGICAL);
1699             genJumpToThrowHlpBlk(jmpNotEqualL, SCK_OVERFLOW);
1700             inst_JMP(EJ_jmp, success);
1701
1702             genDefineTempLabel(allOne);
1703             inst_RV_IV(INS_cmp, hiSrcReg, -1, EA_4BYTE);
1704             emitJumpKind jmpNotEqualS = genJumpKindForOper(GT_NE, CK_SIGNED);
1705             genJumpToThrowHlpBlk(jmpNotEqualS, SCK_OVERFLOW);
1706
1707             genDefineTempLabel(success);
1708         }
1709         else
1710         {
1711             if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
1712             {
1713                 inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1714                 emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1715                 genJumpToThrowHlpBlk(JmpNegative, SCK_OVERFLOW);
1716             }
1717
1718             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1719             emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_LOGICAL);
1720             genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
1721         }
1722     }
1723
1724     if (dstReg != loSrcReg)
1725     {
1726         inst_RV_RV(INS_mov, dstReg, loSrcReg, TYP_INT, EA_4BYTE);
1727     }
1728
1729     genProduceReg(cast);
1730 }
1731
1732 //------------------------------------------------------------------------
1733 // genIntToFloatCast: Generate code to cast an int/long to float/double
1734 //
1735 // Arguments:
1736 //    treeNode - The GT_CAST node
1737 //
1738 // Return Value:
1739 //    None.
1740 //
1741 // Assumptions:
1742 //    Cast is a non-overflow conversion.
1743 //    The treeNode must have an assigned register.
1744 //    SrcType= int32/uint32/int64/uint64 and DstType=float/double.
1745 //
1746 void CodeGen::genIntToFloatCast(GenTreePtr treeNode)
1747 {
1748     // int --> float/double conversions are always non-overflow ones
1749     assert(treeNode->OperGet() == GT_CAST);
1750     assert(!treeNode->gtOverflow());
1751
1752     regNumber targetReg = treeNode->gtRegNum;
1753     assert(genIsValidFloatReg(targetReg));
1754
1755     GenTreePtr op1 = treeNode->gtOp.gtOp1;
1756     assert(!op1->isContained());             // Cannot be contained
1757     assert(genIsValidIntReg(op1->gtRegNum)); // Must be a valid int reg.
1758
1759     var_types dstType = treeNode->CastToType();
1760     var_types srcType = op1->TypeGet();
1761     assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
1762
1763     // force the srcType to unsigned if GT_UNSIGNED flag is set
1764     if (treeNode->gtFlags & GTF_UNSIGNED)
1765     {
1766         srcType = genUnsignedType(srcType);
1767     }
1768
1769     // We should never see a srcType whose size is neither EA_4BYTE or EA_8BYTE
1770     // For conversions from small types (byte/sbyte/int16/uint16) to float/double,
1771     // we expect the front-end or lowering phase to have generated two levels of cast.
1772     //
1773     emitAttr srcSize = EA_ATTR(genTypeSize(srcType));
1774     noway_assert((srcSize == EA_4BYTE) || (srcSize == EA_8BYTE));
1775
1776     instruction insVcvt = INS_invalid;
1777
1778     if (dstType == TYP_DOUBLE)
1779     {
1780         if (srcSize == EA_4BYTE)
1781         {
1782             insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2d : INS_vcvt_i2d;
1783         }
1784         else
1785         {
1786             assert(srcSize == EA_8BYTE);
1787             NYI_ARM("Casting int64/uint64 to double in genIntToFloatCast");
1788         }
1789     }
1790     else
1791     {
1792         assert(dstType == TYP_FLOAT);
1793         if (srcSize == EA_4BYTE)
1794         {
1795             insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2f : INS_vcvt_i2f;
1796         }
1797         else
1798         {
1799             assert(srcSize == EA_8BYTE);
1800             NYI_ARM("Casting int64/uint64 to float in genIntToFloatCast");
1801         }
1802     }
1803
1804     genConsumeOperands(treeNode->AsOp());
1805
1806     assert(insVcvt != INS_invalid);
1807     getEmitter()->emitIns_R_R(INS_vmov_i2f, srcSize, treeNode->gtRegNum, op1->gtRegNum);
1808     getEmitter()->emitIns_R_R(insVcvt, srcSize, treeNode->gtRegNum, treeNode->gtRegNum);
1809
1810     genProduceReg(treeNode);
1811 }
1812
1813 //------------------------------------------------------------------------
1814 // genFloatToIntCast: Generate code to cast float/double to int/long
1815 //
1816 // Arguments:
1817 //    treeNode - The GT_CAST node
1818 //
1819 // Return Value:
1820 //    None.
1821 //
1822 // Assumptions:
1823 //    Cast is a non-overflow conversion.
1824 //    The treeNode must have an assigned register.
1825 //    SrcType=float/double and DstType= int32/uint32/int64/uint64
1826 //
1827 void CodeGen::genFloatToIntCast(GenTreePtr treeNode)
1828 {
1829     // we don't expect to see overflow detecting float/double --> int type conversions here
1830     // as they should have been converted into helper calls by front-end.
1831     assert(treeNode->OperGet() == GT_CAST);
1832     assert(!treeNode->gtOverflow());
1833
1834     regNumber targetReg = treeNode->gtRegNum;
1835     assert(genIsValidIntReg(targetReg)); // Must be a valid int reg.
1836
1837     GenTreePtr op1 = treeNode->gtOp.gtOp1;
1838     assert(!op1->isContained());               // Cannot be contained
1839     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
1840
1841     var_types dstType = treeNode->CastToType();
1842     var_types srcType = op1->TypeGet();
1843     assert(varTypeIsFloating(srcType) && !varTypeIsFloating(dstType));
1844
1845     // We should never see a dstType whose size is neither EA_4BYTE or EA_8BYTE
1846     // For conversions to small types (byte/sbyte/int16/uint16) from float/double,
1847     // we expect the front-end or lowering phase to have generated two levels of cast.
1848     //
1849     emitAttr dstSize = EA_ATTR(genTypeSize(dstType));
1850     noway_assert((dstSize == EA_4BYTE) || (dstSize == EA_8BYTE));
1851
1852     instruction insVcvt = INS_invalid;
1853
1854     if (srcType == TYP_DOUBLE)
1855     {
1856         if (dstSize == EA_4BYTE)
1857         {
1858             insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_d2u : INS_vcvt_d2i;
1859         }
1860         else
1861         {
1862             assert(dstSize == EA_8BYTE);
1863             NYI_ARM("Casting double to int64/uint64 in genIntToFloatCast");
1864         }
1865     }
1866     else
1867     {
1868         assert(srcType == TYP_FLOAT);
1869         if (dstSize == EA_4BYTE)
1870         {
1871             insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_f2u : INS_vcvt_f2i;
1872         }
1873         else
1874         {
1875             assert(dstSize == EA_8BYTE);
1876             NYI_ARM("Casting float to int64/uint64 in genIntToFloatCast");
1877         }
1878     }
1879
1880     genConsumeOperands(treeNode->AsOp());
1881
1882     assert(insVcvt != INS_invalid);
1883     getEmitter()->emitIns_R_R(insVcvt, dstSize, op1->gtRegNum, op1->gtRegNum);
1884     getEmitter()->emitIns_R_R(INS_vmov_f2i, dstSize, treeNode->gtRegNum, op1->gtRegNum);
1885
1886     genProduceReg(treeNode);
1887 }
1888
1889 //------------------------------------------------------------------------
1890 // genEmitHelperCall: Emit a call to a helper function.
1891 //
1892 void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
1893 {
1894     // Can we call the helper function directly
1895
1896     void *addr = NULL, **pAddr = NULL;
1897
1898 #if defined(DEBUG) && defined(PROFILING_SUPPORTED)
1899     // Don't ask VM if it hasn't requested ELT hooks
1900     if (!compiler->compProfilerHookNeeded && compiler->opts.compJitELTHookEnabled &&
1901         (helper == CORINFO_HELP_PROF_FCN_ENTER || helper == CORINFO_HELP_PROF_FCN_LEAVE ||
1902          helper == CORINFO_HELP_PROF_FCN_TAILCALL))
1903     {
1904         addr = compiler->compProfilerMethHnd;
1905     }
1906     else
1907 #endif
1908     {
1909         addr = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, (void**)&pAddr);
1910     }
1911
1912     if (!addr || !arm_Valid_Imm_For_BL((ssize_t)addr))
1913     {
1914         if (callTargetReg == REG_NA)
1915         {
1916             // If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
1917             // this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
1918             callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
1919         }
1920
1921         // Load the address into a register and call through a register
1922         if (addr)
1923         {
1924             instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, callTargetReg, (ssize_t)addr);
1925         }
1926         else
1927         {
1928             getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, callTargetReg, (ssize_t)pAddr);
1929             regTracker.rsTrackRegTrash(callTargetReg);
1930         }
1931
1932         getEmitter()->emitIns_Call(emitter::EC_INDIR_R, compiler->eeFindHelper(helper),
1933                                    INDEBUG_LDISASM_COMMA(nullptr) NULL, // addr
1934                                    argSize, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
1935                                    gcInfo.gcRegByrefSetCur,
1936                                    BAD_IL_OFFSET, // ilOffset
1937                                    callTargetReg, // ireg
1938                                    REG_NA, 0, 0,  // xreg, xmul, disp
1939                                    false,         // isJump
1940                                    emitter::emitNoGChelper(helper),
1941                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
1942     }
1943     else
1944     {
1945         getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, compiler->eeFindHelper(helper),
1946                                    INDEBUG_LDISASM_COMMA(nullptr) addr, argSize, retSize, gcInfo.gcVarPtrSetCur,
1947                                    gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
1948                                    0,     /* ilOffset, ireg, xreg, xmul, disp */
1949                                    false, /* isJump */
1950                                    emitter::emitNoGChelper(helper),
1951                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
1952     }
1953
1954     regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
1955     regTracker.rsTrashRegsForGCInterruptability();
1956 }
1957
1958 //------------------------------------------------------------------------
1959 // genStoreLongLclVar: Generate code to store a non-enregistered long lclVar
1960 //
1961 // Arguments:
1962 //    treeNode - A TYP_LONG lclVar node.
1963 //
1964 // Return Value:
1965 //    None.
1966 //
1967 // Assumptions:
1968 //    'treeNode' must be a TYP_LONG lclVar node for a lclVar that has NOT been promoted.
1969 //    Its operand must be a GT_LONG node.
1970 //
1971 void CodeGen::genStoreLongLclVar(GenTree* treeNode)
1972 {
1973     emitter* emit = getEmitter();
1974
1975     GenTreeLclVarCommon* lclNode = treeNode->AsLclVarCommon();
1976     unsigned             lclNum  = lclNode->gtLclNum;
1977     LclVarDsc*           varDsc  = &(compiler->lvaTable[lclNum]);
1978     assert(varDsc->TypeGet() == TYP_LONG);
1979     assert(!varDsc->lvPromoted);
1980     GenTreePtr op1 = treeNode->gtOp.gtOp1;
1981     noway_assert(op1->OperGet() == GT_LONG || op1->OperGet() == GT_MUL_LONG);
1982     genConsumeRegs(op1);
1983
1984     if (op1->OperGet() == GT_LONG)
1985     {
1986         // Definitions of register candidates will have been lowered to 2 int lclVars.
1987         assert(!treeNode->InReg());
1988
1989         GenTreePtr loVal = op1->gtGetOp1();
1990         GenTreePtr hiVal = op1->gtGetOp2();
1991
1992         // NYI: Contained immediates.
1993         NYI_IF((loVal->gtRegNum == REG_NA) || (hiVal->gtRegNum == REG_NA),
1994                "Store of long lclVar with contained immediate");
1995
1996         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, loVal->gtRegNum, lclNum, 0);
1997         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, hiVal->gtRegNum, lclNum, genTypeSize(TYP_INT));
1998     }
1999     else if (op1->OperGet() == GT_MUL_LONG)
2000     {
2001         assert((op1->gtFlags & GTF_MUL_64RSLT) != 0);
2002
2003         // Stack store
2004         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_LO, lclNum, 0);
2005         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_HI, lclNum,
2006                                   genTypeSize(TYP_INT));
2007     }
2008 }
2009
2010 #endif // _TARGET_ARM_
2011
2012 #endif // !LEGACY_BACKEND