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