Fix reading Time zone rules using Julian days (#17672)
[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     genMov32RelocatableDisplacement(bbFinallyRet, REG_LR);
48
49     // Jump to the finally BB
50     inst_JMP(EJ_jmp, block->bbJumpDest);
51
52     // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the
53     // jump target using bbJumpDest - that is already used to point
54     // to the finally block. So just skip past the BBJ_ALWAYS unless the
55     // block is RETLESS.
56     assert(!(block->bbFlags & BBF_RETLESS_CALL));
57     assert(block->isBBCallAlwaysPair());
58     return block->bbNext;
59 }
60
61 //------------------------------------------------------------------------
62 // genEHCatchRet:
63 void CodeGen::genEHCatchRet(BasicBlock* block)
64 {
65     genMov32RelocatableDisplacement(block->bbJumpDest, REG_INTRET);
66 }
67
68 //------------------------------------------------------------------------
69 // instGen_Set_Reg_To_Imm: Move an immediate value into an integer register.
70 //
71 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
72 {
73     // reg cannot be a FP register
74     assert(!genIsValidFloatReg(reg));
75
76     if (!compiler->opts.compReloc)
77     {
78         size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
79     }
80
81     if (EA_IS_RELOC(size))
82     {
83         genMov32RelocatableImmediate(size, imm, reg);
84     }
85     else if (imm == 0)
86     {
87         instGen_Set_Reg_To_Zero(size, reg, flags);
88     }
89     else
90     {
91         if (arm_Valid_Imm_For_Mov(imm))
92         {
93             getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
94         }
95         else // We have to use a movw/movt pair of instructions
96         {
97             ssize_t imm_lo16 = (imm & 0xffff);
98             ssize_t imm_hi16 = (imm >> 16) & 0xffff;
99
100             assert(arm_Valid_Imm_For_Mov(imm_lo16));
101             assert(imm_hi16 != 0);
102
103             getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
104
105             // If we've got a low register, the high word is all bits set,
106             // and the high bit of the low word is set, we can sign extend
107             // halfword and save two bytes of encoding. This can happen for
108             // small magnitude negative numbers 'n' for -32768 <= n <= -1.
109
110             if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
111             {
112                 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
113             }
114             else
115             {
116                 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
117             }
118
119             if (flags == INS_FLAGS_SET)
120                 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
121         }
122     }
123
124     regTracker.rsTrackRegIntCns(reg, imm);
125 }
126
127 //------------------------------------------------------------------------
128 // genSetRegToConst: Generate code to set a register 'targetReg' of type 'targetType'
129 //    to the constant specified by the constant (GT_CNS_INT or GT_CNS_DBL) in 'tree'.
130 //
131 // Notes:
132 //    This does not call genProduceReg() on the target register.
133 //
134 void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree)
135 {
136     switch (tree->gtOper)
137     {
138         case GT_CNS_INT:
139         {
140             // relocatable values tend to come down as a CNS_INT of native int type
141             // so the line between these two opcodes is kind of blurry
142             GenTreeIntConCommon* con    = tree->AsIntConCommon();
143             ssize_t              cnsVal = con->IconValue();
144
145             if (con->ImmedValNeedsReloc(compiler))
146             {
147                 instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
148                 regTracker.rsTrackRegTrash(targetReg);
149             }
150             else
151             {
152                 genSetRegToIcon(targetReg, cnsVal, targetType);
153             }
154         }
155         break;
156
157         case GT_CNS_DBL:
158         {
159             GenTreeDblCon* dblConst   = tree->AsDblCon();
160             double         constValue = dblConst->gtDblCon.gtDconVal;
161             // TODO-ARM-CQ: Do we have a faster/smaller way to generate 0.0 in thumb2 ISA ?
162             if (targetType == TYP_FLOAT)
163             {
164                 // Get a temp integer register
165                 regNumber tmpReg = tree->GetSingleTempReg();
166
167                 float f = forceCastToFloat(constValue);
168                 genSetRegToIcon(tmpReg, *((int*)(&f)));
169                 getEmitter()->emitIns_R_R(INS_vmov_i2f, EA_4BYTE, targetReg, tmpReg);
170             }
171             else
172             {
173                 assert(targetType == TYP_DOUBLE);
174
175                 unsigned* cv = (unsigned*)&constValue;
176
177                 // Get two temp integer registers
178                 regNumber tmpReg1 = tree->ExtractTempReg();
179                 regNumber tmpReg2 = tree->GetSingleTempReg();
180
181                 genSetRegToIcon(tmpReg1, cv[0]);
182                 genSetRegToIcon(tmpReg2, cv[1]);
183
184                 getEmitter()->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, tmpReg1, tmpReg2);
185             }
186         }
187         break;
188
189         default:
190             unreached();
191     }
192 }
193
194 //------------------------------------------------------------------------
195 // genCodeForBinary: Generate code for many binary arithmetic operators
196 // This method is expected to have called genConsumeOperands() before calling it.
197 //
198 // Arguments:
199 //    treeNode - The binary operation for which we are generating code.
200 //
201 // Return Value:
202 //    None.
203 //
204 // Notes:
205 //    Mul and div are not handled here.
206 //    See the assert below for the operators that are handled.
207
208 void CodeGen::genCodeForBinary(GenTree* treeNode)
209 {
210     const genTreeOps oper       = treeNode->OperGet();
211     regNumber        targetReg  = treeNode->gtRegNum;
212     var_types        targetType = treeNode->TypeGet();
213     emitter*         emit       = getEmitter();
214
215     assert(oper == GT_ADD || oper == GT_SUB || oper == GT_MUL || oper == GT_ADD_LO || oper == GT_ADD_HI ||
216            oper == GT_SUB_LO || oper == GT_SUB_HI || oper == GT_OR || oper == GT_XOR || oper == GT_AND);
217
218     GenTree* op1 = treeNode->gtGetOp1();
219     GenTree* op2 = treeNode->gtGetOp2();
220
221     instruction ins = genGetInsForOper(oper, targetType);
222
223     // The arithmetic node must be sitting in a register (since it's not contained)
224     noway_assert(targetReg != REG_NA);
225
226     if ((oper == GT_ADD_LO || oper == GT_SUB_LO))
227     {
228         // During decomposition, all operands become reg
229         assert(!op1->isContained() && !op2->isContained());
230         emit->emitIns_R_R_R(ins, emitTypeSize(treeNode), treeNode->gtRegNum, op1->gtRegNum, op2->gtRegNum,
231                             INS_FLAGS_SET);
232     }
233     else
234     {
235         regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2);
236         assert(r == targetReg);
237     }
238
239     genProduceReg(treeNode);
240 }
241
242 //--------------------------------------------------------------------------------------
243 // genLclHeap: Generate code for localloc
244 //
245 // Description:
246 //      There are 2 ways depending from build version to generate code for localloc:
247 //          1) For debug build where memory should be initialized we generate loop
248 //             which invoke push {tmpReg} N times.
249 //          2) For non-debug build, we tickle the pages to ensure that SP is always
250 //             valid and is in sync with the "stack guard page". Amount of iteration
251 //             is N/eeGetPageSize().
252 //
253 // Comments:
254 //      There can be some optimization:
255 //          1) It's not needed to generate loop for zero size allocation
256 //          2) For small allocation (less than 4 store) we unroll loop
257 //          3) For allocation less than eeGetPageSize() and when it's not needed to initialize
258 //             memory to zero, we can just decrement SP.
259 //
260 // Notes: Size N should be aligned to STACK_ALIGN before any allocation
261 //
262 void CodeGen::genLclHeap(GenTree* tree)
263 {
264     assert(tree->OperGet() == GT_LCLHEAP);
265
266     GenTree* size = tree->gtOp.gtOp1;
267     noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
268
269     // Result of localloc will be returned in regCnt.
270     // Also it used as temporary register in code generation
271     // for storing allocation size
272     regNumber   regCnt          = tree->gtRegNum;
273     regNumber   pspSymReg       = REG_NA;
274     var_types   type            = genActualType(size->gtType);
275     emitAttr    easz            = emitTypeSize(type);
276     BasicBlock* endLabel        = nullptr;
277     BasicBlock* loop            = nullptr;
278     unsigned    stackAdjustment = 0;
279
280 #ifdef DEBUG
281     // Verify ESP
282     if (compiler->opts.compStackCheckOnRet)
283     {
284         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
285                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
286                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
287         getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
288
289         BasicBlock*  esp_check = genCreateTempLabel();
290         emitJumpKind jmpEqual  = genJumpKindForOper(GT_EQ, CK_SIGNED);
291         inst_JMP(jmpEqual, esp_check);
292         getEmitter()->emitIns(INS_BREAKPOINT);
293         genDefineTempLabel(esp_check);
294     }
295 #endif
296
297     noway_assert(isFramePointerUsed()); // localloc requires Frame Pointer to be established since SP changes
298     noway_assert(genStackLevel == 0);   // Can't have anything on the stack
299
300     // Whether method has PSPSym.
301     bool hasPspSym;
302 #if FEATURE_EH_FUNCLETS
303     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
304 #else
305     hasPspSym = false;
306 #endif
307
308     // Check to 0 size allocations
309     // size_t amount = 0;
310     if (size->IsCnsIntOrI())
311     {
312         // If size is a constant, then it must be contained.
313         assert(size->isContained());
314
315         // If amount is zero then return null in regCnt
316         size_t amount = size->gtIntCon.gtIconVal;
317         if (amount == 0)
318         {
319             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
320             goto BAILOUT;
321         }
322     }
323     else
324     {
325         // If 0 bail out by returning null in regCnt
326         genConsumeRegAndCopy(size, regCnt);
327         endLabel = genCreateTempLabel();
328         getEmitter()->emitIns_R_R(INS_TEST, easz, regCnt, regCnt);
329         emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
330         inst_JMP(jmpEqual, endLabel);
331     }
332
333     stackAdjustment = 0;
334 #if FEATURE_EH_FUNCLETS
335     // If we have PSPsym, then need to re-locate it after localloc.
336     if (hasPspSym)
337     {
338         stackAdjustment += STACK_ALIGN;
339
340         // Save a copy of PSPSym
341         pspSymReg = tree->ExtractTempReg();
342         getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
343     }
344 #endif
345
346 #if FEATURE_FIXED_OUT_ARGS
347     // If we have an outgoing arg area then we must adjust the SP by popping off the
348     // outgoing arg area. We will restore it right before we return from this method.
349     if (compiler->lvaOutgoingArgSpaceSize > 0)
350     {
351         assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain
352                                                                         // aligned
353         inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
354         stackAdjustment += compiler->lvaOutgoingArgSpaceSize;
355     }
356 #endif
357
358     // Put aligned allocation size to regCnt
359     if (size->IsCnsIntOrI())
360     {
361         // 'amount' is the total number of bytes to localloc to properly STACK_ALIGN
362         size_t amount = size->gtIntCon.gtIconVal;
363         amount        = AlignUp(amount, STACK_ALIGN);
364
365         // For small allocations we will generate up to four stp instructions
366         size_t cntStackAlignedWidthItems = (amount >> STACK_ALIGN_SHIFT);
367         if (cntStackAlignedWidthItems <= 4)
368         {
369             instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
370
371             while (cntStackAlignedWidthItems != 0)
372             {
373                 inst_IV(INS_push, (unsigned)genRegMask(regCnt));
374                 cntStackAlignedWidthItems -= 1;
375             }
376
377             goto ALLOC_DONE;
378         }
379         else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
380         {
381             // Since the size is a page or less, simply adjust the SP value
382             // The SP might already be in the guard page, must touch it BEFORE
383             // the alloc, not after.
384             getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regCnt, REG_SP, 0);
385             inst_RV_IV(INS_sub, REG_SP, amount, EA_PTRSIZE);
386             goto ALLOC_DONE;
387         }
388
389         // regCnt will be the total number of bytes to locAlloc
390         genSetRegToIcon(regCnt, amount, ((int)amount == amount) ? TYP_INT : TYP_LONG);
391     }
392     else
393     {
394         // Round up the number of bytes to allocate to a STACK_ALIGN boundary.
395         inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
396         inst_RV_IV(INS_AND, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
397     }
398
399     // Allocation
400     if (compiler->info.compInitMem)
401     {
402         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
403         // Since we have to zero out the allocated memory AND ensure that RSP is always valid
404         // by tickling the pages, we will just push 0's on the stack.
405
406         regNumber regTmp = tree->ExtractTempReg();
407         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regTmp);
408
409         // Loop:
410         BasicBlock* loop = genCreateTempLabel();
411         genDefineTempLabel(loop);
412
413         noway_assert(STACK_ALIGN == 8);
414         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
415         inst_IV(INS_push, (unsigned)genRegMask(regTmp));
416
417         // If not done, loop
418         // Note that regCnt is the number of bytes to stack allocate.
419         assert(genIsValidIntReg(regCnt));
420         getEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, regCnt, STACK_ALIGN, INS_FLAGS_SET);
421         emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
422         inst_JMP(jmpNotEqual, loop);
423     }
424     else
425     {
426         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
427         //
428         // We don't need to zero out the allocated memory. However, we do have
429         // to tickle the pages to ensure that SP is always valid and is
430         // in sync with the "stack guard page".  Note that in the worst
431         // case SP is on the last byte of the guard page.  Thus you must
432         // touch SP-0 first not SP-0x1000.
433         //
434         // Another subtlety is that you don't want SP to be exactly on the
435         // boundary of the guard page because PUSH is predecrement, thus
436         // call setup would not touch the guard page but just beyond it
437         //
438         // Note that we go through a few hoops so that SP never points to
439         // illegal pages at any time during the tickling process
440         //
441         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
442         //       bvc   Loop                    // result is smaller than original SP (no wrap around)
443         //       mov   regCnt, #0              // Overflow, pick lowest possible value
444         //
445         //  Loop:
446         //       ldr   regTmp, [SP + 0]        // tickle the page - read from the page
447         //       sub   regTmp, SP, PAGE_SIZE   // decrement SP by eeGetPageSize()
448         //       cmp   regTmp, regCnt
449         //       jb    Done
450         //       mov   SP, regTmp
451         //       j     Loop
452         //
453         //  Done:
454         //       mov   SP, regCnt
455         //
456
457         // Setup the regTmp
458         regNumber regTmp = tree->ExtractTempReg();
459
460         BasicBlock* loop = genCreateTempLabel();
461         BasicBlock* done = genCreateTempLabel();
462
463         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
464         getEmitter()->emitIns_R_R_R(INS_sub, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt, INS_FLAGS_SET);
465
466         inst_JMP(EJ_vc, loop); // branch if the V flag is not set
467
468         // Overflow, set regCnt to lowest possible value
469         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
470
471         genDefineTempLabel(loop);
472
473         // tickle the page - Read from the updated SP - this triggers a page fault when on the guard page
474         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, regTmp, REG_SPBASE, 0);
475
476         // decrement SP by eeGetPageSize()
477         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());
478
479         getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
480         emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
481         inst_JMP(jmpLTU, done);
482
483         // Update SP to be at the next page of stack that we will tickle
484         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regTmp);
485
486         // Jump to loop and tickle new stack address
487         inst_JMP(EJ_jmp, loop);
488
489         // Done with stack tickle loop
490         genDefineTempLabel(done);
491
492         // Now just move the final value to SP
493         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
494     }
495
496 ALLOC_DONE:
497     // Re-adjust SP to allocate PSPSym and out-going arg area
498     if (stackAdjustment != 0)
499     {
500         assert((stackAdjustment % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
501         assert(stackAdjustment > 0);
502         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, (int)stackAdjustment);
503
504 #if FEATURE_EH_FUNCLETS
505         // Write PSPSym to its new location.
506         if (hasPspSym)
507         {
508             assert(genIsValidIntReg(pspSymReg));
509             getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
510         }
511 #endif
512         // Return the stackalloc'ed address in result register.
513         // regCnt = RSP + stackAdjustment.
514         getEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, regCnt, REG_SPBASE, (int)stackAdjustment);
515     }
516     else // stackAdjustment == 0
517     {
518         // Move the final value of SP to regCnt
519         inst_RV_RV(INS_mov, regCnt, REG_SPBASE);
520     }
521
522 BAILOUT:
523     if (endLabel != nullptr)
524         genDefineTempLabel(endLabel);
525
526     // Write the lvaLocAllocSPvar stack frame slot
527     if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
528     {
529         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaLocAllocSPvar, 0);
530     }
531
532 #if STACK_PROBES
533     if (compiler->opts.compNeedStackProbes)
534     {
535         genGenerateStackProbe();
536     }
537 #endif
538
539 #ifdef DEBUG
540     // Update new ESP
541     if (compiler->opts.compStackCheckOnRet)
542     {
543         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
544                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
545                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
546         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaReturnEspCheck, 0);
547     }
548 #endif
549
550     genProduceReg(tree);
551 }
552
553 //------------------------------------------------------------------------
554 // genTableBasedSwitch: generate code for a switch statement based on a table of ip-relative offsets
555 //
556 void CodeGen::genTableBasedSwitch(GenTree* treeNode)
557 {
558     genConsumeOperands(treeNode->AsOp());
559     regNumber idxReg  = treeNode->gtOp.gtOp1->gtRegNum;
560     regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
561
562     getEmitter()->emitIns_R_ARX(INS_ldr, EA_4BYTE, REG_PC, baseReg, idxReg, TARGET_POINTER_SIZE, 0);
563 }
564
565 //------------------------------------------------------------------------
566 // genJumpTable: emits the table and an instruction to get the address of the first element
567 //
568 void CodeGen::genJumpTable(GenTree* treeNode)
569 {
570     noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
571     assert(treeNode->OperGet() == GT_JMPTABLE);
572
573     unsigned     jumpCount = compiler->compCurBB->bbJumpSwt->bbsCount;
574     BasicBlock** jumpTable = compiler->compCurBB->bbJumpSwt->bbsDstTab;
575     unsigned     jmpTabBase;
576
577     jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCount, false);
578
579     JITDUMP("\n      J_M%03u_DS%02u LABEL   DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
580
581     for (unsigned i = 0; i < jumpCount; i++)
582     {
583         BasicBlock* target = *jumpTable++;
584         noway_assert(target->bbFlags & BBF_JMP_TARGET);
585
586         JITDUMP("            DD      L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
587
588         getEmitter()->emitDataGenData(i, target);
589     }
590
591     getEmitter()->emitDataGenEnd();
592
593     genMov32RelocatableDataLabel(jmpTabBase, treeNode->gtRegNum);
594
595     genProduceReg(treeNode);
596 }
597
598 //------------------------------------------------------------------------
599 // genGetInsForOper: Return instruction encoding of the operation tree.
600 //
601 instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
602 {
603     instruction ins;
604
605     if (varTypeIsFloating(type))
606         return CodeGen::ins_MathOp(oper, type);
607
608     switch (oper)
609     {
610         case GT_ADD:
611             ins = INS_add;
612             break;
613         case GT_AND:
614             ins = INS_AND;
615             break;
616         case GT_MUL:
617             ins = INS_MUL;
618             break;
619 #if !defined(USE_HELPERS_FOR_INT_DIV)
620         case GT_DIV:
621             ins = INS_sdiv;
622             break;
623 #endif // !USE_HELPERS_FOR_INT_DIV
624         case GT_LSH:
625             ins = INS_SHIFT_LEFT_LOGICAL;
626             break;
627         case GT_NEG:
628             ins = INS_rsb;
629             break;
630         case GT_NOT:
631             ins = INS_NOT;
632             break;
633         case GT_OR:
634             ins = INS_OR;
635             break;
636         case GT_RSH:
637             ins = INS_SHIFT_RIGHT_ARITHM;
638             break;
639         case GT_RSZ:
640             ins = INS_SHIFT_RIGHT_LOGICAL;
641             break;
642         case GT_SUB:
643             ins = INS_sub;
644             break;
645         case GT_XOR:
646             ins = INS_XOR;
647             break;
648         case GT_ROR:
649             ins = INS_ror;
650             break;
651         case GT_ADD_LO:
652             ins = INS_add;
653             break;
654         case GT_ADD_HI:
655             ins = INS_adc;
656             break;
657         case GT_SUB_LO:
658             ins = INS_sub;
659             break;
660         case GT_SUB_HI:
661             ins = INS_sbc;
662             break;
663         case GT_LSH_HI:
664             ins = INS_SHIFT_LEFT_LOGICAL;
665             break;
666         case GT_RSH_LO:
667             ins = INS_SHIFT_RIGHT_LOGICAL;
668             break;
669         default:
670             unreached();
671             break;
672     }
673     return ins;
674 }
675
676 // Generate code for InitBlk by performing a loop unroll
677 // Preconditions:
678 //   a) Both the size and fill byte value are integer constants.
679 //   b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
680 void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
681 {
682     // TODO: Generate memory barrier instructions for GTF_BLK_VOLATILE flag
683     NYI_ARM("genCodeForInitBlkUnroll");
684 }
685
686 //------------------------------------------------------------------------
687 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
688 //
689 // Arguments:
690 //    tree - the node
691 //
692 void CodeGen::genCodeForNegNot(GenTree* tree)
693 {
694     assert(tree->OperIs(GT_NEG, GT_NOT));
695
696     var_types targetType = tree->TypeGet();
697
698     assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
699
700     regNumber   targetReg = tree->gtRegNum;
701     instruction ins       = genGetInsForOper(tree->OperGet(), targetType);
702
703     // The arithmetic node must be sitting in a register (since it's not contained)
704     assert(!tree->isContained());
705     // The dst can only be a register.
706     assert(targetReg != REG_NA);
707
708     GenTree* operand = tree->gtGetOp1();
709     assert(!operand->isContained());
710     // The src must be a register.
711     regNumber operandReg = genConsumeReg(operand);
712
713     if (ins == INS_vneg)
714     {
715         getEmitter()->emitIns_R_R(ins, emitTypeSize(tree), targetReg, operandReg);
716     }
717     else
718     {
719         getEmitter()->emitIns_R_R_I(ins, emitTypeSize(tree), targetReg, operandReg, 0, INS_FLAGS_SET);
720     }
721
722     genProduceReg(tree);
723 }
724
725 // Generate code for CpObj nodes wich copy structs that have interleaved
726 // GC pointers.
727 // For this case we'll generate a sequence of loads/stores in the case of struct
728 // slots that don't contain GC pointers.  The generated code will look like:
729 // ldr tempReg, [R13, #8]
730 // str tempReg, [R14, #8]
731 //
732 // In the case of a GC-Pointer we'll call the ByRef write barrier helper
733 // who happens to use the same registers as the previous call to maintain
734 // the same register requirements and register killsets:
735 // bl CORINFO_HELP_ASSIGN_BYREF
736 //
737 // So finally an example would look like this:
738 // ldr tempReg, [R13, #8]
739 // str tempReg, [R14, #8]
740 // bl CORINFO_HELP_ASSIGN_BYREF
741 // ldr tempReg, [R13, #8]
742 // str tempReg, [R14, #8]
743 // bl CORINFO_HELP_ASSIGN_BYREF
744 // ldr tempReg, [R13, #8]
745 // str tempReg, [R14, #8]
746 void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
747 {
748     GenTree*  dstAddr       = cpObjNode->Addr();
749     GenTree*  source        = cpObjNode->Data();
750     var_types srcAddrType   = TYP_BYREF;
751     bool      sourceIsLocal = false;
752     regNumber dstReg        = REG_NA;
753     regNumber srcReg        = REG_NA;
754
755     assert(source->isContained());
756     if (source->gtOper == GT_IND)
757     {
758         GenTree* srcAddr = source->gtGetOp1();
759         assert(!srcAddr->isContained());
760         srcAddrType = srcAddr->TypeGet();
761     }
762     else
763     {
764         noway_assert(source->IsLocal());
765         sourceIsLocal = true;
766     }
767
768     bool dstOnStack = dstAddr->OperIsLocalAddr();
769
770 #ifdef DEBUG
771     assert(!dstAddr->isContained());
772
773     // This GenTree node has data about GC pointers, this means we're dealing
774     // with CpObj.
775     assert(cpObjNode->gtGcPtrCount > 0);
776 #endif // DEBUG
777
778     // Consume the operands and get them into the right registers.
779     // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing").
780     genConsumeBlockOp(cpObjNode, REG_WRITE_BARRIER_DST_BYREF, REG_WRITE_BARRIER_SRC_BYREF, REG_NA);
781     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
782     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());
783
784     // Temp register used to perform the sequence of loads and stores.
785     regNumber tmpReg = cpObjNode->ExtractTempReg();
786     assert(genIsValidIntReg(tmpReg));
787
788     if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
789     {
790         // issue a full memory barrier before & after a volatile CpObj operation
791         instGen_MemoryBarrier();
792     }
793
794     unsigned slots = cpObjNode->gtSlots;
795     emitter* emit  = getEmitter();
796
797     BYTE* gcPtrs = cpObjNode->gtGcPtrs;
798
799     // If we can prove it's on the stack we don't need to use the write barrier.
800     emitAttr attr = EA_PTRSIZE;
801     if (dstOnStack)
802     {
803         for (unsigned i = 0; i < slots; ++i)
804         {
805             if (gcPtrs[i] == GCT_GCREF)
806             {
807                 attr = EA_GCREF;
808             }
809             else if (gcPtrs[i] == GCT_BYREF)
810             {
811                 attr = EA_BYREF;
812             }
813             else
814             {
815                 attr = EA_PTRSIZE;
816             }
817
818             emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
819                                 INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
820             emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
821                                 INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
822         }
823     }
824     else
825     {
826         unsigned gcPtrCount = cpObjNode->gtGcPtrCount;
827
828         unsigned i = 0;
829         while (i < slots)
830         {
831             switch (gcPtrs[i])
832             {
833                 case TYPE_GC_NONE:
834                     emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
835                                         INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
836                     emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
837                                         INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
838                     break;
839
840                 default:
841                     // In the case of a GC-Pointer we'll call the ByRef write barrier helper
842                     genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
843
844                     gcPtrCount--;
845                     break;
846             }
847             ++i;
848         }
849         assert(gcPtrCount == 0);
850     }
851
852     if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
853     {
854         // issue a full memory barrier before & after a volatile CpObj operation
855         instGen_MemoryBarrier();
856     }
857
858     // Clear the gcInfo for registers of source and dest.
859     // While we normally update GC info prior to the last instruction that uses them,
860     // these actually live into the helper call.
861     gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF);
862 }
863
864 //------------------------------------------------------------------------
865 // genCodeForShiftLong: Generates the code sequence for a GenTree node that
866 // represents a three operand bit shift or rotate operation (<<Hi, >>Lo).
867 //
868 // Arguments:
869 //    tree - the bit shift node (that specifies the type of bit shift to perform).
870 //
871 // Assumptions:
872 //    a) All GenTrees are register allocated.
873 //    b) The shift-by-amount in tree->gtOp.gtOp2 is a contained constant
874 //
875 void CodeGen::genCodeForShiftLong(GenTree* tree)
876 {
877     // Only the non-RMW case here.
878     genTreeOps oper = tree->OperGet();
879     assert(oper == GT_LSH_HI || oper == GT_RSH_LO);
880
881     GenTree* operand = tree->gtOp.gtOp1;
882     assert(operand->OperGet() == GT_LONG);
883     assert(operand->gtOp.gtOp1->isUsedFromReg());
884     assert(operand->gtOp.gtOp2->isUsedFromReg());
885
886     GenTree* operandLo = operand->gtGetOp1();
887     GenTree* operandHi = operand->gtGetOp2();
888
889     regNumber regLo = operandLo->gtRegNum;
890     regNumber regHi = operandHi->gtRegNum;
891
892     genConsumeOperands(tree->AsOp());
893
894     var_types   targetType = tree->TypeGet();
895     instruction ins        = genGetInsForOper(oper, targetType);
896
897     GenTree* shiftBy = tree->gtGetOp2();
898
899     assert(shiftBy->isContainedIntOrIImmed());
900
901     unsigned int count = shiftBy->AsIntConCommon()->IconValue();
902
903     regNumber regResult = (oper == GT_LSH_HI) ? regHi : regLo;
904
905     if (regResult != tree->gtRegNum)
906     {
907         inst_RV_RV(INS_mov, tree->gtRegNum, regResult, targetType);
908     }
909
910     if (oper == GT_LSH_HI)
911     {
912         inst_RV_SH(ins, EA_4BYTE, tree->gtRegNum, count);
913         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regLo, 32 - count,
914                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
915     }
916     else
917     {
918         assert(oper == GT_RSH_LO);
919         inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, tree->gtRegNum, count);
920         getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regHi, 32 - count,
921                                       INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
922     }
923
924     genProduceReg(tree);
925 }
926
927 //------------------------------------------------------------------------
928 // genCodeForLclVar: Produce code for a GT_LCL_VAR node.
929 //
930 // Arguments:
931 //    tree - the GT_LCL_VAR node
932 //
933 void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
934 {
935     // lcl_vars are not defs
936     assert((tree->gtFlags & GTF_VAR_DEF) == 0);
937
938     bool isRegCandidate = compiler->lvaTable[tree->gtLclNum].lvIsRegCandidate();
939
940     // If this is a register candidate that has been spilled, genConsumeReg() will
941     // reload it at the point of use.  Otherwise, if it's not in a register, we load it here.
942
943     if (!isRegCandidate && !(tree->gtFlags & GTF_SPILLED))
944     {
945         getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), emitTypeSize(tree), tree->gtRegNum, tree->gtLclNum, 0);
946         genProduceReg(tree);
947     }
948 }
949
950 //------------------------------------------------------------------------
951 // genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
952 //
953 // Arguments:
954 //    tree - the GT_STORE_LCL_FLD node
955 //
956 void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
957 {
958     var_types targetType = tree->TypeGet();
959     regNumber targetReg  = tree->gtRegNum;
960     emitter*  emit       = getEmitter();
961
962     noway_assert(targetType != TYP_STRUCT);
963
964     // record the offset
965     unsigned offset = tree->gtLclOffs;
966
967     // We must have a stack store with GT_STORE_LCL_FLD
968     noway_assert(targetReg == REG_NA);
969
970     unsigned varNum = tree->gtLclNum;
971     assert(varNum < compiler->lvaCount);
972     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
973
974     // Ensure that lclVar nodes are typed correctly.
975     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
976
977     GenTree*    data = tree->gtOp1;
978     instruction ins  = ins_Store(targetType);
979     emitAttr    attr = emitTypeSize(targetType);
980
981     assert(!data->isContained());
982     genConsumeReg(data);
983     emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
984
985     genUpdateLife(tree);
986     varDsc->lvRegNum = REG_STK;
987 }
988
989 //------------------------------------------------------------------------
990 // genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
991 //
992 // Arguments:
993 //    tree - the GT_STORE_LCL_VAR node
994 //
995 void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
996 {
997     var_types targetType = tree->TypeGet();
998     regNumber targetReg  = tree->gtRegNum;
999     emitter*  emit       = getEmitter();
1000
1001     unsigned varNum = tree->gtLclNum;
1002     assert(varNum < compiler->lvaCount);
1003     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1004
1005     // Ensure that lclVar nodes are typed correctly.
1006     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1007
1008     GenTree* data = tree->gtOp1;
1009
1010     // var = call, where call returns a multi-reg return value
1011     // case is handled separately.
1012     if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
1013     {
1014         genMultiRegCallStoreToLocal(tree);
1015     }
1016     else if (tree->TypeGet() == TYP_LONG)
1017     {
1018         genStoreLongLclVar(tree);
1019     }
1020     else
1021     {
1022         genConsumeRegs(data);
1023
1024         assert(!data->isContained());
1025         regNumber dataReg = data->gtRegNum;
1026         assert(dataReg != REG_NA);
1027
1028         if (targetReg == REG_NA) // store into stack based LclVar
1029         {
1030             inst_set_SV_var(tree);
1031
1032             instruction ins  = ins_Store(targetType);
1033             emitAttr    attr = emitTypeSize(targetType);
1034
1035             emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
1036
1037             genUpdateLife(tree);
1038
1039             varDsc->lvRegNum = REG_STK;
1040         }
1041         else // store into register (i.e move into register)
1042         {
1043             if (dataReg != targetReg)
1044             {
1045                 // Assign into targetReg when dataReg (from op1) is not the same register
1046                 inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
1047             }
1048             genProduceReg(tree);
1049         }
1050     }
1051 }
1052
1053 //------------------------------------------------------------------------
1054 // genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
1055 //
1056 // Arguments:
1057 //    tree - the node
1058 //
1059 void CodeGen::genCodeForDivMod(GenTreeOp* tree)
1060 {
1061     assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
1062
1063     // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
1064     // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
1065     // on float/double args.
1066     noway_assert(tree->OperIs(GT_DIV) || !varTypeIsFloating(tree));
1067
1068 #if defined(USE_HELPERS_FOR_INT_DIV)
1069     noway_assert(!varTypeIsIntOrI(tree));
1070 #endif // USE_HELPERS_FOR_INT_DIV
1071
1072     var_types targetType = tree->TypeGet();
1073     regNumber targetReg  = tree->gtRegNum;
1074     emitter*  emit       = getEmitter();
1075
1076     genConsumeOperands(tree);
1077
1078     noway_assert(targetReg != REG_NA);
1079
1080     GenTree*    dst    = tree;
1081     GenTree*    src1   = tree->gtGetOp1();
1082     GenTree*    src2   = tree->gtGetOp2();
1083     instruction ins    = genGetInsForOper(tree->OperGet(), targetType);
1084     emitAttr    attr   = emitTypeSize(tree);
1085     regNumber   result = REG_NA;
1086
1087     // dst can only be a reg
1088     assert(!dst->isContained());
1089
1090     // src can be only reg
1091     assert(!src1->isContained() || !src2->isContained());
1092
1093     if (varTypeIsFloating(targetType))
1094     {
1095         // Floating point divide never raises an exception
1096
1097         emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1098     }
1099     else // an signed integer divide operation
1100     {
1101         // TODO-ARM-Bug: handle zero division exception.
1102
1103         emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1104     }
1105
1106     genProduceReg(tree);
1107 }
1108
1109 //------------------------------------------------------------------------
1110 // genCkfinite: Generate code for ckfinite opcode.
1111 //
1112 // Arguments:
1113 //    treeNode - The GT_CKFINITE node
1114 //
1115 // Return Value:
1116 //    None.
1117 //
1118 // Assumptions:
1119 //    GT_CKFINITE node has reserved an internal register.
1120 //
1121 void CodeGen::genCkfinite(GenTree* treeNode)
1122 {
1123     assert(treeNode->OperGet() == GT_CKFINITE);
1124
1125     emitter*  emit       = getEmitter();
1126     var_types targetType = treeNode->TypeGet();
1127     regNumber intReg     = treeNode->GetSingleTempReg();
1128     regNumber fpReg      = genConsumeReg(treeNode->gtOp.gtOp1);
1129     regNumber targetReg  = treeNode->gtRegNum;
1130
1131     // Extract and sign-extend the exponent into an integer register
1132     if (targetType == TYP_FLOAT)
1133     {
1134         emit->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, intReg, fpReg);
1135         emit->emitIns_R_R_I_I(INS_sbfx, EA_4BYTE, intReg, intReg, 23, 8);
1136     }
1137     else
1138     {
1139         assert(targetType == TYP_DOUBLE);
1140         emit->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, intReg, REG_NEXT(fpReg));
1141         emit->emitIns_R_R_I_I(INS_sbfx, EA_4BYTE, intReg, intReg, 20, 11);
1142     }
1143
1144     // If exponent is all 1's, throw ArithmeticException
1145     emit->emitIns_R_I(INS_add, EA_4BYTE, intReg, 1, INS_FLAGS_SET);
1146     genJumpToThrowHlpBlk(EJ_eq, SCK_ARITH_EXCPN);
1147
1148     // If it's a finite value, copy it to targetReg
1149     if (targetReg != fpReg)
1150     {
1151         emit->emitIns_R_R(ins_Copy(targetType), emitTypeSize(treeNode), targetReg, fpReg);
1152     }
1153     genProduceReg(treeNode);
1154 }
1155
1156 //------------------------------------------------------------------------
1157 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT/GT_CMP node.
1158 //
1159 // Arguments:
1160 //    tree - the node
1161 //
1162 void CodeGen::genCodeForCompare(GenTreeOp* tree)
1163 {
1164     // TODO-ARM-CQ: Check if we can use the currently set flags.
1165     // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register
1166     //         (signed < or >= where targetReg != REG_NA)
1167
1168     GenTree*  op1     = tree->gtOp1;
1169     GenTree*  op2     = tree->gtOp2;
1170     var_types op1Type = op1->TypeGet();
1171     var_types op2Type = op2->TypeGet();
1172
1173     assert(!varTypeIsLong(op1Type));
1174     assert(!varTypeIsLong(op2Type));
1175
1176     regNumber targetReg = tree->gtRegNum;
1177     emitter*  emit      = getEmitter();
1178
1179     genConsumeIfReg(op1);
1180     genConsumeIfReg(op2);
1181
1182     if (varTypeIsFloating(op1Type))
1183     {
1184         assert(op1Type == op2Type);
1185         assert(!tree->OperIs(GT_CMP));
1186         emit->emitInsBinary(INS_vcmp, emitTypeSize(op1Type), op1, op2);
1187         // vmrs with register 0xf has special meaning of transferring flags
1188         emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15);
1189     }
1190     else
1191     {
1192         assert(!varTypeIsFloating(op2Type));
1193         var_types cmpType = (op1Type == op2Type) ? op1Type : TYP_INT;
1194         emit->emitInsBinary(INS_cmp, emitTypeSize(cmpType), op1, op2);
1195     }
1196
1197     // Are we evaluating this into a register?
1198     if (targetReg != REG_NA)
1199     {
1200         genSetRegToCond(targetReg, tree);
1201         genProduceReg(tree);
1202     }
1203 }
1204
1205 //------------------------------------------------------------------------
1206 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
1207 //
1208 // Arguments:
1209 //    tree - the GT_RETURNTRAP node
1210 //
1211 void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
1212 {
1213     assert(tree->OperGet() == GT_RETURNTRAP);
1214
1215     // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
1216     // based on the contents of 'data'
1217
1218     GenTree* data = tree->gtOp1;
1219     genConsumeIfReg(data);
1220     GenTreeIntCon cns = intForm(TYP_INT, 0);
1221     cns.SetContained();
1222     getEmitter()->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
1223
1224     BasicBlock* skipLabel = genCreateTempLabel();
1225
1226     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1227     inst_JMP(jmpEqual, skipLabel);
1228
1229     // emit the call to the EE-helper that stops for GC (or other reasons)
1230
1231     genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
1232     genDefineTempLabel(skipLabel);
1233 }
1234
1235 //------------------------------------------------------------------------
1236 // genCodeForStoreInd: Produce code for a GT_STOREIND node.
1237 //
1238 // Arguments:
1239 //    tree - the GT_STOREIND node
1240 //
1241 void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
1242 {
1243     GenTree*  data       = tree->Data();
1244     GenTree*  addr       = tree->Addr();
1245     var_types targetType = tree->TypeGet();
1246     emitter*  emit       = getEmitter();
1247
1248     assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
1249
1250     GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
1251     if (writeBarrierForm != GCInfo::WBF_NoBarrier)
1252     {
1253         // data and addr must be in registers.
1254         // Consume both registers so that any copies of interfering
1255         // registers are taken care of.
1256         genConsumeOperands(tree);
1257
1258         // At this point, we should not have any interference.
1259         // That is, 'data' must not be in REG_ARG_0,
1260         //  as that is where 'addr' must go.
1261         noway_assert(data->gtRegNum != REG_ARG_0);
1262
1263         // addr goes in REG_ARG_0
1264         if (addr->gtRegNum != REG_ARG_0)
1265         {
1266             inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
1267         }
1268
1269         // data goes in REG_ARG_1
1270         if (data->gtRegNum != REG_ARG_1)
1271         {
1272             inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
1273         }
1274
1275         genGCWriteBarrier(tree, writeBarrierForm);
1276     }
1277     else // A normal store, not a WriteBarrier store
1278     {
1279         bool dataIsUnary = false;
1280
1281         // We must consume the operands in the proper execution order,
1282         // so that liveness is updated appropriately.
1283         genConsumeAddress(addr);
1284
1285         if (!data->isContained())
1286         {
1287             genConsumeRegs(data);
1288         }
1289
1290         if (tree->gtFlags & GTF_IND_VOLATILE)
1291         {
1292             // issue a full memory barrier a before volatile StInd
1293             instGen_MemoryBarrier();
1294         }
1295
1296         emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(tree), data->gtRegNum, tree);
1297     }
1298 }
1299
1300 //------------------------------------------------------------------------
1301 // genSetRegToCond: Generate code to materialize a condition into a register.
1302 //
1303 // Arguments:
1304 //   dstReg - The target register to set to 1 or 0
1305 //   tree - The GenTree Relop node that was used to set the Condition codes
1306 //
1307 // Return Value: none
1308 //
1309 // Preconditions:
1310 //    The condition codes must already have been appropriately set.
1311 //
1312 void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
1313 {
1314     // Emit code like that:
1315     //   ...
1316     //   beq True
1317     //   bvs True    ; this second branch is typically absent
1318     //   movs rD, #0
1319     //   b Next
1320     // True:
1321     //   movs rD, #1
1322     // Next:
1323     //   ...
1324
1325     emitJumpKind jumpKind[2];
1326     bool         branchToTrueLabel[2];
1327     genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
1328
1329     BasicBlock* labelTrue = genCreateTempLabel();
1330     getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[0]), labelTrue);
1331
1332     if (jumpKind[1] != EJ_NONE)
1333     {
1334         getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[1]), labelTrue);
1335     }
1336
1337     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);
1338
1339     BasicBlock* labelNext = genCreateTempLabel();
1340     getEmitter()->emitIns_J(INS_b, labelNext);
1341
1342     genDefineTempLabel(labelTrue);
1343     getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
1344     genDefineTempLabel(labelNext);
1345 }
1346
1347 //------------------------------------------------------------------------
1348 // genLongToIntCast: Generate code for long to int casts.
1349 //
1350 // Arguments:
1351 //    cast - The GT_CAST node
1352 //
1353 // Return Value:
1354 //    None.
1355 //
1356 // Assumptions:
1357 //    The cast node and its sources (via GT_LONG) must have been assigned registers.
1358 //    The destination cannot be a floating point type or a small integer type.
1359 //
1360 void CodeGen::genLongToIntCast(GenTree* cast)
1361 {
1362     assert(cast->OperGet() == GT_CAST);
1363
1364     GenTree* src = cast->gtGetOp1();
1365     noway_assert(src->OperGet() == GT_LONG);
1366
1367     genConsumeRegs(src);
1368
1369     var_types srcType  = ((cast->gtFlags & GTF_UNSIGNED) != 0) ? TYP_ULONG : TYP_LONG;
1370     var_types dstType  = cast->CastToType();
1371     regNumber loSrcReg = src->gtGetOp1()->gtRegNum;
1372     regNumber hiSrcReg = src->gtGetOp2()->gtRegNum;
1373     regNumber dstReg   = cast->gtRegNum;
1374
1375     assert((dstType == TYP_INT) || (dstType == TYP_UINT));
1376     assert(genIsValidIntReg(loSrcReg));
1377     assert(genIsValidIntReg(hiSrcReg));
1378     assert(genIsValidIntReg(dstReg));
1379
1380     if (cast->gtOverflow())
1381     {
1382         //
1383         // Generate an overflow check for [u]long to [u]int casts:
1384         //
1385         // long  -> int  - check if the upper 33 bits are all 0 or all 1
1386         //
1387         // ulong -> int  - check if the upper 33 bits are all 0
1388         //
1389         // long  -> uint - check if the upper 32 bits are all 0
1390         // ulong -> uint - check if the upper 32 bits are all 0
1391         //
1392
1393         if ((srcType == TYP_LONG) && (dstType == TYP_INT))
1394         {
1395             BasicBlock* allOne  = genCreateTempLabel();
1396             BasicBlock* success = genCreateTempLabel();
1397
1398             inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1399             emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1400             inst_JMP(JmpNegative, allOne);
1401             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1402             emitJumpKind jmpNotEqualL = genJumpKindForOper(GT_NE, CK_LOGICAL);
1403             genJumpToThrowHlpBlk(jmpNotEqualL, SCK_OVERFLOW);
1404             inst_JMP(EJ_jmp, success);
1405
1406             genDefineTempLabel(allOne);
1407             inst_RV_IV(INS_cmp, hiSrcReg, -1, EA_4BYTE);
1408             emitJumpKind jmpNotEqualS = genJumpKindForOper(GT_NE, CK_SIGNED);
1409             genJumpToThrowHlpBlk(jmpNotEqualS, SCK_OVERFLOW);
1410
1411             genDefineTempLabel(success);
1412         }
1413         else
1414         {
1415             if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
1416             {
1417                 inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1418                 emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1419                 genJumpToThrowHlpBlk(JmpNegative, SCK_OVERFLOW);
1420             }
1421
1422             inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1423             emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_LOGICAL);
1424             genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
1425         }
1426     }
1427
1428     if (dstReg != loSrcReg)
1429     {
1430         inst_RV_RV(INS_mov, dstReg, loSrcReg, TYP_INT, EA_4BYTE);
1431     }
1432
1433     genProduceReg(cast);
1434 }
1435
1436 //------------------------------------------------------------------------
1437 // genIntToFloatCast: Generate code to cast an int to float/double
1438 //
1439 // Arguments:
1440 //    treeNode - The GT_CAST node
1441 //
1442 // Return Value:
1443 //    None.
1444 //
1445 // Assumptions:
1446 //    Cast is a non-overflow conversion.
1447 //    The treeNode must have an assigned register.
1448 //    SrcType= int32/uint32/int64/uint64 and DstType=float/double.
1449 //
1450 void CodeGen::genIntToFloatCast(GenTree* treeNode)
1451 {
1452     // int --> float/double conversions are always non-overflow ones
1453     assert(treeNode->OperGet() == GT_CAST);
1454     assert(!treeNode->gtOverflow());
1455
1456     regNumber targetReg = treeNode->gtRegNum;
1457     assert(genIsValidFloatReg(targetReg));
1458
1459     GenTree* op1 = treeNode->gtOp.gtOp1;
1460     assert(!op1->isContained());             // Cannot be contained
1461     assert(genIsValidIntReg(op1->gtRegNum)); // Must be a valid int reg.
1462
1463     var_types dstType = treeNode->CastToType();
1464     var_types srcType = genActualType(op1->TypeGet());
1465     assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
1466
1467     // force the srcType to unsigned if GT_UNSIGNED flag is set
1468     if (treeNode->gtFlags & GTF_UNSIGNED)
1469     {
1470         srcType = genUnsignedType(srcType);
1471     }
1472
1473     // We only expect a srcType whose size is EA_4BYTE.
1474     emitAttr srcSize = EA_ATTR(genTypeSize(srcType));
1475     noway_assert(srcSize == EA_4BYTE);
1476
1477     instruction insVcvt = INS_invalid;
1478
1479     if (dstType == TYP_DOUBLE)
1480     {
1481         insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2d : INS_vcvt_i2d;
1482     }
1483     else
1484     {
1485         assert(dstType == TYP_FLOAT);
1486         insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2f : INS_vcvt_i2f;
1487     }
1488     // All other cast are implemented by different CORINFO_HELP_XX2XX
1489     // Look to Compiler::fgMorphCast()
1490
1491     genConsumeOperands(treeNode->AsOp());
1492
1493     assert(insVcvt != INS_invalid);
1494     getEmitter()->emitIns_R_R(INS_vmov_i2f, srcSize, treeNode->gtRegNum, op1->gtRegNum);
1495     getEmitter()->emitIns_R_R(insVcvt, srcSize, treeNode->gtRegNum, treeNode->gtRegNum);
1496
1497     genProduceReg(treeNode);
1498 }
1499
1500 //------------------------------------------------------------------------
1501 // genFloatToIntCast: Generate code to cast float/double to int
1502 //
1503 // Arguments:
1504 //    treeNode - The GT_CAST node
1505 //
1506 // Return Value:
1507 //    None.
1508 //
1509 // Assumptions:
1510 //    Cast is a non-overflow conversion.
1511 //    The treeNode must have an assigned register.
1512 //    SrcType=float/double and DstType= int32/uint32/int64/uint64
1513 //
1514 void CodeGen::genFloatToIntCast(GenTree* treeNode)
1515 {
1516     // we don't expect to see overflow detecting float/double --> int type conversions here
1517     // as they should have been converted into helper calls by front-end.
1518     assert(treeNode->OperGet() == GT_CAST);
1519     assert(!treeNode->gtOverflow());
1520
1521     regNumber targetReg = treeNode->gtRegNum;
1522     assert(genIsValidIntReg(targetReg)); // Must be a valid int reg.
1523
1524     GenTree* op1 = treeNode->gtOp.gtOp1;
1525     assert(!op1->isContained());               // Cannot be contained
1526     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
1527
1528     var_types dstType = treeNode->CastToType();
1529     var_types srcType = op1->TypeGet();
1530     assert(varTypeIsFloating(srcType) && !varTypeIsFloating(dstType));
1531
1532     // We only expect a dstType whose size is EA_4BYTE.
1533     // For conversions to small types (byte/sbyte/int16/uint16) from float/double,
1534     // we expect the front-end or lowering phase to have generated two levels of cast.
1535     //
1536     emitAttr dstSize = EA_ATTR(genTypeSize(dstType));
1537     noway_assert(dstSize == EA_4BYTE);
1538
1539     instruction insVcvt = INS_invalid;
1540
1541     if (srcType == TYP_DOUBLE)
1542     {
1543         insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_d2u : INS_vcvt_d2i;
1544     }
1545     else
1546     {
1547         assert(srcType == TYP_FLOAT);
1548         insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_f2u : INS_vcvt_f2i;
1549     }
1550     // All other cast are implemented by different CORINFO_HELP_XX2XX
1551     // Look to Compiler::fgMorphCast()
1552
1553     genConsumeOperands(treeNode->AsOp());
1554
1555     regNumber tmpReg = treeNode->GetSingleTempReg();
1556
1557     assert(insVcvt != INS_invalid);
1558     getEmitter()->emitIns_R_R(insVcvt, dstSize, tmpReg, op1->gtRegNum);
1559     getEmitter()->emitIns_R_R(INS_vmov_f2i, dstSize, treeNode->gtRegNum, tmpReg);
1560
1561     genProduceReg(treeNode);
1562 }
1563
1564 //------------------------------------------------------------------------
1565 // genEmitHelperCall: Emit a call to a helper function.
1566 //
1567 void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
1568 {
1569     // Can we call the helper function directly
1570
1571     void *addr = NULL, **pAddr = NULL;
1572
1573 #if defined(DEBUG) && defined(PROFILING_SUPPORTED)
1574     // Don't ask VM if it hasn't requested ELT hooks
1575     if (!compiler->compProfilerHookNeeded && compiler->opts.compJitELTHookEnabled &&
1576         (helper == CORINFO_HELP_PROF_FCN_ENTER || helper == CORINFO_HELP_PROF_FCN_LEAVE ||
1577          helper == CORINFO_HELP_PROF_FCN_TAILCALL))
1578     {
1579         addr = compiler->compProfilerMethHnd;
1580     }
1581     else
1582 #endif
1583     {
1584         addr = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, (void**)&pAddr);
1585     }
1586
1587     if (!addr || !arm_Valid_Imm_For_BL((ssize_t)addr))
1588     {
1589         if (callTargetReg == REG_NA)
1590         {
1591             // If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
1592             // this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
1593             callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
1594         }
1595
1596         // Load the address into a register and call through a register
1597         if (addr)
1598         {
1599             instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, callTargetReg, (ssize_t)addr);
1600         }
1601         else
1602         {
1603             getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, callTargetReg, (ssize_t)pAddr);
1604             regTracker.rsTrackRegTrash(callTargetReg);
1605         }
1606
1607         getEmitter()->emitIns_Call(emitter::EC_INDIR_R, compiler->eeFindHelper(helper),
1608                                    INDEBUG_LDISASM_COMMA(nullptr) NULL, // addr
1609                                    argSize, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
1610                                    gcInfo.gcRegByrefSetCur,
1611                                    BAD_IL_OFFSET, // ilOffset
1612                                    callTargetReg, // ireg
1613                                    REG_NA, 0, 0,  // xreg, xmul, disp
1614                                    false,         // isJump
1615                                    emitter::emitNoGChelper(helper),
1616                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
1617     }
1618     else
1619     {
1620         getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, compiler->eeFindHelper(helper),
1621                                    INDEBUG_LDISASM_COMMA(nullptr) addr, argSize, retSize, gcInfo.gcVarPtrSetCur,
1622                                    gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
1623                                    0,     /* ilOffset, ireg, xreg, xmul, disp */
1624                                    false, /* isJump */
1625                                    emitter::emitNoGChelper(helper),
1626                                    (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
1627     }
1628
1629     regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
1630 }
1631
1632 //------------------------------------------------------------------------
1633 // genStoreLongLclVar: Generate code to store a non-enregistered long lclVar
1634 //
1635 // Arguments:
1636 //    treeNode - A TYP_LONG lclVar node.
1637 //
1638 // Return Value:
1639 //    None.
1640 //
1641 // Assumptions:
1642 //    'treeNode' must be a TYP_LONG lclVar node for a lclVar that has NOT been promoted.
1643 //    Its operand must be a GT_LONG node.
1644 //
1645 void CodeGen::genStoreLongLclVar(GenTree* treeNode)
1646 {
1647     emitter* emit = getEmitter();
1648
1649     GenTreeLclVarCommon* lclNode = treeNode->AsLclVarCommon();
1650     unsigned             lclNum  = lclNode->gtLclNum;
1651     LclVarDsc*           varDsc  = &(compiler->lvaTable[lclNum]);
1652     assert(varDsc->TypeGet() == TYP_LONG);
1653     assert(!varDsc->lvPromoted);
1654     GenTree* op1 = treeNode->gtOp.gtOp1;
1655     noway_assert(op1->OperGet() == GT_LONG || op1->OperGet() == GT_MUL_LONG);
1656     genConsumeRegs(op1);
1657
1658     if (op1->OperGet() == GT_LONG)
1659     {
1660         // Definitions of register candidates will have been lowered to 2 int lclVars.
1661         assert(!treeNode->gtHasReg());
1662
1663         GenTree* loVal = op1->gtGetOp1();
1664         GenTree* hiVal = op1->gtGetOp2();
1665
1666         noway_assert((loVal->gtRegNum != REG_NA) && (hiVal->gtRegNum != REG_NA));
1667
1668         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, loVal->gtRegNum, lclNum, 0);
1669         emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, hiVal->gtRegNum, lclNum, genTypeSize(TYP_INT));
1670     }
1671     else if (op1->OperGet() == GT_MUL_LONG)
1672     {
1673         assert((op1->gtFlags & GTF_MUL_64RSLT) != 0);
1674
1675         GenTreeMultiRegOp* mul = op1->AsMultiRegOp();
1676
1677         // Stack store
1678         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), mul->gtRegNum, lclNum, 0);
1679         getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), mul->gtOtherReg, lclNum,
1680                                   genTypeSize(TYP_INT));
1681     }
1682 }
1683
1684 //------------------------------------------------------------------------
1685 // genCodeForMulLong: Generates code for int*int->long multiplication
1686 //
1687 // Arguments:
1688 //    node - the GT_MUL_LONG node
1689 //
1690 // Return Value:
1691 //    None.
1692 //
1693 void CodeGen::genCodeForMulLong(GenTreeMultiRegOp* node)
1694 {
1695     assert(node->OperGet() == GT_MUL_LONG);
1696     genConsumeOperands(node);
1697     GenTree*    src1 = node->gtOp1;
1698     GenTree*    src2 = node->gtOp2;
1699     instruction ins  = node->IsUnsigned() ? INS_umull : INS_smull;
1700     getEmitter()->emitIns_R_R_R_R(ins, EA_4BYTE, node->gtRegNum, node->gtOtherReg, src1->gtRegNum, src2->gtRegNum);
1701     genProduceReg(node);
1702 }
1703
1704 #endif // _TARGET_ARM_
1705
1706 #endif // !LEGACY_BACKEND