1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX Register Requirements for RISCV64 XX
9 XX This encapsulates all the logic for setting register requirements for XX
10 XX the RISCV64 architecture. XX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
25 #include "sideeffects.h"
29 //------------------------------------------------------------------------
30 // BuildNode: Build the RefPositions for a node
33 // treeNode - the node of interest
36 // The number of sources consumed by this node.
40 // LSRA Has been initialized.
43 // RefPositions have been built for all the register defs and uses required
46 int LinearScan::BuildNode(GenTree* tree)
48 assert(!tree->isContained());
51 regMaskTP dstCandidates = RBM_NONE;
52 regMaskTP killMask = RBM_NONE;
53 bool isLocalDefUse = false;
55 // Reset the build-related members of LinearScan.
58 // Set the default dstCount. This may be modified below.
62 if (tree->IsUnusedValue())
72 switch (tree->OperGet())
75 srcCount = BuildSimple(tree);
79 // We make a final determination about whether a GT_LCL_VAR is a candidate or contained
80 // after liveness. In either case we don't build any uses or defs. Otherwise, this is a
81 // load of a stack-based local into a register and we'll fall through to the general
83 if (checkContainedOrCandidateLclVar(tree->AsLclVar()))
92 // Need an additional register to read upper 4 bytes of Vector3.
93 if (tree->TypeGet() == TYP_SIMD12)
95 // We need an internal register different from targetReg in which 'tree' produces its result
96 // because both targetReg and internal reg will be in use at the same time.
97 buildInternalFloatRegisterDefForNode(tree, allSIMDRegs());
98 setInternalRegsDelayFree = true;
99 buildInternalRegisterUses();
106 case GT_STORE_LCL_VAR:
107 if (tree->IsMultiRegLclVar() && isCandidateMultiRegLclVar(tree->AsLclVar()))
109 dstCount = compiler->lvaGetDesc(tree->AsLclVar())->lvFieldCnt;
113 case GT_STORE_LCL_FLD:
114 srcCount = BuildStoreLoc(tree->AsLclVarCommon());
118 // These should always be contained. We don't correctly allocate or
119 // generate code for a non-contained GT_FIELD_LIST.
120 noway_assert(!"Non-contained GT_FIELD_LIST");
127 assert(dstCount == 0);
132 assert(dstCount == 0);
133 killMask = getKillSetForProfilerHook();
134 BuildDefsWithKills(tree, 0, RBM_NONE, killMask);
137 case GT_START_PREEMPTGC:
138 // This kills GC refs in callee save regs
140 assert(dstCount == 0);
141 BuildDefsWithKills(tree, 0, RBM_NONE, RBM_NONE);
146 // There is no instruction for loading float/double imm directly into FPR.
147 // Reserve int to load constant from memory (IF_LARGELDC)
148 buildInternalIntRegisterDefForNode(tree);
149 buildInternalRegisterUses();
156 assert(dstCount == 1);
157 RefPosition* def = BuildDef(tree);
158 def->getInterval()->isConstant = true;
167 assert(dstCount == 0);
172 srcCount = BuildReturn(tree);
173 killMask = getKillSetForReturn();
174 BuildDefsWithKills(tree, 0, RBM_NONE, killMask);
178 assert(dstCount == 0);
179 if (tree->TypeGet() == TYP_VOID)
185 assert(tree->TypeGet() == TYP_INT);
187 BuildUse(tree->gtGetOp1(), RBM_INTRET);
192 // A GT_NOP is either a passthrough (if it is void, or if it has
193 // a child), but must be considered to produce a dummy value if it
194 // has a type but no child.
196 if (tree->TypeGet() != TYP_VOID && tree->gtGetOp1() == nullptr)
198 assert(dstCount == 1);
203 assert(dstCount == 0);
208 assert(dstCount == 0);
209 srcCount = BuildOperandUses(tree->gtGetOp1());
214 assert(dstCount == 0);
219 assert(dstCount == 0);
223 // This should never occur since switch nodes must not be visible at this
226 noway_assert(!"Switch must be lowered at this point");
231 assert(dstCount == 1);
235 case GT_SWITCH_TABLE:
236 buildInternalIntRegisterDefForNode(tree);
237 srcCount = BuildBinaryUses(tree->AsOp());
238 assert(dstCount == 0);
243 if (varTypeIsFloating(tree->TypeGet()))
245 // overflow operations aren't supported on float/double types.
246 assert(!tree->gtOverflow());
248 // No implicit conversions at this stage as the expectation is that
249 // everything is made explicit by adding casts.
250 assert(tree->gtGetOp1()->TypeGet() == tree->gtGetOp2()->TypeGet());
252 else if (tree->gtOverflow())
254 // Need a register different from target reg to check for overflow.
255 buildInternalIntRegisterDefForNode(tree);
256 if ((tree->gtFlags & GTF_UNSIGNED) == 0)
257 buildInternalIntRegisterDefForNode(tree);
258 setInternalRegsDelayFree = true;
271 if (tree->OperIs(GT_ROR, GT_ROL))
272 buildInternalIntRegisterDefForNode(tree);
273 srcCount = BuildBinaryUses(tree->AsOp());
274 buildInternalRegisterUses();
275 assert(dstCount == 1);
280 // this just turns into a compare of its child with an int
281 // + a conditional call
282 BuildUse(tree->gtGetOp1());
284 assert(dstCount == 0);
285 killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC);
286 BuildDefsWithKills(tree, 0, RBM_NONE, killMask);
290 if (tree->gtOverflow())
292 // Need a register different from target reg to check for overflow.
293 buildInternalIntRegisterDefForNode(tree);
294 if ((tree->gtFlags & GTF_UNSIGNED) == 0)
295 buildInternalIntRegisterDefForNode(tree);
296 setInternalRegsDelayFree = true;
305 srcCount = BuildBinaryUses(tree->AsOp());
307 GenTree* divisorOp = tree->gtGetOp2();
309 ExceptionSetFlags exceptions = tree->OperExceptions(compiler);
311 if (!varTypeIsFloating(tree->TypeGet()) &&
312 !((exceptions & ExceptionSetFlags::DivideByZeroException) != ExceptionSetFlags::None &&
313 (divisorOp->IsIntegralConst(0) || divisorOp->GetRegNum() == REG_ZERO)))
315 bool needTemp = false;
316 if (divisorOp->isContainedIntOrIImmed())
318 if (!emitter::isGeneralRegister(divisorOp->GetRegNum()))
322 if (!needTemp && (tree->gtOper == GT_DIV || tree->gtOper == GT_MOD))
324 if ((exceptions & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None)
329 buildInternalIntRegisterDefForNode(tree);
331 buildInternalRegisterUses();
332 assert(dstCount == 1);
339 srcCount = BuildBinaryUses(tree->AsOp());
341 emitAttr attr = emitActualTypeSize(tree->AsOp());
342 if (EA_SIZE(attr) != EA_8BYTE)
344 if ((tree->AsOp()->gtFlags & GTF_UNSIGNED) != 0)
345 buildInternalIntRegisterDefForNode(tree);
348 buildInternalRegisterUses();
349 assert(dstCount == 1);
356 noway_assert((tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Abs) ||
357 (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Ceiling) ||
358 (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Floor) ||
359 (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Round) ||
360 (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Sqrt));
362 // Both operand and its result must be of the same floating point type.
363 GenTree* op1 = tree->gtGetOp1();
364 assert(varTypeIsFloating(op1));
365 assert(op1->TypeGet() == tree->TypeGet());
369 assert(dstCount == 1);
376 srcCount = BuildSIMD(tree->AsSIMD());
378 #endif // FEATURE_SIMD
380 #ifdef FEATURE_HW_INTRINSICS
382 srcCount = BuildHWIntrinsic(tree->AsHWIntrinsic(), &dstCount);
384 #endif // FEATURE_HW_INTRINSICS
387 assert(dstCount == 1);
388 srcCount = BuildCast(tree->AsCast());
393 BuildUse(tree->gtGetOp1());
395 assert(dstCount == 1);
406 var_types op1Type = genActualType(tree->gtGetOp1()->TypeGet());
407 if (varTypeIsFloating(op1Type))
409 bool isUnordered = (tree->gtFlags & GTF_RELOP_NAN_UN) != 0;
412 if (tree->OperIs(GT_EQ))
413 buildInternalIntRegisterDefForNode(tree);
417 if (tree->OperIs(GT_NE))
418 buildInternalIntRegisterDefForNode(tree);
423 emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
424 if (tree->gtGetOp2()->isContainedIntOrIImmed())
426 bool isUnsigned = (tree->gtFlags & GTF_UNSIGNED) != 0;
427 if (cmpSize == EA_4BYTE && isUnsigned)
428 buildInternalIntRegisterDefForNode(tree);
432 if (cmpSize == EA_4BYTE)
433 buildInternalIntRegisterDefForNode(tree);
436 buildInternalRegisterUses();
441 srcCount = BuildCmp(tree);
446 assert(dstCount == 1);
447 buildInternalIntRegisterDefForNode(tree);
448 BuildUse(tree->gtGetOp1());
450 buildInternalRegisterUses();
455 GenTreeCmpXchg* cas = tree->AsCmpXchg();
456 assert(!cas->gtOpComparand->isContained());
458 assert(dstCount == 1);
460 buildInternalIntRegisterDefForNode(tree); // temp reg for store conditional error
461 // Extend lifetimes of argument regs because they may be reused during retries
462 setDelayFree(BuildUse(cas->gtOpLocation));
463 setDelayFree(BuildUse(cas->gtOpValue));
464 setDelayFree(BuildUse(cas->gtOpComparand));
466 // Internals may not collide with target
467 setInternalRegsDelayFree = true;
468 buildInternalRegisterUses();
474 assert(!"-----unimplemented on RISCV64----");
482 assert(dstCount == (tree->TypeIs(TYP_VOID) ? 0 : 1));
483 GenTree* addr = tree->gtGetOp1();
484 GenTree* data = tree->gtGetOp2();
485 assert(!addr->isContained() && !data->isContained());
497 case GT_PUTARG_SPLIT:
498 srcCount = BuildPutArgSplit(tree->AsPutArgSplit());
499 dstCount = tree->AsPutArgSplit()->gtNumRegs;
503 srcCount = BuildPutArgStk(tree->AsPutArgStk());
507 srcCount = BuildPutArgReg(tree->AsUnOp());
511 srcCount = BuildCall(tree->AsCall());
512 if (tree->AsCall()->HasMultiRegRetVal())
514 dstCount = tree->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
519 // These should all be eliminated prior to Lowering.
520 assert(!"Non-store block node in Lowering");
525 case GT_STORE_DYN_BLK:
526 srcCount = BuildBlockStore(tree->AsBlk());
530 // Always a passthrough of its child's value.
531 assert(!"INIT_VAL should always be contained");
537 assert(dstCount == 1);
539 // Need a variable number of temp regs (see genLclHeap() in codegenrisv64.cpp):
540 // Here '-' means don't care.
542 // Size? Init Memory? # temp regs
544 // const and <=UnrollLimit - 0
545 // const and <PageSize No 0
546 // >UnrollLimit Yes 0
551 bool needExtraTemp = (compiler->lvaOutgoingArgSpaceSize > 0);
553 GenTree* size = tree->gtGetOp1();
554 if (size->IsCnsIntOrI())
556 assert(size->isContained());
559 size_t sizeVal = size->AsIntCon()->gtIconVal;
563 // Compute the amount of memory to properly STACK_ALIGN.
564 // Note: The Gentree node is not updated here as it is cheap to recompute stack aligned size.
565 // This should also help in debugging as we can examine the original size specified with
567 sizeVal = AlignUp(sizeVal, STACK_ALIGN);
569 // For small allocations up to 4 'st' instructions (i.e. 16 to 64 bytes of localloc)
570 if (sizeVal <= (REGSIZE_BYTES * 2 * 4))
572 // Need no internal registers
574 else if (!compiler->info.compInitMem)
576 // No need to initialize allocated stack space.
577 if (sizeVal < compiler->eeGetPageSize())
579 ssize_t imm = -(ssize_t)sizeVal;
580 needExtraTemp |= !emitter::isValidSimm12(imm);
584 // We need two registers: regCnt and RegTmp
585 buildInternalIntRegisterDefForNode(tree);
586 buildInternalIntRegisterDefForNode(tree);
587 needExtraTemp = true;
595 if (!compiler->info.compInitMem)
597 buildInternalIntRegisterDefForNode(tree);
598 buildInternalIntRegisterDefForNode(tree);
599 needExtraTemp = true;
604 buildInternalIntRegisterDefForNode(tree); // tempReg
606 if (!size->isContained())
610 buildInternalRegisterUses();
615 case GT_BOUNDS_CHECK:
617 GenTreeBoundsChk* node = tree->AsBoundsChk();
618 if (genActualType(node->GetArrayLength()) == TYP_INT)
620 buildInternalIntRegisterDefForNode(tree);
622 if (genActualType(node->GetIndex()) == TYP_INT)
624 buildInternalIntRegisterDefForNode(tree);
626 buildInternalRegisterUses();
627 // Consumes arrLen & index - has no result
628 assert(dstCount == 0);
629 srcCount = BuildOperandUses(node->GetIndex());
630 srcCount += BuildOperandUses(node->GetArrayLength());
635 // These must have been lowered
636 noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
638 assert(dstCount == 0);
643 GenTreeAddrMode* lea = tree->AsAddrMode();
645 GenTree* base = lea->Base();
646 GenTree* index = lea->Index();
647 int cns = lea->Offset();
649 // This LEA is instantiating an address, so we set up the srcCount here.
656 if (index != nullptr)
661 assert(dstCount == 1);
663 if ((base != nullptr) && (index != nullptr))
666 BitScanForward(&scale, lea->gtScale);
668 buildInternalIntRegisterDefForNode(tree); // scaleTempReg
671 // On RISCV64 we may need a single internal register
672 // (when both conditions are true then we still only need a single internal register)
673 if ((index != nullptr) && (cns != 0))
675 // RISCV64 does not support both Index and offset so we need an internal register
676 buildInternalIntRegisterDefForNode(tree);
678 else if (!emitter::isValidSimm12(cns))
680 // This offset can't be contained in the add instruction, so we need an internal register
681 buildInternalIntRegisterDefForNode(tree);
683 buildInternalRegisterUses();
690 assert(dstCount == 0);
692 if (compiler->codeGen->gcInfo.gcIsWriteBarrierStoreIndNode(tree->AsStoreInd()))
694 srcCount = BuildGCWriteBarrier(tree);
698 srcCount = BuildIndir(tree->AsIndir());
699 if (!tree->gtGetOp2()->isContained())
701 BuildUse(tree->gtGetOp2());
709 assert(dstCount == (tree->OperIs(GT_NULLCHECK) ? 0 : 1));
710 srcCount = BuildIndir(tree->AsIndir());
715 assert(dstCount == 1);
716 BuildDef(tree, RBM_EXCEPTION_OBJECT);
720 assert(dstCount == 1);
721 srcCount = BuildBinaryUses(tree->AsOp());
722 buildInternalIntRegisterDefForNode(tree);
723 buildInternalRegisterUses();
727 } // end switch (tree->OperGet())
729 if (tree->IsUnusedValue() && (dstCount != 0))
731 isLocalDefUse = true;
733 // We need to be sure that we've set srcCount and dstCount appropriately
734 assert((dstCount < 2) || tree->IsMultiRegNode());
735 assert(isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
736 assert(!tree->IsUnusedValue() || (dstCount != 0));
737 assert(dstCount == tree->GetRegisterDstCount(compiler));
742 //------------------------------------------------------------------------
743 // BuildSIMD: Set the NodeInfo for a GT_SIMD tree.
746 // tree - The GT_SIMD node of interest
749 // The number of sources consumed by this node.
751 int LinearScan::BuildSIMD(GenTreeSIMD* simdTree)
753 NYI_RISCV64("-----unimplemented on RISCV64 yet----");
756 #endif // FEATURE_SIMD
758 #ifdef FEATURE_HW_INTRINSICS
759 #include "hwintrinsic.h"
760 //------------------------------------------------------------------------
761 // BuildHWIntrinsic: Set the NodeInfo for a GT_HWINTRINSIC tree.
764 // tree - The GT_HWINTRINSIC node of interest
767 // The number of sources consumed by this node.
769 int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
771 NYI_RISCV64("-----unimplemented on RISCV64 yet----");
776 //------------------------------------------------------------------------
777 // BuildIndir: Specify register requirements for address expression
778 // of an indirection operation.
781 // indirTree - GT_IND, GT_STOREIND or block gentree node
784 // The number of sources consumed by this node.
786 int LinearScan::BuildIndir(GenTreeIndir* indirTree)
788 // struct typed indirs are expected only on rhs of a block copy,
789 // but in this case they must be contained.
790 assert(indirTree->TypeGet() != TYP_STRUCT);
792 GenTree* addr = indirTree->Addr();
793 GenTree* index = nullptr;
796 if (addr->isContained())
798 if (addr->OperGet() == GT_LEA)
800 GenTreeAddrMode* lea = addr->AsAddrMode();
801 index = lea->Index();
804 // On RISCV64 we may need a single internal register
805 // (when both conditions are true then we still only need a single internal register)
806 if ((index != nullptr) && (cns != 0))
808 // RISCV64 does not support both Index and offset so we need an internal register
809 buildInternalIntRegisterDefForNode(indirTree);
811 else if (!emitter::isValidSimm12(cns))
813 // This offset can't be contained in the ldr/str instruction, so we need an internal register
814 buildInternalIntRegisterDefForNode(indirTree);
817 else if (addr->OperGet() == GT_CLS_VAR_ADDR)
819 // Reserve int to load constant from memory (IF_LARGELDC)
820 buildInternalIntRegisterDefForNode(indirTree);
825 if (indirTree->TypeGet() == TYP_SIMD12)
827 // If indirTree is of TYP_SIMD12, addr is not contained. See comment in LowerIndir().
828 assert(!addr->isContained());
830 // Vector3 is read/written as two reads/writes: 8 byte and 4 byte.
831 // To assemble the vector properly we would need an additional int register
832 buildInternalIntRegisterDefForNode(indirTree);
834 #endif // FEATURE_SIMD
836 int srcCount = BuildIndirUses(indirTree);
837 buildInternalRegisterUses();
839 if (!indirTree->OperIs(GT_STOREIND, GT_NULLCHECK))
846 //------------------------------------------------------------------------
847 // BuildCall: Set the NodeInfo for a call.
850 // call - The call node of interest
853 // The number of sources consumed by this node.
855 int LinearScan::BuildCall(GenTreeCall* call)
857 bool hasMultiRegRetVal = false;
858 const ReturnTypeDesc* retTypeDesc = nullptr;
859 regMaskTP dstCandidates = RBM_NONE;
863 if (call->TypeGet() != TYP_VOID)
865 hasMultiRegRetVal = call->HasMultiRegRetVal();
866 if (hasMultiRegRetVal)
868 // dst count = number of registers in which the value is returned by call
869 retTypeDesc = call->GetReturnTypeDesc();
870 dstCount = retTypeDesc->GetReturnRegCount();
878 GenTree* ctrlExpr = call->gtControlExpr;
879 regMaskTP ctrlExprCandidates = RBM_NONE;
880 if (call->gtCallType == CT_INDIRECT)
882 // either gtControlExpr != null or gtCallAddr != null.
883 // Both cannot be non-null at the same time.
884 assert(ctrlExpr == nullptr);
885 assert(call->gtCallAddr != nullptr);
886 ctrlExpr = call->gtCallAddr;
889 // set reg requirements on call target represented as control sequence.
890 if (ctrlExpr != nullptr)
892 // we should never see a gtControlExpr whose type is void.
893 assert(ctrlExpr->TypeGet() != TYP_VOID);
895 // In case of fast tail implemented as jmp, make sure that gtControlExpr is
896 // computed into a register.
897 if (call->IsFastTailCall())
899 // Fast tail call - make sure that call target is always computed in volatile registers
900 // that will not be overridden by epilog sequence.
901 ctrlExprCandidates = allRegs(TYP_INT) & RBM_INT_CALLEE_TRASH;
902 if (compiler->getNeedsGSSecurityCookie())
904 ctrlExprCandidates &= ~(genRegMask(REG_GSCOOKIE_TMP_0) | genRegMask(REG_GSCOOKIE_TMP_1));
906 assert(ctrlExprCandidates != RBM_NONE);
909 else if (call->IsR2ROrVirtualStubRelativeIndir())
911 // For R2R and VSD we have stub address in REG_R2R_INDIRECT_PARAM
912 // and will load call address into the temp register from this register.
913 regMaskTP candidates = RBM_NONE;
914 if (call->IsFastTailCall())
916 candidates = allRegs(TYP_INT) & RBM_INT_CALLEE_TRASH;
917 assert(candidates != RBM_NONE);
920 buildInternalIntRegisterDefForNode(call, candidates);
923 RegisterType registerType = call->TypeGet();
925 // Set destination candidates for return value of the call.
927 if (hasMultiRegRetVal)
929 assert(retTypeDesc != nullptr);
930 dstCandidates = retTypeDesc->GetABIReturnRegs();
932 else if (varTypeUsesFloatArgReg(registerType))
934 dstCandidates = RBM_FLOATRET;
936 else if (registerType == TYP_LONG)
938 dstCandidates = RBM_LNGRET;
942 dstCandidates = RBM_INTRET;
945 // First, count reg args
946 // Each register argument corresponds to one source.
947 bool callHasFloatRegArgs = false;
949 for (CallArg& arg : call->gtArgs.LateArgs())
951 CallArgABIInformation& abiInfo = arg.AbiInfo;
952 GenTree* argNode = arg.GetLateNode();
955 regNumber argReg = abiInfo.GetRegNum();
958 if (argNode->gtOper == GT_PUTARG_STK)
960 // late arg that is not passed in a register
961 assert(abiInfo.GetRegNum() == REG_STK);
962 // These should never be contained.
963 assert(!argNode->isContained());
967 // A GT_FIELD_LIST has a TYP_VOID, but is used to represent a multireg struct
968 if (argNode->OperGet() == GT_FIELD_LIST)
970 assert(argNode->isContained());
972 // There could be up to 2 PUTARG_REGs in the list.
973 for (GenTreeFieldList::Use& use : argNode->AsFieldList()->Uses())
976 assert(use.GetNode()->OperIs(GT_PUTARG_REG));
978 BuildUse(use.GetNode(), genRegMask(use.GetNode()->GetRegNum()));
982 else if (argNode->OperGet() == GT_PUTARG_SPLIT)
984 unsigned regCount = argNode->AsPutArgSplit()->gtNumRegs;
985 assert(regCount == abiInfo.NumRegs);
986 for (unsigned int i = 0; i < regCount; i++)
988 BuildUse(argNode, genRegMask(argNode->AsPutArgSplit()->GetRegNumByIdx(i)), i);
990 srcCount += regCount;
994 assert(argNode->OperIs(GT_PUTARG_REG));
995 assert(argNode->GetRegNum() == argReg);
996 HandleFloatVarArgs(call, argNode, &callHasFloatRegArgs);
998 BuildUse(argNode, genRegMask(argNode->GetRegNum()));
1005 // Now, count stack args
1006 // Note that these need to be computed into a register, but then
1007 // they're just stored to the stack - so the reg doesn't
1008 // need to remain live until the call. In fact, it must not
1009 // because the code generator doesn't actually consider it live,
1010 // so it can't be spilled.
1012 for (CallArg& arg : call->gtArgs.EarlyArgs())
1014 GenTree* argNode = arg.GetEarlyNode();
1016 // Skip arguments that have been moved to the Late Arg list
1017 if (arg.GetLateNode() == nullptr)
1019 // PUTARG_SPLIT nodes must be in the gtCallLateArgs list, since they
1020 // define registers used by the call.
1021 assert(argNode->OperGet() != GT_PUTARG_SPLIT);
1022 if (argNode->gtOper == GT_PUTARG_STK)
1024 assert(arg.AbiInfo.GetRegNum() == REG_STK);
1028 assert(!argNode->IsValue() || argNode->IsUnusedValue());
1034 // If it is a fast tail call, it is already preferenced to use IP0.
1035 // Therefore, no need set src candidates on call tgt again.
1036 if (call->IsVarargs() && callHasFloatRegArgs && !call->IsFastTailCall() && (ctrlExpr != nullptr))
1038 // Don't assign the call target to any of the argument registers because
1039 // we will use them to also pass floating point arguments as required
1041 ctrlExprCandidates = allRegs(TYP_INT) & ~(RBM_ARG_REGS);
1044 if (ctrlExpr != nullptr)
1046 BuildUse(ctrlExpr, ctrlExprCandidates);
1050 buildInternalRegisterUses();
1052 // Now generate defs and kills.
1053 regMaskTP killMask = getKillSetForCall(call);
1054 BuildDefsWithKills(call, dstCount, dstCandidates, killMask);
1056 // No args are placed in registers anymore.
1057 placedArgRegs = RBM_NONE;
1058 numPlacedArgLocals = 0;
1062 //------------------------------------------------------------------------
1063 // BuildPutArgStk: Set the NodeInfo for a GT_PUTARG_STK node
1066 // argNode - a GT_PUTARG_STK node
1069 // The number of sources consumed by this node.
1072 // Set the child node(s) to be contained when we have a multireg arg
1074 int LinearScan::BuildPutArgStk(GenTreePutArgStk* argNode)
1076 assert(argNode->gtOper == GT_PUTARG_STK);
1078 GenTree* src = argNode->gtGetOp1();
1082 // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct
1083 if (src->TypeIs(TYP_STRUCT))
1085 // We will use store instructions that each write a register sized value
1087 if (src->OperIs(GT_FIELD_LIST))
1089 assert(src->isContained());
1090 // We consume all of the items in the GT_FIELD_LIST
1091 for (GenTreeFieldList::Use& use : src->AsFieldList()->Uses())
1093 BuildUse(use.GetNode());
1099 // We can use a ld/st sequence so we need two internal registers for RISCV64.
1100 buildInternalIntRegisterDefForNode(argNode);
1101 buildInternalIntRegisterDefForNode(argNode);
1103 assert(src->isContained());
1105 if (src->OperGet() == GT_BLK)
1107 srcCount = BuildOperandUses(src->AsBlk()->Addr());
1111 // No source registers.
1112 assert(src->OperIs(GT_LCL_VAR, GT_LCL_FLD));
1118 assert(!src->isContained());
1119 srcCount = BuildOperandUses(src);
1121 buildInternalRegisterUses();
1125 //------------------------------------------------------------------------
1126 // BuildPutArgSplit: Set the NodeInfo for a GT_PUTARG_SPLIT node
1129 // argNode - a GT_PUTARG_SPLIT node
1132 // The number of sources consumed by this node.
1135 // Set the child node(s) to be contained
1137 int LinearScan::BuildPutArgSplit(GenTreePutArgSplit* argNode)
1140 assert(argNode->gtOper == GT_PUTARG_SPLIT);
1142 GenTree* src = argNode->gtGetOp1();
1144 // Registers for split argument corresponds to source
1145 int dstCount = argNode->gtNumRegs;
1147 regNumber argReg = argNode->GetRegNum();
1148 regMaskTP argMask = RBM_NONE;
1149 for (unsigned i = 0; i < argNode->gtNumRegs; i++)
1151 regNumber thisArgReg = (regNumber)((unsigned)argReg + i);
1152 argMask |= genRegMask(thisArgReg);
1153 argNode->SetRegNumByIdx(thisArgReg, i);
1156 if (src->OperGet() == GT_FIELD_LIST)
1159 // 1. Consume all of the items in the GT_FIELD_LIST (source)
1160 // 2. Store to target slot and move to target registers (destination) from source
1162 unsigned sourceRegCount = 0;
1164 // To avoid redundant moves, have the argument operand computed in the
1165 // register in which the argument is passed to the call.
1167 for (GenTreeFieldList::Use& use : src->AsFieldList()->Uses())
1169 GenTree* node = use.GetNode();
1170 assert(!node->isContained());
1171 // The only multi-reg nodes we should see are OperIsMultiRegOp()
1172 unsigned currentRegCount = 1;
1173 assert(!node->IsMultiRegNode());
1175 // Consume all the registers, setting the appropriate register mask for the ones that
1176 // go into registers.
1177 for (unsigned regIndex = 0; regIndex < currentRegCount; regIndex++)
1179 regMaskTP sourceMask = RBM_NONE;
1180 if (sourceRegCount < argNode->gtNumRegs)
1182 sourceMask = genRegMask((regNumber)((unsigned)argReg + sourceRegCount));
1185 BuildUse(node, sourceMask, regIndex);
1188 srcCount += sourceRegCount;
1189 assert(src->isContained());
1193 assert(src->TypeIs(TYP_STRUCT) && src->isContained());
1195 if (src->OperIs(GT_BLK))
1197 // If the PUTARG_SPLIT clobbers only one register we may need an
1198 // extra internal register in case there is a conflict between the
1199 // source address register and target register.
1200 if (argNode->gtNumRegs == 1)
1202 // We can use a ldr/str sequence so we need an internal register
1203 buildInternalIntRegisterDefForNode(argNode, allRegs(TYP_INT) & ~argMask);
1206 // We will generate code that loads from the OBJ's address, which must be in a register.
1207 srcCount = BuildOperandUses(src->AsBlk()->Addr());
1211 // We will generate all of the code for the GT_PUTARG_SPLIT and LCL_VAR/LCL_FLD as one contained operation.
1212 assert(src->OperIsLocalRead());
1215 buildInternalRegisterUses();
1216 BuildDefs(argNode, dstCount, argMask);
1220 //------------------------------------------------------------------------
1221 // BuildBlockStore: Build the RefPositions for a block store node.
1224 // blkNode - The block store node of interest
1227 // The number of sources consumed by this node.
1229 int LinearScan::BuildBlockStore(GenTreeBlk* blkNode)
1231 GenTree* dstAddr = blkNode->Addr();
1232 GenTree* src = blkNode->Data();
1233 unsigned size = blkNode->Size();
1235 GenTree* srcAddrOrFill = nullptr;
1237 regMaskTP dstAddrRegMask = RBM_NONE;
1238 regMaskTP srcRegMask = RBM_NONE;
1239 regMaskTP sizeRegMask = RBM_NONE;
1241 if (blkNode->OperIsInitBlkOp())
1243 if (src->OperIs(GT_INIT_VAL))
1245 assert(src->isContained());
1246 src = src->AsUnOp()->gtGetOp1();
1249 srcAddrOrFill = src;
1251 switch (blkNode->gtBlkOpKind)
1253 case GenTreeBlk::BlkOpKindUnroll:
1255 if (dstAddr->isContained())
1257 // Since the dstAddr is contained the address will be computed in CodeGen.
1258 // This might require an integer register to store the value.
1259 buildInternalIntRegisterDefForNode(blkNode);
1262 const bool isDstRegAddrAlignmentKnown = dstAddr->OperIs(GT_LCL_ADDR);
1264 if (isDstRegAddrAlignmentKnown && (size > FP_REGSIZE_BYTES))
1266 // TODO-RISCV64: For larger block sizes CodeGen can choose to use 16-byte SIMD instructions.
1267 // here just used a temp register.
1268 buildInternalIntRegisterDefForNode(blkNode);
1273 case GenTreeBlk::BlkOpKindHelper:
1274 assert(!src->isContained());
1275 dstAddrRegMask = RBM_ARG_0;
1276 srcRegMask = RBM_ARG_1;
1277 sizeRegMask = RBM_ARG_2;
1286 if (src->OperIs(GT_IND))
1288 assert(src->isContained());
1289 srcAddrOrFill = src->AsIndir()->Addr();
1292 switch (blkNode->gtBlkOpKind)
1294 case GenTreeBlk::BlkOpKindCpObjUnroll:
1296 // We don't need to materialize the struct size but we still need
1297 // a temporary register to perform the sequence of loads and stores.
1298 // We can't use the special Write Barrier registers, so exclude them from the mask
1299 regMaskTP internalIntCandidates =
1300 allRegs(TYP_INT) & ~(RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF);
1301 buildInternalIntRegisterDefForNode(blkNode, internalIntCandidates);
1303 if (size >= 2 * REGSIZE_BYTES)
1305 // TODO-RISCV64: We will use ld/st paired to reduce code size and improve performance
1306 // so we need to reserve an extra internal register.
1307 buildInternalIntRegisterDefForNode(blkNode, internalIntCandidates);
1310 // If we have a dest address we want it in RBM_WRITE_BARRIER_DST_BYREF.
1311 dstAddrRegMask = RBM_WRITE_BARRIER_DST_BYREF;
1313 // If we have a source address we want it in REG_WRITE_BARRIER_SRC_BYREF.
1314 // Otherwise, if it is a local, codegen will put its address in REG_WRITE_BARRIER_SRC_BYREF,
1315 // which is killed by a StoreObj (and thus needn't be reserved).
1316 if (srcAddrOrFill != nullptr)
1318 assert(!srcAddrOrFill->isContained());
1319 srcRegMask = RBM_WRITE_BARRIER_SRC_BYREF;
1324 case GenTreeBlk::BlkOpKindUnroll:
1325 buildInternalIntRegisterDefForNode(blkNode);
1328 case GenTreeBlk::BlkOpKindHelper:
1329 dstAddrRegMask = RBM_ARG_0;
1330 if (srcAddrOrFill != nullptr)
1332 assert(!srcAddrOrFill->isContained());
1333 srcRegMask = RBM_ARG_1;
1335 sizeRegMask = RBM_ARG_2;
1343 if (!blkNode->OperIs(GT_STORE_DYN_BLK) && (sizeRegMask != RBM_NONE))
1345 // Reserve a temp register for the block size argument.
1346 buildInternalIntRegisterDefForNode(blkNode, sizeRegMask);
1351 if (!dstAddr->isContained())
1354 BuildUse(dstAddr, dstAddrRegMask);
1356 else if (dstAddr->OperIsAddrMode())
1358 useCount += BuildAddrUses(dstAddr->AsAddrMode()->Base());
1361 if (srcAddrOrFill != nullptr)
1363 if (!srcAddrOrFill->isContained())
1366 BuildUse(srcAddrOrFill, srcRegMask);
1368 else if (srcAddrOrFill->OperIsAddrMode())
1370 useCount += BuildAddrUses(srcAddrOrFill->AsAddrMode()->Base());
1374 if (blkNode->OperIs(GT_STORE_DYN_BLK))
1377 BuildUse(blkNode->AsStoreDynBlk()->gtDynamicSize, sizeRegMask);
1380 buildInternalRegisterUses();
1381 regMaskTP killMask = getKillSetForBlockStore(blkNode);
1382 BuildDefsWithKills(blkNode, 0, RBM_NONE, killMask);
1386 //------------------------------------------------------------------------
1387 // BuildCast: Set the NodeInfo for a GT_CAST.
1390 // cast - The GT_CAST node
1393 // The number of sources consumed by this node.
1395 int LinearScan::BuildCast(GenTreeCast* cast)
1397 enum CodeGen::GenIntCastDesc::CheckKind kind = CodeGen::GenIntCastDesc(cast).CheckKind();
1398 if ((kind != CodeGen::GenIntCastDesc::CHECK_NONE) && (kind != CodeGen::GenIntCastDesc::CHECK_POSITIVE))
1400 buildInternalIntRegisterDefForNode(cast);
1402 buildInternalRegisterUses();
1403 int srcCount = BuildOperandUses(cast->CastOp());
1406 if (varTypeIsFloating(cast->gtOp1) && !varTypeIsFloating(cast->TypeGet()))
1408 buildInternalIntRegisterDefForNode(cast);
1409 buildInternalRegisterUses();
1415 #endif // TARGET_RISCV64