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 Register Requirements for ARM XX
10 XX This encapsulates all the logic for setting register requirements for XX
11 XX the ARM architecture. XX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
23 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
28 #include "sideeffects.h"
32 //------------------------------------------------------------------------
33 // TreeNodeInfoInitStoreLoc: Lower a store of a lclVar
36 // storeLoc - the local store (GT_STORE_LCL_FLD or GT_STORE_LCL_VAR)
40 // - Setting the appropriate candidates for a store of a multi-reg call return value.
41 // - Handling of contained immediates and widening operations of unsigneds.
43 void Lowering::TreeNodeInfoInitStoreLoc(GenTreeLclVarCommon* storeLoc)
45 TreeNodeInfo* info = &(storeLoc->gtLsraInfo);
47 // Is this the case of var = call where call is returning
48 // a value in multiple return registers?
49 GenTree* op1 = storeLoc->gtGetOp1();
50 if (op1->IsMultiRegCall())
52 // backend expects to see this case only for store lclvar.
53 assert(storeLoc->OperGet() == GT_STORE_LCL_VAR);
55 // srcCount = number of registers in which the value is returned by call
56 GenTreeCall* call = op1->AsCall();
57 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
58 info->srcCount = retTypeDesc->GetReturnRegCount();
60 // Call node srcCandidates = Bitwise-OR(allregs(GetReturnRegType(i))) for all i=0..RetRegCount-1
61 regMaskTP srcCandidates = m_lsra->allMultiRegCallNodeRegs(call);
62 op1->gtLsraInfo.setSrcCandidates(m_lsra, srcCandidates);
66 CheckImmedAndMakeContained(storeLoc, op1);
69 //------------------------------------------------------------------------
70 // TreeNodeInfoInitCmp: Lower a GT comparison node.
73 // tree - the node to lower
78 void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
80 TreeNodeInfo* info = &(tree->gtLsraInfo);
85 GenTreePtr op1 = tree->gtOp.gtOp1;
86 GenTreePtr op2 = tree->gtOp.gtOp2;
87 var_types op1Type = op1->TypeGet();
88 var_types op2Type = op2->TypeGet();
90 // Long compares will consume GT_LONG nodes, each of which produces two results.
91 // Thus for each long operand there will be an additional source.
92 // TODO-ARM-CQ: Mark hiOp2 and loOp2 as contained if it is a constant.
93 if (varTypeIsLong(op1Type))
97 if (varTypeIsLong(op2Type))
102 CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
105 //------------------------------------------------------------------------
106 // TreeNodeInfoInitGCWriteBarrier: GC lowering helper.
109 // tree - the node to lower
114 void Lowering::TreeNodeInfoInitGCWriteBarrier(GenTree* tree)
116 GenTreePtr dst = tree;
117 GenTreePtr addr = tree->gtOp.gtOp1;
118 GenTreePtr src = tree->gtOp.gtOp2;
120 if (addr->OperGet() == GT_LEA)
122 // In the case where we are doing a helper assignment, if the dst
123 // is an indir through an lea, we need to actually instantiate the
125 GenTreeAddrMode* lea = addr->AsAddrMode();
127 short leaSrcCount = 0;
128 if (lea->Base() != nullptr)
132 if (lea->Index() != nullptr)
136 lea->gtLsraInfo.srcCount = leaSrcCount;
137 lea->gtLsraInfo.dstCount = 1;
140 #if NOGC_WRITE_BARRIERS
141 NYI_ARM("NOGC_WRITE_BARRIERS");
143 // For the standard JIT Helper calls
144 // op1 goes into REG_ARG_0 and
145 // op2 goes into REG_ARG_1
147 addr->gtLsraInfo.setSrcCandidates(m_lsra, RBM_ARG_0);
148 src->gtLsraInfo.setSrcCandidates(m_lsra, RBM_ARG_1);
149 #endif // NOGC_WRITE_BARRIERS
151 // Both src and dst must reside in a register, which they should since we haven't set
152 // either of them as contained.
153 assert(addr->gtLsraInfo.dstCount == 1);
154 assert(src->gtLsraInfo.dstCount == 1);
157 //------------------------------------------------------------------------
158 // TreeNodeInfoInitIndir: Specify register requirements for address expression
159 // of an indirection operation.
162 // indirTree - GT_IND, GT_STOREIND, block node or GT_NULLCHECK gentree node
164 void Lowering::TreeNodeInfoInitIndir(GenTreePtr indirTree)
166 assert(indirTree->OperIsIndir());
167 // If this is the rhs of a block copy (i.e. non-enregisterable struct),
168 // it has no register requirements.
169 if (indirTree->TypeGet() == TYP_STRUCT)
174 GenTreePtr addr = indirTree->gtGetOp1();
175 TreeNodeInfo* info = &(indirTree->gtLsraInfo);
177 GenTreePtr base = nullptr;
178 GenTreePtr index = nullptr;
182 bool modifiedSources = false;
184 if ((addr->OperGet() == GT_LEA) && IsSafeToContainMem(indirTree, addr))
186 GenTreeAddrMode* lea = addr->AsAddrMode();
188 index = lea->Index();
191 m_lsra->clearOperandCounts(addr);
192 // The srcCount is decremented because addr is now "contained",
193 // then we account for the base and index below, if they are non-null.
196 else if (comp->codeGen->genCreateAddrMode(addr, -1, true, 0, &rev, &base, &index, &mul, &cns, true /*nogen*/) &&
197 !(modifiedSources = AreSourcesPossiblyModifiedLocals(indirTree, base, index)))
199 // An addressing mode will be constructed that may cause some
200 // nodes to not need a register, and cause others' lifetimes to be extended
201 // to the GT_IND or even its parent if it's an assignment
203 assert(base != addr);
204 m_lsra->clearOperandCounts(addr);
206 GenTreePtr arrLength = nullptr;
208 // Traverse the computation below GT_IND to find the operands
209 // for the addressing mode, marking the various constants and
210 // intermediate results as not consuming/producing.
211 // If the traversal were more complex, we might consider using
212 // a traversal function, but the addressing mode is only made
213 // up of simple arithmetic operators, and the code generator
214 // only traverses one leg of each node.
216 bool foundBase = (base == nullptr);
217 bool foundIndex = (index == nullptr);
218 GenTreePtr nextChild = nullptr;
219 for (GenTreePtr child = addr; child != nullptr && !child->OperIsLeaf(); child = nextChild)
222 GenTreePtr op1 = child->gtOp.gtOp1;
223 GenTreePtr op2 = (child->OperIsBinary()) ? child->gtOp.gtOp2 : nullptr;
229 else if (op1 == index)
235 m_lsra->clearOperandCounts(op1);
236 if (!op1->OperIsLeaf())
248 else if (op2 == index)
254 m_lsra->clearOperandCounts(op2);
255 if (!op2->OperIsLeaf())
257 assert(nextChild == nullptr);
263 assert(foundBase && foundIndex);
264 info->srcCount--; // it gets incremented below.
266 else if (addr->gtOper == GT_ARR_ELEM)
268 // The GT_ARR_ELEM consumes all the indices and produces the offset.
269 // The array object lives until the mem access.
270 // We also consume the target register to which the address is
274 assert(addr->gtLsraInfo.srcCount >= 2);
275 addr->gtLsraInfo.srcCount -= 1;
279 // it is nothing but a plain indir
280 info->srcCount--; // base gets added in below
289 if (index != nullptr && !modifiedSources)
292 info->internalIntCount++;
296 //------------------------------------------------------------------------
297 // TreeNodeInfoInitReturn: Set the NodeInfo for a GT_RETURN.
300 // tree - The node of interest
305 void Lowering::TreeNodeInfoInitReturn(GenTree* tree)
307 TreeNodeInfo* info = &(tree->gtLsraInfo);
308 LinearScan* l = m_lsra;
309 Compiler* compiler = comp;
311 if (tree->TypeGet() == TYP_LONG)
313 GenTree* op1 = tree->gtGetOp1();
314 noway_assert(op1->OperGet() == GT_LONG);
315 GenTree* loVal = op1->gtGetOp1();
316 GenTree* hiVal = op1->gtGetOp2();
318 loVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_LO);
319 hiVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_HI);
324 GenTree* op1 = tree->gtGetOp1();
325 regMaskTP useCandidates = RBM_NONE;
327 info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
330 if (varTypeIsStruct(tree))
332 // op1 has to be either an lclvar or a multi-reg returning call
333 if (op1->OperGet() == GT_LCL_VAR)
335 GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon();
336 LclVarDsc* varDsc = &(compiler->lvaTable[lclVarCommon->gtLclNum]);
337 assert(varDsc->lvIsMultiRegRet);
339 // Mark var as contained if not enregistrable.
340 if (!varTypeIsEnregisterableStruct(op1))
342 MakeSrcContained(tree, op1);
347 noway_assert(op1->IsMultiRegCall());
349 ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc();
350 info->srcCount = retTypeDesc->GetReturnRegCount();
351 useCandidates = retTypeDesc->GetABIReturnRegs();
356 // Non-struct type return - determine useCandidates
357 switch (tree->TypeGet())
360 useCandidates = RBM_NONE;
363 useCandidates = RBM_FLOATRET;
366 useCandidates = RBM_DOUBLERET;
369 useCandidates = RBM_LNGRET;
372 useCandidates = RBM_INTRET;
377 if (useCandidates != RBM_NONE)
379 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, useCandidates);
384 //------------------------------------------------------------------------
385 // TreeNodeInfoInitShiftRotate: Set the NodeInfo for a shift or rotate.
388 // tree - The node of interest
393 void Lowering::TreeNodeInfoInitShiftRotate(GenTree* tree)
395 TreeNodeInfo* info = &(tree->gtLsraInfo);
396 LinearScan* l = m_lsra;
401 GenTreePtr shiftBy = tree->gtOp.gtOp2;
402 GenTreePtr source = tree->gtOp.gtOp1;
403 if (shiftBy->IsCnsIntOrI())
405 l->clearDstCount(shiftBy);
409 // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
410 // we can have a three operand form. Increment the srcCount.
411 if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
413 assert(source->OperGet() == GT_LONG);
417 if (tree->OperGet() == GT_LSH_HI)
419 GenTreePtr sourceLo = source->gtOp.gtOp1;
420 sourceLo->gtLsraInfo.isDelayFree = true;
424 GenTreePtr sourceHi = source->gtOp.gtOp2;
425 sourceHi->gtLsraInfo.isDelayFree = true;
428 source->gtLsraInfo.hasDelayFreeSrc = true;
429 info->hasDelayFreeSrc = true;
433 //------------------------------------------------------------------------
434 // TreeNodeInfoInitPutArgReg: Set the NodeInfo for a PUTARG_REG.
437 // node - The PUTARG_REG node.
438 // argReg - The register in which to pass the argument.
439 // info - The info for the node's using call.
440 // isVarArgs - True if the call uses a varargs calling convention.
441 // callHasFloatRegArgs - Set to true if this PUTARG_REG uses an FP register.
446 void Lowering::TreeNodeInfoInitPutArgReg(
447 GenTreeUnOp* node, regNumber argReg, TreeNodeInfo& info, bool isVarArgs, bool* callHasFloatRegArgs)
449 assert(node != nullptr);
450 assert(node->OperIsPutArgReg());
451 assert(argReg != REG_NA);
453 // Each register argument corresponds to one source.
456 // Set the register requirements for the node.
457 const regMaskTP argMask = genRegMask(argReg);
458 node->gtLsraInfo.setDstCandidates(m_lsra, argMask);
459 node->gtLsraInfo.setSrcCandidates(m_lsra, argMask);
461 // To avoid redundant moves, have the argument operand computed in the
462 // register in which the argument is passed to the call.
463 node->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(m_lsra, m_lsra->getUseCandidates(node));
465 *callHasFloatRegArgs |= varTypeIsFloating(node->TypeGet());
468 //------------------------------------------------------------------------
469 // TreeNodeInfoInitCall: Set the NodeInfo for a call.
472 // call - The call node of interest
477 void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
479 TreeNodeInfo* info = &(call->gtLsraInfo);
480 LinearScan* l = m_lsra;
481 Compiler* compiler = comp;
482 bool hasMultiRegRetVal = false;
483 ReturnTypeDesc* retTypeDesc = nullptr;
486 if (call->TypeGet() != TYP_VOID)
488 hasMultiRegRetVal = call->HasMultiRegRetVal();
489 if (hasMultiRegRetVal)
491 // dst count = number of registers in which the value is returned by call
492 retTypeDesc = call->GetReturnTypeDesc();
493 info->dstCount = retTypeDesc->GetReturnRegCount();
505 GenTree* ctrlExpr = call->gtControlExpr;
506 if (call->gtCallType == CT_INDIRECT)
508 // either gtControlExpr != null or gtCallAddr != null.
509 // Both cannot be non-null at the same time.
510 assert(ctrlExpr == nullptr);
511 assert(call->gtCallAddr != nullptr);
512 ctrlExpr = call->gtCallAddr;
515 // set reg requirements on call target represented as control sequence.
516 if (ctrlExpr != nullptr)
518 // we should never see a gtControlExpr whose type is void.
519 assert(ctrlExpr->TypeGet() != TYP_VOID);
522 // In case of fast tail implemented as jmp, make sure that gtControlExpr is
523 // computed into a register.
524 if (call->IsFastTailCall())
526 NYI_ARM("tail call");
531 info->internalIntCount = 1;
534 RegisterType registerType = call->TypeGet();
536 // Set destination candidates for return value of the call.
537 if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
539 // The ARM CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
540 // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers.
541 info->setDstCandidates(l, RBM_PINVOKE_TCB);
543 else if (hasMultiRegRetVal)
545 assert(retTypeDesc != nullptr);
546 info->setDstCandidates(l, retTypeDesc->GetABIReturnRegs());
548 else if (varTypeIsFloating(registerType))
550 info->setDstCandidates(l, RBM_FLOATRET);
552 else if (registerType == TYP_LONG)
554 info->setDstCandidates(l, RBM_LNGRET);
558 info->setDstCandidates(l, RBM_INTRET);
561 // If there is an explicit this pointer, we don't want that node to produce anything
562 // as it is redundant
563 if (call->gtCallObjp != nullptr)
565 GenTreePtr thisPtrNode = call->gtCallObjp;
567 if (thisPtrNode->gtOper == GT_PUTARG_REG)
569 l->clearOperandCounts(thisPtrNode);
570 l->clearDstCount(thisPtrNode->gtOp.gtOp1);
574 l->clearDstCount(thisPtrNode);
578 // First, count reg args
579 bool callHasFloatRegArgs = false;
581 for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
583 assert(list->OperIsList());
585 GenTreePtr argNode = list->Current();
587 fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
588 assert(curArgTabEntry);
590 if (curArgTabEntry->regNum == REG_STK)
592 // late arg that is not passed in a register
593 assert(argNode->gtOper == GT_PUTARG_STK);
595 TreeNodeInfoInitPutArgStk(argNode->AsPutArgStk(), curArgTabEntry);
599 // A GT_FIELD_LIST has a TYP_VOID, but is used to represent a multireg struct
600 if (argNode->OperGet() == GT_FIELD_LIST)
602 // There could be up to 2-4 PUTARG_REGs in the list (3 or 4 can only occur for HFAs)
603 regNumber argReg = curArgTabEntry->regNum;
604 for (GenTreeFieldList* entry = argNode->AsFieldList(); entry != nullptr; entry = entry->Rest())
606 TreeNodeInfoInitPutArgReg(entry->Current()->AsUnOp(), argReg, *info, false, &callHasFloatRegArgs);
608 // Update argReg for the next putarg_reg (if any)
609 argReg = genRegArgNext(argReg);
614 TreeNodeInfoInitPutArgReg(argNode->AsUnOp(), curArgTabEntry->regNum, *info, false, &callHasFloatRegArgs);
618 // Now, count stack args
619 // Note that these need to be computed into a register, but then
620 // they're just stored to the stack - so the reg doesn't
621 // need to remain live until the call. In fact, it must not
622 // because the code generator doesn't actually consider it live,
623 // so it can't be spilled.
625 GenTreePtr args = call->gtCallArgs;
628 GenTreePtr arg = args->gtOp.gtOp1;
630 // Skip arguments that have been moved to the Late Arg list
631 if (!(args->gtFlags & GTF_LATE_ARG))
633 if (arg->gtOper == GT_PUTARG_STK)
635 fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
636 assert(curArgTabEntry);
638 assert(curArgTabEntry->regNum == REG_STK);
640 TreeNodeInfoInitPutArgStk(arg->AsPutArgStk(), curArgTabEntry);
644 TreeNodeInfo* argInfo = &(arg->gtLsraInfo);
645 if (argInfo->dstCount != 0)
647 argInfo->isLocalDefUse = true;
650 argInfo->dstCount = 0;
653 args = args->gtOp.gtOp2;
656 if (call->IsVarargs() && callHasFloatRegArgs && !call->IsFastTailCall() && (ctrlExpr != nullptr))
658 NYI_ARM("float reg varargs");
661 if (call->NeedsNullCheck())
663 info->internalIntCount++;
667 //------------------------------------------------------------------------
668 // TreeNodeInfoInitPutArgStk: Set the NodeInfo for a GT_PUTARG_STK node
671 // argNode - a GT_PUTARG_STK node
677 // Set the child node(s) to be contained when we have a multireg arg
679 void Lowering::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntryPtr info)
681 assert(argNode->gtOper == GT_PUTARG_STK);
683 GenTreePtr putArgChild = argNode->gtOp.gtOp1;
685 // Initialize 'argNode' as not contained, as this is both the default case
686 // and how MakeSrcContained expects to find things setup.
688 argNode->gtLsraInfo.srcCount = 1;
689 argNode->gtLsraInfo.dstCount = 0;
691 // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct
692 if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_FIELD_LIST))
694 // We will use store instructions that each write a register sized value
696 if (putArgChild->OperGet() == GT_FIELD_LIST)
698 // We consume all of the items in the GT_FIELD_LIST
699 argNode->gtLsraInfo.srcCount = info->numSlots;
703 // We could use a ldp/stp sequence so we need two internal registers
704 argNode->gtLsraInfo.internalIntCount = 2;
706 if (putArgChild->OperGet() == GT_OBJ)
708 GenTreePtr objChild = putArgChild->gtOp.gtOp1;
709 if (objChild->OperGet() == GT_LCL_VAR_ADDR)
711 // We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR
712 // as one contained operation
714 MakeSrcContained(putArgChild, objChild);
718 // We will generate all of the code for the GT_PUTARG_STK and it's child node
719 // as one contained operation
721 MakeSrcContained(argNode, putArgChild);
726 // We must not have a multi-reg struct
727 assert(info->numSlots == 1);
731 void Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
733 TreeNodeInfo* info = &(tree->gtLsraInfo);
734 LinearScan* l = m_lsra;
735 Compiler* compiler = comp;
740 // Need a variable number of temp regs (see genLclHeap() in codegenarm.cpp):
741 // Here '-' means don't care.
743 // Size? Init Memory? # temp regs
745 // const and <=4 ptr words - hasPspSym ? 1 : 0
746 // const and <PageSize No hasPspSym ? 1 : 0
747 // >4 ptr words Yes hasPspSym ? 2 : 1
748 // Non-const Yes hasPspSym ? 2 : 1
749 // Non-const No hasPspSym ? 2 : 1
752 #if FEATURE_EH_FUNCLETS
753 hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
758 GenTreePtr size = tree->gtOp.gtOp1;
759 if (size->IsCnsIntOrI())
761 MakeSrcContained(tree, size);
763 size_t sizeVal = size->gtIntCon.gtIconVal;
766 info->internalIntCount = 0;
770 sizeVal = AlignUp(sizeVal, STACK_ALIGN);
771 size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
773 // For small allocations up to 4 store instructions
774 if (cntStackAlignedWidthItems <= 4)
776 info->internalIntCount = 0;
778 else if (!compiler->info.compInitMem)
780 // No need to initialize allocated stack space.
781 if (sizeVal < compiler->eeGetPageSize())
783 info->internalIntCount = 0;
787 // target (regCnt) + tmp + [psp]
788 info->internalIntCount = 1;
789 info->isInternalRegDelayFree = true;
794 // target (regCnt) + tmp + [psp]
795 info->internalIntCount = 1;
796 info->isInternalRegDelayFree = true;
801 info->internalIntCount++;
807 // target (regCnt) + tmp + [psp]
808 info->internalIntCount = hasPspSym ? 2 : 1;
809 info->isInternalRegDelayFree = true;
813 //------------------------------------------------------------------------
814 // TreeNodeInfoInitBlockStore: Set the NodeInfo for a block store.
817 // blkNode - The block store node of interest
821 void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
823 GenTree* dstAddr = blkNode->Addr();
824 unsigned size = blkNode->gtBlkSize;
825 GenTree* source = blkNode->Data();
826 LinearScan* l = m_lsra;
827 Compiler* compiler = comp;
829 // Sources are dest address and initVal or source.
830 // We may require an additional source or temp register for the size.
831 blkNode->gtLsraInfo.srcCount = 2;
832 blkNode->gtLsraInfo.dstCount = 0;
833 GenTreePtr srcAddrOrFill = nullptr;
834 bool isInitBlk = blkNode->OperIsInitBlkOp();
838 // CopyObj or CopyBlk
839 if (source->gtOper == GT_IND)
841 srcAddrOrFill = blkNode->Data()->gtGetOp1();
842 // We're effectively setting source as contained, but can't call MakeSrcContained, because the
843 // "inheritance" of the srcCount is to a child not a parent - it would "just work" but could be misleading.
844 // If srcAddr is already non-contained, we don't need to change it.
845 if (srcAddrOrFill->gtLsraInfo.getDstCount() == 0)
847 srcAddrOrFill->gtLsraInfo.setDstCount(1);
848 srcAddrOrFill->gtLsraInfo.setSrcCount(source->gtLsraInfo.srcCount);
850 m_lsra->clearOperandCounts(source);
852 else if (!source->IsMultiRegCall() && !source->OperIsSIMD())
854 assert(source->IsLocal());
855 MakeSrcContained(blkNode, source);
861 GenTreePtr initVal = source;
862 if (initVal->OperIsInitVal())
864 initVal = initVal->gtGetOp1();
866 srcAddrOrFill = initVal;
868 if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
870 // TODO-ARM-CQ: Currently we generate a helper call for every
871 // initblk we encounter. Later on we should implement loop unrolling
872 // code sequences to improve CQ.
873 // For reference see the code in lsraxarch.cpp.
874 NYI_ARM("initblk loop unrolling is currently not implemented.");
878 assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
879 // The helper follows the regular ABI.
880 dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
881 initVal->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
884 // Reserve a temp register for the block size argument.
885 blkNode->gtLsraInfo.setInternalCandidates(l, RBM_ARG_2);
886 blkNode->gtLsraInfo.internalIntCount = 1;
890 // The block size argument is a third argument to GT_STORE_DYN_BLK
891 noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
892 blkNode->gtLsraInfo.setSrcCount(3);
893 GenTree* sizeNode = blkNode->AsDynBlk()->gtDynamicSize;
894 sizeNode->gtLsraInfo.setSrcCandidates(l, RBM_ARG_2);
900 // CopyObj or CopyBlk
901 // Sources are src and dest and size if not constant.
902 if (blkNode->OperGet() == GT_STORE_OBJ)
905 NYI_ARM("GT_STORE_OBJ is needed of write barriers implementation");
910 short internalIntCount = 0;
911 regMaskTP internalIntCandidates = RBM_NONE;
913 if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
915 // TODO-ARM-CQ: cpblk loop unrolling is currently not implemented.
916 // In case of a CpBlk with a constant size and less than CPBLK_UNROLL_LIMIT size
917 // we should unroll the loop to improve CQ.
918 // For reference see the code in lsraxarch.cpp.
919 NYI_ARM("cpblk loop unrolling is currently not implemented.");
923 assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
924 dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
925 // The srcAddr goes in arg1.
926 if (srcAddrOrFill != nullptr)
928 srcAddrOrFill->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
932 // Reserve a temp register for the block size argument.
933 internalIntCandidates |= RBM_ARG_2;
938 // The block size argument is a third argument to GT_STORE_DYN_BLK
939 noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
940 blkNode->gtLsraInfo.setSrcCount(3);
941 GenTree* blockSize = blkNode->AsDynBlk()->gtDynamicSize;
942 blockSize->gtLsraInfo.setSrcCandidates(l, RBM_ARG_2);
945 if (internalIntCount != 0)
947 blkNode->gtLsraInfo.internalIntCount = internalIntCount;
948 blkNode->gtLsraInfo.setInternalCandidates(l, internalIntCandidates);
954 //------------------------------------------------------------------------
955 // TreeNodeInfoInit: Set the register requirements for RA.
958 // Takes care of annotating the register requirements
959 // for every TreeNodeInfo struct that maps to each tree node.
962 // LSRA has been initialized and there is a TreeNodeInfo node
963 // already allocated and initialized for every tree in the IR.
966 // Every TreeNodeInfo instance has the right annotations on register
967 // requirements needed by LSRA to build the Interval Table (source,
968 // destination and internal [temp] register counts).
970 void Lowering::TreeNodeInfoInit(GenTree* tree)
972 LinearScan* l = m_lsra;
973 Compiler* compiler = comp;
975 unsigned kind = tree->OperKind();
976 TreeNodeInfo* info = &(tree->gtLsraInfo);
977 RegisterType registerType = TypeGet(tree);
979 JITDUMP("TreeNodeInfoInit for: ");
982 NYI_IF(tree->TypeGet() == TYP_DOUBLE, "lowering double");
984 switch (tree->OperGet())
989 case GT_STORE_LCL_FLD:
990 case GT_STORE_LCL_VAR:
991 if (tree->gtGetOp1()->OperGet() == GT_LONG)
1000 LowerStoreLoc(tree->AsLclVarCommon());
1001 TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon());
1005 // A GT_NOP is either a passthrough (if it is void, or if it has
1006 // a child), but must be considered to produce a dummy value if it
1007 // has a type but no child
1009 if (tree->TypeGet() != TYP_VOID && tree->gtOp.gtOp1 == nullptr)
1021 // TODO-ARM: Implement other type of intrinsics (round, sqrt and etc.)
1022 // Both operand and its result must be of the same floating point type.
1023 op1 = tree->gtOp.gtOp1;
1024 assert(varTypeIsFloating(op1));
1025 assert(op1->TypeGet() == tree->TypeGet());
1027 switch (tree->gtIntrinsic.gtIntrinsicId)
1029 case CORINFO_INTRINSIC_Abs:
1030 case CORINFO_INTRINSIC_Sqrt:
1035 NYI_ARM("Lowering::TreeNodeInfoInit for GT_INTRINSIC");
1046 // Non-overflow casts to/from float/double are done using SSE2 instructions
1047 // and that allow the source operand to be either a reg or memop. Given the
1048 // fact that casts from small int to float/double are done as two-level casts,
1049 // the source operand is always guaranteed to be of size 4 or 8 bytes.
1050 var_types castToType = tree->CastToType();
1051 GenTreePtr castOp = tree->gtCast.CastOp();
1052 var_types castOpType = castOp->TypeGet();
1053 if (tree->gtFlags & GTF_UNSIGNED)
1055 castOpType = genUnsignedType(castOpType);
1058 if (!tree->gtOverflow() && (varTypeIsFloating(castToType) || varTypeIsFloating(castOpType)))
1060 // If converting to float/double, the operand must be 4 or 8 byte in size.
1061 if (varTypeIsFloating(castToType))
1063 unsigned opSize = genTypeSize(castOpType);
1064 assert(opSize == 4 || opSize == 8);
1069 if (varTypeIsLong(castOpType))
1071 noway_assert(castOp->OperGet() == GT_LONG);
1077 // Get information about the cast.
1078 getCastDescription(tree, &castInfo);
1080 if (castInfo.requiresOverflowCheck)
1082 var_types srcType = castOp->TypeGet();
1083 emitAttr cmpSize = EA_ATTR(genTypeSize(srcType));
1085 // If we cannot store the comparisons in an immediate for either
1086 // comparing against the max or min value, then we will need to
1087 // reserve a temporary register.
1089 bool canStoreMaxValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE);
1090 bool canStoreMinValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE);
1092 if (!canStoreMaxValue || !canStoreMinValue)
1094 info->internalIntCount = 1;
1103 l->clearDstCount(tree->gtOp.gtOp1);
1112 // This should never occur since switch nodes must not be visible at this
1113 // point in the JIT.
1115 info->dstCount = 0; // To avoid getting uninit errors.
1116 noway_assert(!"Switch must be lowered at this point");
1124 case GT_SWITCH_TABLE:
1132 noway_assert(!"We should never hit any assignment operator in lowering");
1143 if (varTypeIsFloating(tree->TypeGet()))
1145 // overflow operations aren't supported on float/double types.
1146 assert(!tree->gtOverflow());
1148 // No implicit conversions at this stage as the expectation is that
1149 // everything is made explicit by adding casts.
1150 assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
1165 // Check and make op2 contained (if it is a containable immediate)
1166 CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
1170 // this just turns into a compare of its child with an int
1171 // + a conditional call
1177 if (tree->gtOverflow())
1179 // Need a register different from target reg to check for overflow.
1180 info->internalIntCount = 2;
1197 case GT_START_NONGC:
1204 if ((tree->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0)
1206 // An unused GT_LONG node needs to consume its sources.
1221 if (tree->TypeGet() == TYP_FLOAT)
1223 // An int register for float constant
1224 info->internalIntCount = 1;
1229 assert(tree->TypeGet() == TYP_DOUBLE);
1231 // Two int registers for double constant
1232 info->internalIntCount = 2;
1237 TreeNodeInfoInitReturn(tree);
1241 if (tree->TypeGet() == TYP_VOID)
1248 assert(tree->TypeGet() == TYP_INT);
1253 info->setSrcCandidates(l, RBM_INTRET);
1254 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, RBM_INTRET);
1258 case GT_ARR_BOUNDS_CHECK:
1261 #endif // FEATURE_SIMD
1263 // Consumes arrLen & index - has no result
1270 // These must have been lowered to GT_ARR_INDEX
1271 noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
1280 // We need one internal register when generating code for GT_ARR_INDEX, however the
1281 // register allocator always may just give us the same one as it gives us for the 'dst'
1282 // as a workaround we will just ask for two internal registers.
1284 info->internalIntCount = 2;
1286 // For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
1287 // times while the result is being computed.
1288 tree->AsArrIndex()->ArrObj()->gtLsraInfo.isDelayFree = true;
1289 info->hasDelayFreeSrc = true;
1293 // This consumes the offset, if any, the arrObj and the effective index,
1294 // and produces the flattened offset for this dimension.
1297 info->internalIntCount = 1;
1299 // we don't want to generate code for this
1300 if (tree->gtArrOffs.gtOffset->IsIntegralConst(0))
1302 MakeSrcContained(tree, tree->gtArrOffs.gtOffset);
1308 GenTreeAddrMode* lea = tree->AsAddrMode();
1310 GenTree* base = lea->Base();
1311 GenTree* index = lea->Index();
1312 unsigned cns = lea->gtOffset;
1314 // This LEA is instantiating an address,
1315 // so we set up the srcCount and dstCount here.
1317 if (base != nullptr)
1321 if (index != nullptr)
1327 // On ARM we may need a single internal register
1328 // (when both conditions are true then we still only need a single internal register)
1329 if ((index != nullptr) && (cns != 0))
1331 // ARM does not support both Index and offset so we need an internal register
1332 info->internalIntCount = 1;
1334 else if (!emitter::emitIns_valid_imm_for_add(cns, INS_FLAGS_DONT_CARE))
1336 // This offset can't be contained in the add instruction, so we need an internal register
1337 info->internalIntCount = 1;
1358 TreeNodeInfoInitShiftRotate(tree);
1367 TreeNodeInfoInitCmp(tree);
1371 TreeNodeInfoInitCall(tree->AsCall());
1376 case GT_STORE_DYN_BLK:
1377 LowerBlockStore(tree->AsBlk());
1378 TreeNodeInfoInitBlockStore(tree->AsBlk());
1382 TreeNodeInfoInitLclHeap(tree);
1389 GenTree* src = tree->gtOp.gtOp2;
1391 if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
1393 TreeNodeInfoInitGCWriteBarrier(tree);
1397 TreeNodeInfoInitIndir(tree);
1404 info->isLocalDefUse = true;
1405 // null check is an indirection on an addr
1406 TreeNodeInfoInitIndir(tree);
1412 TreeNodeInfoInitIndir(tree);
1418 info->setDstCandidates(l, RBM_EXCEPTION_OBJECT);
1423 // GT_CLS_VAR, by the time we reach the backend, must always
1425 // It will produce a result of the type of the
1426 // node, and use an internal register for the address.
1429 assert((tree->gtFlags & (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_USEDEF)) == 0);
1430 info->internalIntCount = 1;
1436 _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
1437 GenTree::NodeName(tree->OperGet()));
1440 NYI_ARM("TreeNodeInfoInit default case");
1443 case GT_LCL_FLD_ADDR:
1445 case GT_LCL_VAR_ADDR:
1447 case GT_CLS_VAR_ADDR:
1453 case GT_PINVOKE_PROLOG:
1455 case GT_MEMORYBARRIER:
1456 info->dstCount = tree->IsValue() ? 1 : 0;
1457 if (kind & (GTK_CONST | GTK_LEAF))
1461 else if (kind & (GTK_SMPOP))
1463 if (tree->gtGetOp2IfPresent() != nullptr)
1477 } // end switch (tree->OperGet())
1479 // We need to be sure that we've set info->srcCount and info->dstCount appropriately
1480 assert((info->dstCount < 2) || tree->IsMultiRegCall());
1483 #endif // _TARGET_ARM_
1485 #endif // !LEGACY_BACKEND