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 // TreeNodeInfoInitReturn: Set the NodeInfo for a GT_RETURN.
36 // tree - The node of interest
41 void Lowering::TreeNodeInfoInitReturn(GenTree* tree)
43 TreeNodeInfo* info = &(tree->gtLsraInfo);
44 LinearScan* l = m_lsra;
45 Compiler* compiler = comp;
47 if (tree->TypeGet() == TYP_LONG)
49 GenTree* op1 = tree->gtGetOp1();
50 noway_assert(op1->OperGet() == GT_LONG);
51 GenTree* loVal = op1->gtGetOp1();
52 GenTree* hiVal = op1->gtGetOp2();
54 loVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_LO);
55 hiVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_HI);
60 GenTree* op1 = tree->gtGetOp1();
61 regMaskTP useCandidates = RBM_NONE;
63 info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
66 if (varTypeIsStruct(tree))
68 // op1 has to be either an lclvar or a multi-reg returning call
69 if (op1->OperGet() == GT_LCL_VAR)
71 GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon();
72 LclVarDsc* varDsc = &(compiler->lvaTable[lclVarCommon->gtLclNum]);
73 assert(varDsc->lvIsMultiRegRet);
75 // Mark var as contained if not enregistrable.
76 if (!varTypeIsEnregisterableStruct(op1))
78 MakeSrcContained(tree, op1);
83 noway_assert(op1->IsMultiRegCall());
85 ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc();
86 info->srcCount = retTypeDesc->GetReturnRegCount();
87 useCandidates = retTypeDesc->GetABIReturnRegs();
92 // Non-struct type return - determine useCandidates
93 switch (tree->TypeGet())
96 useCandidates = RBM_NONE;
99 useCandidates = RBM_FLOATRET;
102 useCandidates = RBM_DOUBLERET;
105 useCandidates = RBM_LNGRET;
108 useCandidates = RBM_INTRET;
113 if (useCandidates != RBM_NONE)
115 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, useCandidates);
120 void Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
122 TreeNodeInfo* info = &(tree->gtLsraInfo);
123 LinearScan* l = m_lsra;
124 Compiler* compiler = comp;
129 // Need a variable number of temp regs (see genLclHeap() in codegenarm.cpp):
130 // Here '-' means don't care.
132 // Size? Init Memory? # temp regs
134 // const and <=4 str instr - hasPspSym ? 1 : 0
135 // const and <PageSize No hasPspSym ? 1 : 0
136 // >4 ptr words Yes hasPspSym ? 2 : 1
137 // Non-const Yes hasPspSym ? 2 : 1
138 // Non-const No hasPspSym ? 2 : 1
141 #if FEATURE_EH_FUNCLETS
142 hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
147 GenTreePtr size = tree->gtOp.gtOp1;
148 if (size->IsCnsIntOrI())
150 MakeSrcContained(tree, size);
152 size_t sizeVal = size->gtIntCon.gtIconVal;
155 info->internalIntCount = 0;
159 sizeVal = AlignUp(sizeVal, STACK_ALIGN);
160 size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
162 // For small allocations up to 4 store instructions
163 if (cntStackAlignedWidthItems <= 4)
165 info->internalIntCount = 0;
167 else if (!compiler->info.compInitMem)
169 // No need to initialize allocated stack space.
170 if (sizeVal < compiler->eeGetPageSize())
172 info->internalIntCount = 0;
176 info->internalIntCount = 1;
181 info->internalIntCount = 1;
186 info->internalIntCount++;
192 // target (regCnt) + tmp + [psp]
193 info->internalIntCount = hasPspSym ? 2 : 1;
196 // If we are needed in temporary registers we should be sure that
197 // it's different from target (regCnt)
198 if (info->internalIntCount > 0)
200 info->isInternalRegDelayFree = true;
204 //------------------------------------------------------------------------
205 // TreeNodeInfoInit: Set the register requirements for RA.
208 // Takes care of annotating the register requirements
209 // for every TreeNodeInfo struct that maps to each tree node.
212 // LSRA has been initialized and there is a TreeNodeInfo node
213 // already allocated and initialized for every tree in the IR.
216 // Every TreeNodeInfo instance has the right annotations on register
217 // requirements needed by LSRA to build the Interval Table (source,
218 // destination and internal [temp] register counts).
220 void Lowering::TreeNodeInfoInit(GenTree* tree)
222 LinearScan* l = m_lsra;
223 Compiler* compiler = comp;
225 unsigned kind = tree->OperKind();
226 TreeNodeInfo* info = &(tree->gtLsraInfo);
227 RegisterType registerType = TypeGet(tree);
229 JITDUMP("TreeNodeInfoInit for: ");
232 switch (tree->OperGet())
237 case GT_STORE_LCL_FLD:
238 case GT_STORE_LCL_VAR:
239 if (varTypeIsLong(tree->gtGetOp1()))
248 LowerStoreLoc(tree->AsLclVarCommon());
249 TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon());
253 // A GT_NOP is either a passthrough (if it is void, or if it has
254 // a child), but must be considered to produce a dummy value if it
255 // has a type but no child
257 if (tree->TypeGet() != TYP_VOID && tree->gtOp.gtOp1 == nullptr)
269 // TODO-ARM: Implement other type of intrinsics (round, sqrt and etc.)
270 // Both operand and its result must be of the same floating point type.
271 op1 = tree->gtOp.gtOp1;
272 assert(varTypeIsFloating(op1));
273 assert(op1->TypeGet() == tree->TypeGet());
275 switch (tree->gtIntrinsic.gtIntrinsicId)
277 case CORINFO_INTRINSIC_Abs:
278 case CORINFO_INTRINSIC_Sqrt:
283 NYI_ARM("Lowering::TreeNodeInfoInit for GT_INTRINSIC");
294 // Non-overflow casts to/from float/double are done using SSE2 instructions
295 // and that allow the source operand to be either a reg or memop. Given the
296 // fact that casts from small int to float/double are done as two-level casts,
297 // the source operand is always guaranteed to be of size 4 or 8 bytes.
298 var_types castToType = tree->CastToType();
299 GenTreePtr castOp = tree->gtCast.CastOp();
300 var_types castOpType = castOp->TypeGet();
301 if (tree->gtFlags & GTF_UNSIGNED)
303 castOpType = genUnsignedType(castOpType);
306 if (!tree->gtOverflow() && (varTypeIsFloating(castToType) || varTypeIsFloating(castOpType)))
308 // If converting to float/double, the operand must be 4 or 8 byte in size.
309 if (varTypeIsFloating(castToType))
311 unsigned opSize = genTypeSize(castOpType);
312 assert(opSize == 4 || opSize == 8);
317 if (varTypeIsLong(castOpType))
319 noway_assert(castOp->OperGet() == GT_LONG);
323 // FloatToIntCast needs a temporary register
324 if (varTypeIsFloating(castOpType) && varTypeIsIntOrI(tree))
326 info->setInternalCandidates(m_lsra, RBM_ALLFLOAT);
327 info->internalFloatCount = 1;
328 info->isInternalRegDelayFree = true;
333 // Get information about the cast.
334 getCastDescription(tree, &castInfo);
336 if (castInfo.requiresOverflowCheck)
338 var_types srcType = castOp->TypeGet();
339 emitAttr cmpSize = EA_ATTR(genTypeSize(srcType));
341 // If we cannot store data in an immediate for instructions,
342 // then we will need to reserve a temporary register.
344 if (!castInfo.signCheckOnly) // In case of only sign check, temp regs are not needeed.
346 if (castInfo.unsignedSource || castInfo.unsignedDest)
349 bool canStoreTypeMask = emitter::emitIns_valid_imm_for_alu(castInfo.typeMask);
350 if (!canStoreTypeMask)
352 info->internalIntCount = 1;
357 // For comparing against the max or min value
358 bool canStoreMaxValue =
359 emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE);
360 bool canStoreMinValue =
361 emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE);
363 if (!canStoreMaxValue || !canStoreMinValue)
365 info->internalIntCount = 1;
376 l->clearDstCount(tree->gtOp.gtOp1);
385 // This should never occur since switch nodes must not be visible at this
388 info->dstCount = 0; // To avoid getting uninit errors.
389 noway_assert(!"Switch must be lowered at this point");
397 case GT_SWITCH_TABLE:
405 noway_assert(!"We should never hit any assignment operator in lowering");
416 if (varTypeIsFloating(tree->TypeGet()))
418 // overflow operations aren't supported on float/double types.
419 assert(!tree->gtOverflow());
421 // No implicit conversions at this stage as the expectation is that
422 // everything is made explicit by adding casts.
423 assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
438 // Check and make op2 contained (if it is a containable immediate)
439 CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
443 // this just turns into a compare of its child with an int
444 // + a conditional call
450 if (tree->gtOverflow())
452 // Need a register different from target reg to check for overflow.
453 info->internalIntCount = 1;
454 info->isInternalRegDelayFree = true;
483 if ((tree->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0)
485 // An unused GT_LONG node needs to consume its sources.
500 if (tree->TypeGet() == TYP_FLOAT)
502 // An int register for float constant
503 info->internalIntCount = 1;
508 assert(tree->TypeGet() == TYP_DOUBLE);
510 // Two int registers for double constant
511 info->internalIntCount = 2;
516 TreeNodeInfoInitReturn(tree);
520 if (tree->TypeGet() == TYP_VOID)
527 assert(tree->TypeGet() == TYP_INT);
532 info->setSrcCandidates(l, RBM_INTRET);
533 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, RBM_INTRET);
537 case GT_ARR_BOUNDS_CHECK:
540 #endif // FEATURE_SIMD
542 // Consumes arrLen & index - has no result
549 // These must have been lowered to GT_ARR_INDEX
550 noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
558 info->internalIntCount = 1;
559 info->isInternalRegDelayFree = true;
561 // For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
562 // times while the result is being computed.
563 tree->AsArrIndex()->ArrObj()->gtLsraInfo.isDelayFree = true;
564 info->hasDelayFreeSrc = true;
568 // This consumes the offset, if any, the arrObj and the effective index,
569 // and produces the flattened offset for this dimension.
573 // we don't want to generate code for this
574 if (tree->gtArrOffs.gtOffset->IsIntegralConst(0))
576 MakeSrcContained(tree, tree->gtArrOffs.gtOffset);
580 // Here we simply need an internal register, which must be different
581 // from any of the operand's registers, but may be the same as targetReg.
582 info->internalIntCount = 1;
588 GenTreeAddrMode* lea = tree->AsAddrMode();
589 unsigned offset = lea->gtOffset;
591 // This LEA is instantiating an address, so we set up the srcCount and dstCount here.
603 // An internal register may be needed too; the logic here should be in sync with the
604 // genLeaInstruction()'s requirements for a such register.
605 if (lea->HasBase() && lea->HasIndex())
609 // We need a register when we have all three: base reg, index reg and a non-zero offset.
610 info->internalIntCount = 1;
613 else if (lea->HasBase())
615 if (!emitter::emitIns_valid_imm_for_add(offset, INS_FLAGS_DONT_CARE))
617 // We need a register when we have an offset that is too large to encode in the add instruction.
618 info->internalIntCount = 1;
640 TreeNodeInfoInitShiftRotate(tree);
650 TreeNodeInfoInitCmp(tree);
656 info->internalIntCount = 1;
660 TreeNodeInfoInitCall(tree->AsCall());
665 case GT_STORE_DYN_BLK:
666 LowerBlockStore(tree->AsBlk());
667 TreeNodeInfoInitBlockStore(tree->AsBlk());
671 // Always a passthrough of its child's value.
677 TreeNodeInfoInitLclHeap(tree);
684 GenTree* src = tree->gtOp.gtOp2;
686 if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
688 TreeNodeInfoInitGCWriteBarrier(tree);
692 TreeNodeInfoInitIndir(tree);
699 info->isLocalDefUse = true;
700 // null check is an indirection on an addr
701 TreeNodeInfoInitIndir(tree);
707 TreeNodeInfoInitIndir(tree);
713 info->setDstCandidates(l, RBM_EXCEPTION_OBJECT);
718 // GT_CLS_VAR, by the time we reach the backend, must always
720 // It will produce a result of the type of the
721 // node, and use an internal register for the address.
724 assert((tree->gtFlags & (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_USEDEF)) == 0);
725 info->internalIntCount = 1;
731 _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
732 GenTree::NodeName(tree->OperGet()));
735 NYI_ARM("TreeNodeInfoInit default case");
738 case GT_LCL_FLD_ADDR:
740 case GT_LCL_VAR_ADDR:
742 case GT_CLS_VAR_ADDR:
748 case GT_PINVOKE_PROLOG:
751 case GT_MEMORYBARRIER:
753 info->dstCount = tree->IsValue() ? 1 : 0;
754 if (kind & (GTK_CONST | GTK_LEAF))
758 else if (kind & (GTK_SMPOP))
760 if (tree->gtGetOp2IfPresent() != nullptr)
774 } // end switch (tree->OperGet())
776 // We need to be sure that we've set info->srcCount and info->dstCount appropriately
777 assert((info->dstCount < 2) || tree->IsMultiRegNode());
780 #endif // _TARGET_ARM_
782 #endif // !LEGACY_BACKEND