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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8 XX ARM Code Generator XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
18 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
26 //------------------------------------------------------------------------
27 // genCallFinally: Generate a call to the finally block.
29 BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
31 BasicBlock* bbFinallyRet = nullptr;
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());
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);
42 bbFinallyRet = block->bbNext->bbJumpDest;
43 bbFinallyRet->bbFlags |= BBF_JMP_TARGET;
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);
49 // Jump to the finally BB
50 inst_JMP(EJ_jmp, block->bbJumpDest);
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
56 assert(!(block->bbFlags & BBF_RETLESS_CALL));
57 assert(block->isBBCallAlwaysPair());
61 //------------------------------------------------------------------------
63 void CodeGen::genEHCatchRet(BasicBlock* block)
65 genMov32RelocatableDisplacement(block->bbJumpDest, REG_INTRET);
68 //------------------------------------------------------------------------
69 // instGen_Set_Reg_To_Imm: Move an immediate value into an integer register.
71 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
73 // reg cannot be a FP register
74 assert(!genIsValidFloatReg(reg));
76 if (!compiler->opts.compReloc)
78 size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
81 if (EA_IS_RELOC(size))
83 genMov32RelocatableImmediate(size, imm, reg);
87 instGen_Set_Reg_To_Zero(size, reg, flags);
91 if (arm_Valid_Imm_For_Mov(imm))
93 getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
95 else // We have to use a movw/movt pair of instructions
97 ssize_t imm_lo16 = (imm & 0xffff);
98 ssize_t imm_hi16 = (imm >> 16) & 0xffff;
100 assert(arm_Valid_Imm_For_Mov(imm_lo16));
101 assert(imm_hi16 != 0);
103 getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
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.
110 if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
112 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
116 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
119 if (flags == INS_FLAGS_SET)
120 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
124 regTracker.rsTrackRegIntCns(reg, imm);
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'.
132 // This does not call genProduceReg() on the target register.
134 void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree)
136 switch (tree->gtOper)
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();
145 if (con->ImmedValNeedsReloc(compiler))
147 instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
148 regTracker.rsTrackRegTrash(targetReg);
152 genSetRegToIcon(targetReg, cnsVal, targetType);
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)
164 // Get a temp integer register
165 regNumber tmpReg = tree->GetSingleTempReg();
167 float f = forceCastToFloat(constValue);
168 genSetRegToIcon(tmpReg, *((int*)(&f)));
169 getEmitter()->emitIns_R_R(INS_vmov_i2f, EA_4BYTE, targetReg, tmpReg);
173 assert(targetType == TYP_DOUBLE);
175 unsigned* cv = (unsigned*)&constValue;
177 // Get two temp integer registers
178 regNumber tmpReg1 = tree->ExtractTempReg();
179 regNumber tmpReg2 = tree->GetSingleTempReg();
181 genSetRegToIcon(tmpReg1, cv[0]);
182 genSetRegToIcon(tmpReg2, cv[1]);
184 getEmitter()->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, tmpReg1, tmpReg2);
194 //------------------------------------------------------------------------
195 // genCodeForBinary: Generate code for many binary arithmetic operators
196 // This method is expected to have called genConsumeOperands() before calling it.
199 // treeNode - The binary operation for which we are generating code.
205 // Mul and div are not handled here.
206 // See the assert below for the operators that are handled.
208 void CodeGen::genCodeForBinary(GenTree* treeNode)
210 const genTreeOps oper = treeNode->OperGet();
211 regNumber targetReg = treeNode->gtRegNum;
212 var_types targetType = treeNode->TypeGet();
213 emitter* emit = getEmitter();
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);
218 GenTree* op1 = treeNode->gtGetOp1();
219 GenTree* op2 = treeNode->gtGetOp2();
221 instruction ins = genGetInsForOper(oper, targetType);
223 // The arithmetic node must be sitting in a register (since it's not contained)
224 noway_assert(targetReg != REG_NA);
226 if ((oper == GT_ADD_LO || oper == GT_SUB_LO))
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,
235 regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2);
236 assert(r == targetReg);
239 genProduceReg(treeNode);
242 //--------------------------------------------------------------------------------------
243 // genLclHeap: Generate code for localloc
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().
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.
260 // Notes: Size N should be aligned to STACK_ALIGN before any allocation
262 void CodeGen::genLclHeap(GenTree* tree)
264 assert(tree->OperGet() == GT_LCLHEAP);
266 GenTree* size = tree->gtOp.gtOp1;
267 noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
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;
282 if (compiler->opts.compStackCheckOnRet)
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);
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);
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
300 // Whether method has PSPSym.
302 #if FEATURE_EH_FUNCLETS
303 hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
308 // Check to 0 size allocations
309 // size_t amount = 0;
310 if (size->IsCnsIntOrI())
312 // If size is a constant, then it must be contained.
313 assert(size->isContained());
315 // If amount is zero then return null in regCnt
316 size_t amount = size->gtIntCon.gtIconVal;
319 instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
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);
334 #if FEATURE_EH_FUNCLETS
335 // If we have PSPsym, then need to re-locate it after localloc.
338 stackAdjustment += STACK_ALIGN;
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);
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)
351 assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain
353 inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
354 stackAdjustment += compiler->lvaOutgoingArgSpaceSize;
358 // Put aligned allocation size to regCnt
359 if (size->IsCnsIntOrI())
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);
365 // For small allocations we will generate up to four stp instructions
366 size_t cntStackAlignedWidthItems = (amount >> STACK_ALIGN_SHIFT);
367 if (cntStackAlignedWidthItems <= 4)
369 instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
371 while (cntStackAlignedWidthItems != 0)
373 inst_IV(INS_push, (unsigned)genRegMask(regCnt));
374 cntStackAlignedWidthItems -= 1;
379 else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
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);
389 // regCnt will be the total number of bytes to locAlloc
390 genSetRegToIcon(regCnt, amount, ((int)amount == amount) ? TYP_INT : TYP_LONG);
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));
400 if (compiler->info.compInitMem)
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.
406 regNumber regTmp = tree->ExtractTempReg();
407 instGen_Set_Reg_To_Zero(EA_PTRSIZE, regTmp);
410 BasicBlock* loop = genCreateTempLabel();
411 genDefineTempLabel(loop);
413 noway_assert(STACK_ALIGN == 8);
414 inst_IV(INS_push, (unsigned)genRegMask(regTmp));
415 inst_IV(INS_push, (unsigned)genRegMask(regTmp));
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);
426 // At this point 'regCnt' is set to the total number of bytes to locAlloc.
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.
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
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
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
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
458 regNumber regTmp = tree->ExtractTempReg();
460 BasicBlock* loop = genCreateTempLabel();
461 BasicBlock* done = genCreateTempLabel();
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);
466 inst_JMP(EJ_vc, loop); // branch if the V flag is not set
468 // Overflow, set regCnt to lowest possible value
469 instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
471 genDefineTempLabel(loop);
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);
476 // decrement SP by eeGetPageSize()
477 getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());
479 getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
480 emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
481 inst_JMP(jmpLTU, done);
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);
486 // Jump to loop and tickle new stack address
487 inst_JMP(EJ_jmp, loop);
489 // Done with stack tickle loop
490 genDefineTempLabel(done);
492 // Now just move the final value to SP
493 getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
497 // Re-adjust SP to allocate PSPSym and out-going arg area
498 if (stackAdjustment != 0)
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);
504 #if FEATURE_EH_FUNCLETS
505 // Write PSPSym to its new location.
508 assert(genIsValidIntReg(pspSymReg));
509 getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
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);
516 else // stackAdjustment == 0
518 // Move the final value of SP to regCnt
519 inst_RV_RV(INS_mov, regCnt, REG_SPBASE);
523 if (endLabel != nullptr)
524 genDefineTempLabel(endLabel);
526 // Write the lvaLocAllocSPvar stack frame slot
527 if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
529 getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regCnt, compiler->lvaLocAllocSPvar, 0);
533 if (compiler->opts.compNeedStackProbes)
535 genGenerateStackProbe();
541 if (compiler->opts.compStackCheckOnRet)
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);
553 //------------------------------------------------------------------------
554 // genTableBasedSwitch: generate code for a switch statement based on a table of ip-relative offsets
556 void CodeGen::genTableBasedSwitch(GenTree* treeNode)
558 genConsumeOperands(treeNode->AsOp());
559 regNumber idxReg = treeNode->gtOp.gtOp1->gtRegNum;
560 regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
562 getEmitter()->emitIns_R_ARX(INS_ldr, EA_4BYTE, REG_PC, baseReg, idxReg, TARGET_POINTER_SIZE, 0);
565 //------------------------------------------------------------------------
566 // genJumpTable: emits the table and an instruction to get the address of the first element
568 void CodeGen::genJumpTable(GenTree* treeNode)
570 noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
571 assert(treeNode->OperGet() == GT_JMPTABLE);
573 unsigned jumpCount = compiler->compCurBB->bbJumpSwt->bbsCount;
574 BasicBlock** jumpTable = compiler->compCurBB->bbJumpSwt->bbsDstTab;
577 jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCount, false);
579 JITDUMP("\n J_M%03u_DS%02u LABEL DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
581 for (unsigned i = 0; i < jumpCount; i++)
583 BasicBlock* target = *jumpTable++;
584 noway_assert(target->bbFlags & BBF_JMP_TARGET);
586 JITDUMP(" DD L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
588 getEmitter()->emitDataGenData(i, target);
591 getEmitter()->emitDataGenEnd();
593 genMov32RelocatableDataLabel(jmpTabBase, treeNode->gtRegNum);
595 genProduceReg(treeNode);
598 //------------------------------------------------------------------------
599 // genGetInsForOper: Return instruction encoding of the operation tree.
601 instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
605 if (varTypeIsFloating(type))
606 return CodeGen::ins_MathOp(oper, type);
619 #if !defined(USE_HELPERS_FOR_INT_DIV)
623 #endif // !USE_HELPERS_FOR_INT_DIV
625 ins = INS_SHIFT_LEFT_LOGICAL;
637 ins = INS_SHIFT_RIGHT_ARITHM;
640 ins = INS_SHIFT_RIGHT_LOGICAL;
664 ins = INS_SHIFT_LEFT_LOGICAL;
667 ins = INS_SHIFT_RIGHT_LOGICAL;
676 // Generate code for InitBlk by performing a loop unroll
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)
682 // TODO: Generate memory barrier instructions for GTF_BLK_VOLATILE flag
683 NYI_ARM("genCodeForInitBlkUnroll");
686 //------------------------------------------------------------------------
687 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
692 void CodeGen::genCodeForNegNot(GenTree* tree)
694 assert(tree->OperIs(GT_NEG, GT_NOT));
696 var_types targetType = tree->TypeGet();
698 assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
700 regNumber targetReg = tree->gtRegNum;
701 instruction ins = genGetInsForOper(tree->OperGet(), targetType);
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);
708 GenTree* operand = tree->gtGetOp1();
709 assert(!operand->isContained());
710 // The src must be a register.
711 regNumber operandReg = genConsumeReg(operand);
715 getEmitter()->emitIns_R_R(ins, emitTypeSize(tree), targetReg, operandReg);
719 getEmitter()->emitIns_R_R_I(ins, emitTypeSize(tree), targetReg, operandReg, 0, INS_FLAGS_SET);
725 // Generate code for CpObj nodes wich copy structs that have interleaved
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]
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
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)
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;
755 assert(source->isContained());
756 if (source->gtOper == GT_IND)
758 GenTree* srcAddr = source->gtGetOp1();
759 assert(!srcAddr->isContained());
760 srcAddrType = srcAddr->TypeGet();
764 noway_assert(source->IsLocal());
765 sourceIsLocal = true;
768 bool dstOnStack = dstAddr->OperIsLocalAddr();
771 assert(!dstAddr->isContained());
773 // This GenTree node has data about GC pointers, this means we're dealing
775 assert(cpObjNode->gtGcPtrCount > 0);
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());
784 // Temp register used to perform the sequence of loads and stores.
785 regNumber tmpReg = cpObjNode->ExtractTempReg();
786 assert(genIsValidIntReg(tmpReg));
788 if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
790 // issue a full memory barrier before & after a volatile CpObj operation
791 instGen_MemoryBarrier();
794 unsigned slots = cpObjNode->gtSlots;
795 emitter* emit = getEmitter();
797 BYTE* gcPtrs = cpObjNode->gtGcPtrs;
799 // If we can prove it's on the stack we don't need to use the write barrier.
800 emitAttr attr = EA_PTRSIZE;
803 for (unsigned i = 0; i < slots; ++i)
805 if (gcPtrs[i] == GCT_GCREF)
809 else if (gcPtrs[i] == GCT_BYREF)
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);
826 unsigned gcPtrCount = cpObjNode->gtGcPtrCount;
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);
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);
849 assert(gcPtrCount == 0);
852 if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
854 // issue a full memory barrier before & after a volatile CpObj operation
855 instGen_MemoryBarrier();
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);
864 //------------------------------------------------------------------------
865 // genCodeForShiftLong: Generates the code sequence for a GenTree node that
866 // represents a three operand bit shift or rotate operation (<<Hi, >>Lo).
869 // tree - the bit shift node (that specifies the type of bit shift to perform).
872 // a) All GenTrees are register allocated.
873 // b) The shift-by-amount in tree->gtOp.gtOp2 is a contained constant
875 void CodeGen::genCodeForShiftLong(GenTree* tree)
877 // Only the non-RMW case here.
878 genTreeOps oper = tree->OperGet();
879 assert(oper == GT_LSH_HI || oper == GT_RSH_LO);
881 GenTree* operand = tree->gtOp.gtOp1;
882 assert(operand->OperGet() == GT_LONG);
883 assert(operand->gtOp.gtOp1->isUsedFromReg());
884 assert(operand->gtOp.gtOp2->isUsedFromReg());
886 GenTree* operandLo = operand->gtGetOp1();
887 GenTree* operandHi = operand->gtGetOp2();
889 regNumber regLo = operandLo->gtRegNum;
890 regNumber regHi = operandHi->gtRegNum;
892 genConsumeOperands(tree->AsOp());
894 var_types targetType = tree->TypeGet();
895 instruction ins = genGetInsForOper(oper, targetType);
897 GenTree* shiftBy = tree->gtGetOp2();
899 assert(shiftBy->isContainedIntOrIImmed());
901 unsigned int count = shiftBy->AsIntConCommon()->IconValue();
903 regNumber regResult = (oper == GT_LSH_HI) ? regHi : regLo;
905 if (regResult != tree->gtRegNum)
907 inst_RV_RV(INS_mov, tree->gtRegNum, regResult, targetType);
910 if (oper == GT_LSH_HI)
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);
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);
927 //------------------------------------------------------------------------
928 // genCodeForLclVar: Produce code for a GT_LCL_VAR node.
931 // tree - the GT_LCL_VAR node
933 void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
935 // lcl_vars are not defs
936 assert((tree->gtFlags & GTF_VAR_DEF) == 0);
938 bool isRegCandidate = compiler->lvaTable[tree->gtLclNum].lvIsRegCandidate();
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.
943 if (!isRegCandidate && !(tree->gtFlags & GTF_SPILLED))
945 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), emitTypeSize(tree), tree->gtRegNum, tree->gtLclNum, 0);
950 //------------------------------------------------------------------------
951 // genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
954 // tree - the GT_STORE_LCL_FLD node
956 void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
958 var_types targetType = tree->TypeGet();
959 regNumber targetReg = tree->gtRegNum;
960 emitter* emit = getEmitter();
962 noway_assert(targetType != TYP_STRUCT);
965 unsigned offset = tree->gtLclOffs;
967 // We must have a stack store with GT_STORE_LCL_FLD
968 noway_assert(targetReg == REG_NA);
970 unsigned varNum = tree->gtLclNum;
971 assert(varNum < compiler->lvaCount);
972 LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
974 // Ensure that lclVar nodes are typed correctly.
975 assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
977 GenTree* data = tree->gtOp1;
978 instruction ins = ins_Store(targetType);
979 emitAttr attr = emitTypeSize(targetType);
981 assert(!data->isContained());
983 emit->emitIns_S_R(ins, attr, data->gtRegNum, varNum, offset);
986 varDsc->lvRegNum = REG_STK;
989 //------------------------------------------------------------------------
990 // genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
993 // tree - the GT_STORE_LCL_VAR node
995 void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
997 var_types targetType = tree->TypeGet();
998 regNumber targetReg = tree->gtRegNum;
999 emitter* emit = getEmitter();
1001 unsigned varNum = tree->gtLclNum;
1002 assert(varNum < compiler->lvaCount);
1003 LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1005 // Ensure that lclVar nodes are typed correctly.
1006 assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1008 GenTree* data = tree->gtOp1;
1010 // var = call, where call returns a multi-reg return value
1011 // case is handled separately.
1012 if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
1014 genMultiRegCallStoreToLocal(tree);
1016 else if (tree->TypeGet() == TYP_LONG)
1018 genStoreLongLclVar(tree);
1022 genConsumeRegs(data);
1024 assert(!data->isContained());
1025 regNumber dataReg = data->gtRegNum;
1026 assert(dataReg != REG_NA);
1028 if (targetReg == REG_NA) // store into stack based LclVar
1030 inst_set_SV_var(tree);
1032 instruction ins = ins_Store(targetType);
1033 emitAttr attr = emitTypeSize(targetType);
1035 emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
1037 genUpdateLife(tree);
1039 varDsc->lvRegNum = REG_STK;
1041 else // store into register (i.e move into register)
1043 if (dataReg != targetReg)
1045 // Assign into targetReg when dataReg (from op1) is not the same register
1046 inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
1048 genProduceReg(tree);
1053 //------------------------------------------------------------------------
1054 // genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
1059 void CodeGen::genCodeForDivMod(GenTreeOp* tree)
1061 assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
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));
1068 #if defined(USE_HELPERS_FOR_INT_DIV)
1069 noway_assert(!varTypeIsIntOrI(tree));
1070 #endif // USE_HELPERS_FOR_INT_DIV
1072 var_types targetType = tree->TypeGet();
1073 regNumber targetReg = tree->gtRegNum;
1074 emitter* emit = getEmitter();
1076 genConsumeOperands(tree);
1078 noway_assert(targetReg != REG_NA);
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;
1087 // dst can only be a reg
1088 assert(!dst->isContained());
1090 // src can be only reg
1091 assert(!src1->isContained() || !src2->isContained());
1093 if (varTypeIsFloating(targetType))
1095 // Floating point divide never raises an exception
1097 emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1099 else // an signed integer divide operation
1101 // TODO-ARM-Bug: handle zero division exception.
1103 emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
1106 genProduceReg(tree);
1109 //------------------------------------------------------------------------
1110 // genCkfinite: Generate code for ckfinite opcode.
1113 // treeNode - The GT_CKFINITE node
1119 // GT_CKFINITE node has reserved an internal register.
1121 void CodeGen::genCkfinite(GenTree* treeNode)
1123 assert(treeNode->OperGet() == GT_CKFINITE);
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;
1131 // Extract and sign-extend the exponent into an integer register
1132 if (targetType == TYP_FLOAT)
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);
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);
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);
1148 // If it's a finite value, copy it to targetReg
1149 if (targetReg != fpReg)
1151 emit->emitIns_R_R(ins_Copy(targetType), emitTypeSize(treeNode), targetReg, fpReg);
1153 genProduceReg(treeNode);
1156 //------------------------------------------------------------------------
1157 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT/GT_CMP node.
1162 void CodeGen::genCodeForCompare(GenTreeOp* tree)
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)
1168 GenTree* op1 = tree->gtOp1;
1169 GenTree* op2 = tree->gtOp2;
1170 var_types op1Type = op1->TypeGet();
1171 var_types op2Type = op2->TypeGet();
1173 assert(!varTypeIsLong(op1Type));
1174 assert(!varTypeIsLong(op2Type));
1176 regNumber targetReg = tree->gtRegNum;
1177 emitter* emit = getEmitter();
1179 genConsumeIfReg(op1);
1180 genConsumeIfReg(op2);
1182 if (varTypeIsFloating(op1Type))
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);
1192 assert(!varTypeIsFloating(op2Type));
1193 var_types cmpType = (op1Type == op2Type) ? op1Type : TYP_INT;
1194 emit->emitInsBinary(INS_cmp, emitTypeSize(cmpType), op1, op2);
1197 // Are we evaluating this into a register?
1198 if (targetReg != REG_NA)
1200 genSetRegToCond(targetReg, tree);
1201 genProduceReg(tree);
1205 //------------------------------------------------------------------------
1206 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
1209 // tree - the GT_RETURNTRAP node
1211 void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
1213 assert(tree->OperGet() == GT_RETURNTRAP);
1215 // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
1216 // based on the contents of 'data'
1218 GenTree* data = tree->gtOp1;
1219 genConsumeIfReg(data);
1220 GenTreeIntCon cns = intForm(TYP_INT, 0);
1222 getEmitter()->emitInsBinary(INS_cmp, emitTypeSize(TYP_INT), data, &cns);
1224 BasicBlock* skipLabel = genCreateTempLabel();
1226 emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1227 inst_JMP(jmpEqual, skipLabel);
1229 // emit the call to the EE-helper that stops for GC (or other reasons)
1231 genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
1232 genDefineTempLabel(skipLabel);
1235 //------------------------------------------------------------------------
1236 // genCodeForStoreInd: Produce code for a GT_STOREIND node.
1239 // tree - the GT_STOREIND node
1241 void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
1243 GenTree* data = tree->Data();
1244 GenTree* addr = tree->Addr();
1245 var_types targetType = tree->TypeGet();
1246 emitter* emit = getEmitter();
1248 assert(!varTypeIsFloating(targetType) || (targetType == data->TypeGet()));
1250 GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
1251 if (writeBarrierForm != GCInfo::WBF_NoBarrier)
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);
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);
1263 // addr goes in REG_ARG_0
1264 if (addr->gtRegNum != REG_ARG_0)
1266 inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
1269 // data goes in REG_ARG_1
1270 if (data->gtRegNum != REG_ARG_1)
1272 inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
1275 genGCWriteBarrier(tree, writeBarrierForm);
1277 else // A normal store, not a WriteBarrier store
1279 bool dataIsUnary = false;
1281 // We must consume the operands in the proper execution order,
1282 // so that liveness is updated appropriately.
1283 genConsumeAddress(addr);
1285 if (!data->isContained())
1287 genConsumeRegs(data);
1290 if (tree->gtFlags & GTF_IND_VOLATILE)
1292 // issue a full memory barrier a before volatile StInd
1293 instGen_MemoryBarrier();
1296 emit->emitInsLoadStoreOp(ins_Store(targetType), emitTypeSize(tree), data->gtRegNum, tree);
1300 //------------------------------------------------------------------------
1301 // genSetRegToCond: Generate code to materialize a condition into a register.
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
1307 // Return Value: none
1310 // The condition codes must already have been appropriately set.
1312 void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
1314 // Emit code like that:
1317 // bvs True ; this second branch is typically absent
1325 emitJumpKind jumpKind[2];
1326 bool branchToTrueLabel[2];
1327 genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
1329 BasicBlock* labelTrue = genCreateTempLabel();
1330 getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[0]), labelTrue);
1332 if (jumpKind[1] != EJ_NONE)
1334 getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[1]), labelTrue);
1337 getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);
1339 BasicBlock* labelNext = genCreateTempLabel();
1340 getEmitter()->emitIns_J(INS_b, labelNext);
1342 genDefineTempLabel(labelTrue);
1343 getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
1344 genDefineTempLabel(labelNext);
1347 //------------------------------------------------------------------------
1348 // genLongToIntCast: Generate code for long to int casts.
1351 // cast - The GT_CAST node
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.
1360 void CodeGen::genLongToIntCast(GenTree* cast)
1362 assert(cast->OperGet() == GT_CAST);
1364 GenTree* src = cast->gtGetOp1();
1365 noway_assert(src->OperGet() == GT_LONG);
1367 genConsumeRegs(src);
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;
1375 assert((dstType == TYP_INT) || (dstType == TYP_UINT));
1376 assert(genIsValidIntReg(loSrcReg));
1377 assert(genIsValidIntReg(hiSrcReg));
1378 assert(genIsValidIntReg(dstReg));
1380 if (cast->gtOverflow())
1383 // Generate an overflow check for [u]long to [u]int casts:
1385 // long -> int - check if the upper 33 bits are all 0 or all 1
1387 // ulong -> int - check if the upper 33 bits are all 0
1389 // long -> uint - check if the upper 32 bits are all 0
1390 // ulong -> uint - check if the upper 32 bits are all 0
1393 if ((srcType == TYP_LONG) && (dstType == TYP_INT))
1395 BasicBlock* allOne = genCreateTempLabel();
1396 BasicBlock* success = genCreateTempLabel();
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);
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);
1411 genDefineTempLabel(success);
1415 if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
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);
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);
1428 if (dstReg != loSrcReg)
1430 inst_RV_RV(INS_mov, dstReg, loSrcReg, TYP_INT, EA_4BYTE);
1433 genProduceReg(cast);
1436 //------------------------------------------------------------------------
1437 // genIntToFloatCast: Generate code to cast an int to float/double
1440 // treeNode - The GT_CAST node
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.
1450 void CodeGen::genIntToFloatCast(GenTree* treeNode)
1452 // int --> float/double conversions are always non-overflow ones
1453 assert(treeNode->OperGet() == GT_CAST);
1454 assert(!treeNode->gtOverflow());
1456 regNumber targetReg = treeNode->gtRegNum;
1457 assert(genIsValidFloatReg(targetReg));
1459 GenTree* op1 = treeNode->gtOp.gtOp1;
1460 assert(!op1->isContained()); // Cannot be contained
1461 assert(genIsValidIntReg(op1->gtRegNum)); // Must be a valid int reg.
1463 var_types dstType = treeNode->CastToType();
1464 var_types srcType = genActualType(op1->TypeGet());
1465 assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
1467 // force the srcType to unsigned if GT_UNSIGNED flag is set
1468 if (treeNode->gtFlags & GTF_UNSIGNED)
1470 srcType = genUnsignedType(srcType);
1473 // We only expect a srcType whose size is EA_4BYTE.
1474 emitAttr srcSize = EA_ATTR(genTypeSize(srcType));
1475 noway_assert(srcSize == EA_4BYTE);
1477 instruction insVcvt = INS_invalid;
1479 if (dstType == TYP_DOUBLE)
1481 insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2d : INS_vcvt_i2d;
1485 assert(dstType == TYP_FLOAT);
1486 insVcvt = (varTypeIsUnsigned(srcType)) ? INS_vcvt_u2f : INS_vcvt_i2f;
1488 // All other cast are implemented by different CORINFO_HELP_XX2XX
1489 // Look to Compiler::fgMorphCast()
1491 genConsumeOperands(treeNode->AsOp());
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);
1497 genProduceReg(treeNode);
1500 //------------------------------------------------------------------------
1501 // genFloatToIntCast: Generate code to cast float/double to int
1504 // treeNode - The GT_CAST node
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
1514 void CodeGen::genFloatToIntCast(GenTree* treeNode)
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());
1521 regNumber targetReg = treeNode->gtRegNum;
1522 assert(genIsValidIntReg(targetReg)); // Must be a valid int reg.
1524 GenTree* op1 = treeNode->gtOp.gtOp1;
1525 assert(!op1->isContained()); // Cannot be contained
1526 assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
1528 var_types dstType = treeNode->CastToType();
1529 var_types srcType = op1->TypeGet();
1530 assert(varTypeIsFloating(srcType) && !varTypeIsFloating(dstType));
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.
1536 emitAttr dstSize = EA_ATTR(genTypeSize(dstType));
1537 noway_assert(dstSize == EA_4BYTE);
1539 instruction insVcvt = INS_invalid;
1541 if (srcType == TYP_DOUBLE)
1543 insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_d2u : INS_vcvt_d2i;
1547 assert(srcType == TYP_FLOAT);
1548 insVcvt = (varTypeIsUnsigned(dstType)) ? INS_vcvt_f2u : INS_vcvt_f2i;
1550 // All other cast are implemented by different CORINFO_HELP_XX2XX
1551 // Look to Compiler::fgMorphCast()
1553 genConsumeOperands(treeNode->AsOp());
1555 regNumber tmpReg = treeNode->GetSingleTempReg();
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);
1561 genProduceReg(treeNode);
1564 //------------------------------------------------------------------------
1565 // genEmitHelperCall: Emit a call to a helper function.
1567 void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
1569 // Can we call the helper function directly
1571 void *addr = NULL, **pAddr = NULL;
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))
1579 addr = compiler->compProfilerMethHnd;
1584 addr = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, (void**)&pAddr);
1587 if (!addr || !arm_Valid_Imm_For_BL((ssize_t)addr))
1589 if (callTargetReg == REG_NA)
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;
1596 // Load the address into a register and call through a register
1599 instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, callTargetReg, (ssize_t)addr);
1603 getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, callTargetReg, (ssize_t)pAddr);
1604 regTracker.rsTrackRegTrash(callTargetReg);
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
1615 emitter::emitNoGChelper(helper),
1616 (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
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 */
1625 emitter::emitNoGChelper(helper),
1626 (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
1629 regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
1632 //------------------------------------------------------------------------
1633 // genStoreLongLclVar: Generate code to store a non-enregistered long lclVar
1636 // treeNode - A TYP_LONG lclVar node.
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.
1645 void CodeGen::genStoreLongLclVar(GenTree* treeNode)
1647 emitter* emit = getEmitter();
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);
1658 if (op1->OperGet() == GT_LONG)
1660 // Definitions of register candidates will have been lowered to 2 int lclVars.
1661 assert(!treeNode->gtHasReg());
1663 GenTree* loVal = op1->gtGetOp1();
1664 GenTree* hiVal = op1->gtGetOp2();
1666 noway_assert((loVal->gtRegNum != REG_NA) && (hiVal->gtRegNum != REG_NA));
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));
1671 else if (op1->OperGet() == GT_MUL_LONG)
1673 assert((op1->gtFlags & GTF_MUL_64RSLT) != 0);
1675 GenTreeMultiRegOp* mul = op1->AsMultiRegOp();
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));
1684 //------------------------------------------------------------------------
1685 // genCodeForMulLong: Generates code for int*int->long multiplication
1688 // node - the GT_MUL_LONG node
1693 void CodeGen::genCodeForMulLong(GenTreeMultiRegOp* node)
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);
1704 #endif // _TARGET_ARM_
1706 #endif // !LEGACY_BACKEND