Merge pull request #13597 from CarolEidt/InfoLinearScan
[platform/upstream/coreclr.git] / src / jit / lsraarmarch.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX              Register Requirements for ARM and ARM64 common code          XX
9 XX                                                                           XX
10 XX  This encapsulates common logic for setting register requirements for     XX
11 XX  the ARM and ARM64 architectures.                                         XX
12 XX                                                                           XX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 */
16
17 #include "jitpch.h"
18 #ifdef _MSC_VER
19 #pragma hdrstop
20 #endif
21
22 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
23
24 #ifdef _TARGET_ARMARCH_ // This file is ONLY used for ARM and ARM64 architectures
25
26 #include "jit.h"
27 #include "sideeffects.h"
28 #include "lower.h"
29 #include "lsra.h"
30
31 //------------------------------------------------------------------------
32 // TreeNodeInfoInitStoreLoc: Set register requirements for a store of a lclVar
33 //
34 // Arguments:
35 //    storeLoc - the local store (GT_STORE_LCL_FLD or GT_STORE_LCL_VAR)
36 //
37 // Notes:
38 //    This involves:
39 //    - Setting the appropriate candidates for a store of a multi-reg call return value.
40 //    - Handling of contained immediates.
41 //
42 void LinearScan::TreeNodeInfoInitStoreLoc(GenTreeLclVarCommon* storeLoc)
43 {
44     TreeNodeInfo* info = &(storeLoc->gtLsraInfo);
45     GenTree*      op1  = storeLoc->gtGetOp1();
46
47     assert(info->dstCount == 0);
48 #ifdef _TARGET_ARM_
49     if (varTypeIsLong(op1))
50     {
51         info->srcCount = 2;
52         assert(!op1->OperIs(GT_LONG) || op1->isContained());
53     }
54     else
55 #endif // _TARGET_ARM_
56         if (op1->isContained())
57     {
58         info->srcCount = 0;
59     }
60     else if (op1->IsMultiRegCall())
61     {
62         // This is the case of var = call where call is returning
63         // a value in multiple return registers.
64         // Must be a store lclvar.
65         assert(storeLoc->OperGet() == GT_STORE_LCL_VAR);
66
67         // srcCount = number of registers in which the value is returned by call
68         GenTreeCall*    call        = op1->AsCall();
69         ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
70         info->srcCount              = retTypeDesc->GetReturnRegCount();
71
72         // Call node srcCandidates = Bitwise-OR(allregs(GetReturnRegType(i))) for all i=0..RetRegCount-1
73         regMaskTP srcCandidates = allMultiRegCallNodeRegs(call);
74         op1->gtLsraInfo.setSrcCandidates(this, srcCandidates);
75     }
76     else
77     {
78         info->srcCount = 1;
79     }
80 }
81
82 //------------------------------------------------------------------------
83 // TreeNodeInfoInitCmp: Lower a GT comparison node.
84 //
85 // Arguments:
86 //    tree - the node to lower
87 //
88 // Return Value:
89 //    None.
90 //
91 void LinearScan::TreeNodeInfoInitCmp(GenTreePtr tree)
92 {
93     TreeNodeInfo* info = &(tree->gtLsraInfo);
94
95     info->srcCount = tree->gtOp.gtOp2->isContained() ? 1 : 2;
96     if (info->isNoRegCompare)
97     {
98         info->dstCount = 0;
99     }
100     else
101     {
102         assert((info->dstCount == 1) || tree->OperIs(GT_CMP));
103     }
104 }
105
106 void LinearScan::TreeNodeInfoInitGCWriteBarrier(GenTree* tree)
107 {
108     GenTreePtr dst  = tree;
109     GenTreePtr addr = tree->gtOp.gtOp1;
110     GenTreePtr src  = tree->gtOp.gtOp2;
111
112     if (addr->OperGet() == GT_LEA)
113     {
114         // In the case where we are doing a helper assignment, if the dst
115         // is an indir through an lea, we need to actually instantiate the
116         // lea in a register
117         GenTreeAddrMode* lea = addr->AsAddrMode();
118
119         short leaSrcCount = 0;
120         if (lea->Base() != nullptr)
121         {
122             leaSrcCount++;
123         }
124         if (lea->Index() != nullptr)
125         {
126             leaSrcCount++;
127         }
128         lea->gtLsraInfo.srcCount = leaSrcCount;
129         lea->gtLsraInfo.dstCount = 1;
130     }
131
132 #if NOGC_WRITE_BARRIERS
133     NYI_ARM("NOGC_WRITE_BARRIERS");
134
135     // For the NOGC JIT Helper calls
136     //
137     // the 'addr' goes into x14 (REG_WRITE_BARRIER_DST_BYREF)
138     // the 'src'  goes into x15 (REG_WRITE_BARRIER)
139     //
140     addr->gtLsraInfo.setSrcCandidates(this, RBM_WRITE_BARRIER_DST_BYREF);
141     src->gtLsraInfo.setSrcCandidates(this, RBM_WRITE_BARRIER);
142 #else
143     // For the standard JIT Helper calls
144     // op1 goes into REG_ARG_0 and
145     // op2 goes into REG_ARG_1
146     //
147     addr->gtLsraInfo.setSrcCandidates(this, RBM_ARG_0);
148     src->gtLsraInfo.setSrcCandidates(this, RBM_ARG_1);
149 #endif // NOGC_WRITE_BARRIERS
150
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);
155 }
156
157 //------------------------------------------------------------------------
158 // TreeNodeInfoInitIndir: Specify register requirements for address expression
159 //                       of an indirection operation.
160 //
161 // Arguments:
162 //    indirTree - GT_IND, GT_STOREIND, block node or GT_NULLCHECK gentree node
163 //
164 void LinearScan::TreeNodeInfoInitIndir(GenTreeIndir* indirTree)
165 {
166     // If this is the rhs of a block copy (i.e. non-enregisterable struct),
167     // it has no register requirements.
168     if (indirTree->TypeGet() == TYP_STRUCT)
169     {
170         return;
171     }
172
173     TreeNodeInfo* info    = &(indirTree->gtLsraInfo);
174     bool          isStore = (indirTree->gtOper == GT_STOREIND);
175     info->srcCount        = GetIndirSourceCount(indirTree);
176
177     GenTree* addr  = indirTree->Addr();
178     GenTree* index = nullptr;
179     int      cns   = 0;
180
181 #ifdef _TARGET_ARM_
182     // Unaligned loads/stores for floating point values must first be loaded into integer register(s)
183     if (indirTree->gtFlags & GTF_IND_UNALIGNED)
184     {
185         var_types type = TYP_UNDEF;
186         if (indirTree->OperGet() == GT_STOREIND)
187         {
188             type = indirTree->AsStoreInd()->Data()->TypeGet();
189         }
190         else if (indirTree->OperGet() == GT_IND)
191         {
192             type = indirTree->TypeGet();
193         }
194
195         if (type == TYP_FLOAT)
196         {
197             info->internalIntCount = 1;
198         }
199         else if (type == TYP_DOUBLE)
200         {
201             info->internalIntCount = 2;
202         }
203     }
204 #endif
205
206     if (addr->isContained())
207     {
208         assert(addr->OperGet() == GT_LEA);
209         GenTreeAddrMode* lea = addr->AsAddrMode();
210         index                = lea->Index();
211         cns                  = lea->Offset();
212
213         // On ARM we may need a single internal register
214         // (when both conditions are true then we still only need a single internal register)
215         if ((index != nullptr) && (cns != 0))
216         {
217             // ARM does not support both Index and offset so we need an internal register
218             info->internalIntCount++;
219         }
220         else if (!emitter::emitIns_valid_imm_for_ldst_offset(cns, emitTypeSize(indirTree)))
221         {
222             // This offset can't be contained in the ldr/str instruction, so we need an internal register
223             info->internalIntCount++;
224         }
225     }
226 }
227
228 //------------------------------------------------------------------------
229 // TreeNodeInfoInitShiftRotate: Set the NodeInfo for a shift or rotate.
230 //
231 // Arguments:
232 //    tree      - The node of interest
233 //
234 // Return Value:
235 //    None.
236 //
237 void LinearScan::TreeNodeInfoInitShiftRotate(GenTree* tree)
238 {
239     TreeNodeInfo* info = &(tree->gtLsraInfo);
240
241     GenTreePtr shiftBy = tree->gtOp.gtOp2;
242     info->srcCount     = shiftBy->isContained() ? 1 : 2;
243     info->dstCount     = 1;
244
245 #ifdef _TARGET_ARM_
246
247     // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
248     // we can have a three operand form. Increment the srcCount.
249     GenTreePtr source = tree->gtOp.gtOp1;
250     if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
251     {
252         assert((source->OperGet() == GT_LONG) && source->isContained());
253         info->srcCount++;
254
255         if (tree->OperGet() == GT_LSH_HI)
256         {
257             GenTreePtr sourceLo              = source->gtOp.gtOp1;
258             sourceLo->gtLsraInfo.isDelayFree = true;
259         }
260         else
261         {
262             GenTreePtr sourceHi              = source->gtOp.gtOp2;
263             sourceHi->gtLsraInfo.isDelayFree = true;
264         }
265
266         source->gtLsraInfo.hasDelayFreeSrc = true;
267         info->hasDelayFreeSrc              = true;
268     }
269
270 #endif // _TARGET_ARM_
271 }
272
273 //------------------------------------------------------------------------
274 // TreeNodeInfoInitPutArgReg: Set the NodeInfo for a PUTARG_REG.
275 //
276 // Arguments:
277 //    node                - The PUTARG_REG node.
278 //    argReg              - The register in which to pass the argument.
279 //    info                - The info for the node's using call.
280 //    isVarArgs           - True if the call uses a varargs calling convention.
281 //    callHasFloatRegArgs - Set to true if this PUTARG_REG uses an FP register.
282 //
283 // Return Value:
284 //    None.
285 //
286 void LinearScan::TreeNodeInfoInitPutArgReg(GenTreeUnOp* node)
287 {
288     assert(node != nullptr);
289     assert(node->OperIsPutArgReg());
290     node->gtLsraInfo.srcCount = 1;
291     regNumber argReg          = node->gtRegNum;
292     assert(argReg != REG_NA);
293
294     // Set the register requirements for the node.
295     regMaskTP argMask = genRegMask(argReg);
296 #ifdef ARM_SOFTFP
297     // If type of node is `long` then it is actually `double`.
298     // The actual `long` types must have been transformed as a field list with two fields.
299     if (node->TypeGet() == TYP_LONG)
300     {
301         node->gtLsraInfo.srcCount++;
302         assert(genRegArgNext(argReg) == REG_NEXT(argReg));
303         argMask |= genRegMask(REG_NEXT(argReg));
304     }
305 #endif // ARM_SOFTFP
306     node->gtLsraInfo.setDstCandidates(this, argMask);
307     node->gtLsraInfo.setSrcCandidates(this, argMask);
308
309     // To avoid redundant moves, have the argument operand computed in the
310     // register in which the argument is passed to the call.
311     node->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(this, getUseCandidates(node));
312 }
313
314 //------------------------------------------------------------------------
315 // HandleFloatVarArgs: Handle additional register requirements for a varargs call
316 //
317 // Arguments:
318 //    call    - The call node of interest
319 //    argNode - The current argument
320 //
321 // Return Value:
322 //    None.
323 //
324 // Notes:
325 //    In the case of a varargs call, the ABI dictates that if we have floating point args,
326 //    we must pass the enregistered arguments in both the integer and floating point registers.
327 //    Since the integer register is not associated with the arg node, we will reserve it as
328 //    an internal register on the call so that it is not used during the evaluation of the call node
329 //    (e.g. for the target).
330 void LinearScan::HandleFloatVarArgs(GenTreeCall* call, GenTree* argNode, bool* callHasFloatRegArgs)
331 {
332 #if FEATURE_VARARG
333     if (call->IsVarargs() && varTypeIsFloating(argNode))
334     {
335         *callHasFloatRegArgs = true;
336
337         regNumber argReg    = argNode->gtRegNum;
338         regNumber targetReg = compiler->getCallArgIntRegister(argReg);
339         call->gtLsraInfo.setInternalIntCount(call->gtLsraInfo.internalIntCount + 1);
340         call->gtLsraInfo.addInternalCandidates(this, genRegMask(targetReg));
341     }
342 #endif // FEATURE_VARARG
343 }
344
345 //------------------------------------------------------------------------
346 // TreeNodeInfoInitCall: Set the NodeInfo for a call.
347 //
348 // Arguments:
349 //    call - The call node of interest
350 //
351 // Return Value:
352 //    None.
353 //
354 void LinearScan::TreeNodeInfoInitCall(GenTreeCall* call)
355 {
356     TreeNodeInfo*   info              = &(call->gtLsraInfo);
357     bool            hasMultiRegRetVal = false;
358     ReturnTypeDesc* retTypeDesc       = nullptr;
359
360     info->srcCount = 0;
361     if (call->TypeGet() != TYP_VOID)
362     {
363         hasMultiRegRetVal = call->HasMultiRegRetVal();
364         if (hasMultiRegRetVal)
365         {
366             // dst count = number of registers in which the value is returned by call
367             retTypeDesc    = call->GetReturnTypeDesc();
368             info->dstCount = retTypeDesc->GetReturnRegCount();
369         }
370         else
371         {
372             info->dstCount = 1;
373         }
374     }
375     else
376     {
377         info->dstCount = 0;
378     }
379
380     GenTree* ctrlExpr = call->gtControlExpr;
381     if (call->gtCallType == CT_INDIRECT)
382     {
383         // either gtControlExpr != null or gtCallAddr != null.
384         // Both cannot be non-null at the same time.
385         assert(ctrlExpr == nullptr);
386         assert(call->gtCallAddr != nullptr);
387         ctrlExpr = call->gtCallAddr;
388     }
389
390     // set reg requirements on call target represented as control sequence.
391     if (ctrlExpr != nullptr)
392     {
393         // we should never see a gtControlExpr whose type is void.
394         assert(ctrlExpr->TypeGet() != TYP_VOID);
395
396         info->srcCount++;
397
398         // In case of fast tail implemented as jmp, make sure that gtControlExpr is
399         // computed into a register.
400         if (call->IsFastTailCall())
401         {
402             NYI_ARM("tail call");
403
404 #ifdef _TARGET_ARM64_
405             // Fast tail call - make sure that call target is always computed in IP0
406             // so that epilog sequence can generate "br xip0" to achieve fast tail call.
407             ctrlExpr->gtLsraInfo.setSrcCandidates(this, genRegMask(REG_IP0));
408 #endif // _TARGET_ARM64_
409         }
410     }
411 #ifdef _TARGET_ARM_
412     else
413     {
414         info->internalIntCount = 1;
415     }
416 #endif // _TARGET_ARM_
417
418     RegisterType registerType = call->TypeGet();
419
420 // Set destination candidates for return value of the call.
421
422 #ifdef _TARGET_ARM_
423     if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
424     {
425         // The ARM CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
426         // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers.
427         info->setDstCandidates(this, RBM_PINVOKE_TCB);
428     }
429     else
430 #endif // _TARGET_ARM_
431         if (hasMultiRegRetVal)
432     {
433         assert(retTypeDesc != nullptr);
434         info->setDstCandidates(this, retTypeDesc->GetABIReturnRegs());
435     }
436     else if (varTypeIsFloating(registerType))
437     {
438         info->setDstCandidates(this, RBM_FLOATRET);
439     }
440     else if (registerType == TYP_LONG)
441     {
442         info->setDstCandidates(this, RBM_LNGRET);
443     }
444     else
445     {
446         info->setDstCandidates(this, RBM_INTRET);
447     }
448
449     // First, count reg args
450     // Each register argument corresponds to one source.
451     bool callHasFloatRegArgs = false;
452
453     for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
454     {
455         assert(list->OperIsList());
456
457         GenTreePtr argNode = list->Current();
458
459 #ifdef DEBUG
460         // During TreeNodeInfoInit, we only use the ArgTabEntry for validation,
461         // as getting it is rather expensive.
462         fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
463         regNumber        argReg         = curArgTabEntry->regNum;
464         assert(curArgTabEntry);
465 #endif
466
467         if (argNode->gtOper == GT_PUTARG_STK)
468         {
469             // late arg that is not passed in a register
470             assert(curArgTabEntry->regNum == REG_STK);
471             GenTree* putArgChild = argNode->gtGetOp1();
472             if (!varTypeIsStruct(putArgChild) && !putArgChild->OperIs(GT_FIELD_LIST))
473             {
474 #ifdef ARM_SOFTFP
475                 // The `double` types have been transformed to `long` on armel, while the actual longs
476                 // have been decomposed.
477                 const bool isDouble = putArgChild->TypeGet() == TYP_LONG;
478                 if (isDouble)
479                 {
480                     argNode->gtLsraInfo.srcCount = 2;
481                 }
482 #endif // ARM_SOFT_FP
483
484 #ifdef DEBUG
485 // Validate the slot count for this arg.
486 #ifdef _TARGET_ARM_
487 #ifndef ARM_SOFTFP
488                 const bool isDouble = (curArgTabEntry->numSlots == 2) && (putArgChild->TypeGet() == TYP_DOUBLE);
489 #endif // !ARM_SOFTFP
490
491                 // We must not have a multi-reg struct; double uses 2 slots and isn't a multi-reg struct
492                 assert((curArgTabEntry->numSlots == 1) || isDouble);
493
494 #else  // !_TARGET_ARM_
495                 // We must not have a multi-reg struct
496                 assert(curArgTabEntry->numSlots == 1);
497 #endif // !_TARGET_ARM_
498 #endif
499             }
500             continue;
501         }
502
503         // A GT_FIELD_LIST has a TYP_VOID, but is used to represent a multireg struct
504         if (argNode->OperGet() == GT_FIELD_LIST)
505         {
506             assert(argNode->isContained());
507
508             // There could be up to 2-4 PUTARG_REGs in the list (3 or 4 can only occur for HFAs)
509             for (GenTreeFieldList* entry = argNode->AsFieldList(); entry != nullptr; entry = entry->Rest())
510             {
511                 info->srcCount++;
512 #ifdef DEBUG
513                 assert(entry->Current()->OperIs(GT_PUTARG_REG));
514                 assert(entry->Current()->gtRegNum == argReg);
515                 // Update argReg for the next putarg_reg (if any)
516                 argReg = genRegArgNext(argReg);
517
518 #if defined(_TARGET_ARM_)
519                 // A double register is modelled as an even-numbered single one
520                 if (entry->Current()->TypeGet() == TYP_DOUBLE)
521                 {
522                     argReg = genRegArgNext(argReg);
523                 }
524 #endif // _TARGET_ARM_
525 #endif
526             }
527         }
528 #ifdef _TARGET_ARM_
529         else if (argNode->OperGet() == GT_PUTARG_SPLIT)
530         {
531             fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
532             info->srcCount += argNode->AsPutArgSplit()->gtNumRegs;
533         }
534 #endif
535         else
536         {
537             assert(argNode->OperIs(GT_PUTARG_REG));
538             assert(argNode->gtRegNum == argReg);
539             HandleFloatVarArgs(call, argNode, &callHasFloatRegArgs);
540             info->srcCount++;
541         }
542     }
543
544     // Now, count stack args
545     // Note that these need to be computed into a register, but then
546     // they're just stored to the stack - so the reg doesn't
547     // need to remain live until the call.  In fact, it must not
548     // because the code generator doesn't actually consider it live,
549     // so it can't be spilled.
550
551     GenTreePtr args = call->gtCallArgs;
552     while (args)
553     {
554         GenTreePtr arg = args->gtOp.gtOp1;
555
556         // Skip arguments that have been moved to the Late Arg list
557         if (!(args->gtFlags & GTF_LATE_ARG))
558         {
559 #ifdef DEBUG
560             fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
561             assert(curArgTabEntry);
562 #endif
563             if (arg->gtOper == GT_PUTARG_STK)
564             {
565                 assert(curArgTabEntry->regNum == REG_STK);
566             }
567 #ifdef _TARGET_ARM_
568             else if (arg->OperGet() == GT_PUTARG_SPLIT)
569             {
570                 assert(arg->AsPutArgSplit()->gtNumRegs == curArgTabEntry->numRegs);
571                 info->srcCount += arg->gtLsraInfo.dstCount;
572             }
573 #endif
574             else
575             {
576                 TreeNodeInfo* argInfo = &(arg->gtLsraInfo);
577                 assert((argInfo->dstCount == 0) || (argInfo->isLocalDefUse));
578             }
579         }
580         args = args->gtOp.gtOp2;
581     }
582
583     // If it is a fast tail call, it is already preferenced to use IP0.
584     // Therefore, no need set src candidates on call tgt again.
585     if (call->IsVarargs() && callHasFloatRegArgs && !call->IsFastTailCall() && (ctrlExpr != nullptr))
586     {
587         NYI_ARM("float reg varargs");
588
589         // Don't assign the call target to any of the argument registers because
590         // we will use them to also pass floating point arguments as required
591         // by Arm64 ABI.
592         ctrlExpr->gtLsraInfo.setSrcCandidates(this, allRegs(TYP_INT) & ~(RBM_ARG_REGS));
593     }
594
595 #ifdef _TARGET_ARM_
596
597     if (call->NeedsNullCheck())
598     {
599         info->internalIntCount++;
600     }
601
602 #endif // _TARGET_ARM_
603 }
604
605 //------------------------------------------------------------------------
606 // TreeNodeInfoInitPutArgStk: Set the NodeInfo for a GT_PUTARG_STK node
607 //
608 // Arguments:
609 //    argNode - a GT_PUTARG_STK node
610 //
611 // Return Value:
612 //    None.
613 //
614 // Notes:
615 //    Set the child node(s) to be contained when we have a multireg arg
616 //
617 void LinearScan::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode)
618 {
619     assert(argNode->gtOper == GT_PUTARG_STK);
620
621     GenTreePtr putArgChild = argNode->gtOp.gtOp1;
622
623     argNode->gtLsraInfo.srcCount = 0;
624     argNode->gtLsraInfo.dstCount = 0;
625
626     // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct
627     if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_FIELD_LIST))
628     {
629         // We will use store instructions that each write a register sized value
630
631         if (putArgChild->OperGet() == GT_FIELD_LIST)
632         {
633             assert(putArgChild->isContained());
634             // We consume all of the items in the GT_FIELD_LIST
635             for (GenTreeFieldList* current = putArgChild->AsFieldList(); current != nullptr; current = current->Rest())
636             {
637                 argNode->gtLsraInfo.srcCount++;
638             }
639         }
640         else
641         {
642 #ifdef _TARGET_ARM64_
643             // We could use a ldp/stp sequence so we need two internal registers
644             argNode->gtLsraInfo.internalIntCount = 2;
645 #else  // _TARGET_ARM_
646             // We could use a ldr/str sequence so we need a internal register
647             argNode->gtLsraInfo.internalIntCount = 1;
648 #endif // _TARGET_ARM_
649
650             if (putArgChild->OperGet() == GT_OBJ)
651             {
652                 GenTreePtr objChild = putArgChild->gtOp.gtOp1;
653                 if (objChild->OperGet() == GT_LCL_VAR_ADDR)
654                 {
655                     // We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR
656                     // as one contained operation
657                     //
658                     assert(objChild->isContained());
659                 }
660             }
661
662             // We will generate all of the code for the GT_PUTARG_STK and its child node
663             // as one contained operation
664             //
665             argNode->gtLsraInfo.srcCount = putArgChild->gtLsraInfo.srcCount;
666             assert(putArgChild->isContained());
667         }
668     }
669     else
670     {
671 #if defined(_TARGET_ARM_) && defined(ARM_SOFTFP)
672         // The `double` types have been transformed to `long` on armel,
673         // while the actual long types have been decomposed.
674         const bool isDouble = (putArgChild->TypeGet() == TYP_LONG);
675         if (isDouble)
676         {
677             argNode->gtLsraInfo.srcCount = 2;
678         }
679         else
680 #endif // defined(_TARGET_ARM_) && defined(ARM_SOFTFP)
681         {
682             argNode->gtLsraInfo.srcCount = 1;
683         }
684     }
685 }
686
687 #ifdef _TARGET_ARM_
688 //------------------------------------------------------------------------
689 // TreeNodeInfoInitPutArgSplit: Set the NodeInfo for a GT_PUTARG_SPLIT node
690 //
691 // Arguments:
692 //    argNode - a GT_PUTARG_SPLIT node
693 //
694 // Return Value:
695 //    None.
696 //
697 // Notes:
698 //    Set the child node(s) to be contained
699 //
700 void LinearScan::TreeNodeInfoInitPutArgSplit(GenTreePutArgSplit* argNode)
701 {
702     assert(argNode->gtOper == GT_PUTARG_SPLIT);
703
704     GenTreePtr putArgChild = argNode->gtOp.gtOp1;
705
706     // Registers for split argument corresponds to source
707     argNode->gtLsraInfo.dstCount = argNode->gtNumRegs;
708
709     regNumber argReg  = argNode->gtRegNum;
710     regMaskTP argMask = RBM_NONE;
711     for (unsigned i = 0; i < argNode->gtNumRegs; i++)
712     {
713         argMask |= genRegMask((regNumber)((unsigned)argReg + i));
714     }
715     argNode->gtLsraInfo.setDstCandidates(this, argMask);
716     argNode->gtLsraInfo.setSrcCandidates(this, argMask);
717
718     if (putArgChild->OperGet() == GT_FIELD_LIST)
719     {
720         // Generated code:
721         // 1. Consume all of the items in the GT_FIELD_LIST (source)
722         // 2. Store to target slot and move to target registers (destination) from source
723         //
724         unsigned slotCount = 0;
725
726         // To avoid redundant moves, have the argument operand computed in the
727         // register in which the argument is passed to the call.
728         GenTreeFieldList* fieldListPtr = putArgChild->AsFieldList();
729         for (unsigned idx = 0; fieldListPtr != nullptr; fieldListPtr = fieldListPtr->Rest(), idx++)
730         {
731             if (idx < argNode->gtNumRegs)
732             {
733                 GenTreePtr node = fieldListPtr->gtGetOp1();
734                 node->gtLsraInfo.setSrcCandidates(this, genRegMask((regNumber)((unsigned)argReg + idx)));
735             }
736             else
737             {
738                 slotCount++;
739             }
740         }
741         argNode->gtLsraInfo.srcCount = argNode->gtNumRegs + slotCount;
742         assert(putArgChild->isContained());
743     }
744     else
745     {
746         assert(putArgChild->TypeGet() == TYP_STRUCT);
747         assert(putArgChild->OperGet() == GT_OBJ);
748
749         // We can use a ldr/str sequence so we need an internal register
750         argNode->gtLsraInfo.internalIntCount = 1;
751         regMaskTP internalMask               = RBM_ALLINT & ~argMask;
752         argNode->gtLsraInfo.setInternalCandidates(this, internalMask);
753
754         GenTreePtr objChild = putArgChild->gtOp.gtOp1;
755         if (objChild->OperGet() == GT_LCL_VAR_ADDR)
756         {
757             // We will generate all of the code for the GT_PUTARG_SPLIT, the GT_OBJ and the GT_LCL_VAR_ADDR
758             // as one contained operation
759             //
760             assert(objChild->isContained());
761         }
762         else
763         {
764             argNode->gtLsraInfo.srcCount = GetIndirSourceCount(putArgChild->AsIndir());
765         }
766         assert(putArgChild->isContained());
767     }
768 }
769 #endif // _TARGET_ARM_
770
771 //------------------------------------------------------------------------
772 // TreeNodeInfoInitBlockStore: Set the NodeInfo for a block store.
773 //
774 // Arguments:
775 //    blkNode       - The block store node of interest
776 //
777 // Return Value:
778 //    None.
779 //
780 void LinearScan::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
781 {
782     GenTree* dstAddr = blkNode->Addr();
783     unsigned size    = blkNode->gtBlkSize;
784     GenTree* source  = blkNode->Data();
785
786     // Sources are dest address and initVal or source.
787     // We may require an additional source or temp register for the size.
788     blkNode->gtLsraInfo.srcCount = GetOperandSourceCount(dstAddr);
789     assert(blkNode->gtLsraInfo.dstCount == 0);
790     GenTreePtr srcAddrOrFill = nullptr;
791     bool       isInitBlk     = blkNode->OperIsInitBlkOp();
792
793     if (isInitBlk)
794     {
795         GenTreePtr initVal = source;
796         if (initVal->OperIsInitVal())
797         {
798             assert(initVal->isContained());
799             initVal = initVal->gtGetOp1();
800         }
801         srcAddrOrFill = initVal;
802
803         if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
804         {
805             // TODO-ARM-CQ: Currently we generate a helper call for every
806             // initblk we encounter.  Later on we should implement loop unrolling
807             // code sequences to improve CQ.
808             // For reference see the code in lsraxarch.cpp.
809             NYI_ARM("initblk loop unrolling is currently not implemented.");
810             if (!initVal->isContained())
811             {
812                 blkNode->gtLsraInfo.srcCount++;
813             }
814         }
815         else
816         {
817             assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
818             // The helper follows the regular ABI.
819             dstAddr->gtLsraInfo.setSrcCandidates(this, RBM_ARG_0);
820             assert(!initVal->isContained());
821             blkNode->gtLsraInfo.srcCount++;
822             initVal->gtLsraInfo.setSrcCandidates(this, RBM_ARG_1);
823             if (size != 0)
824             {
825                 // Reserve a temp register for the block size argument.
826                 blkNode->gtLsraInfo.setInternalCandidates(this, RBM_ARG_2);
827                 blkNode->gtLsraInfo.internalIntCount = 1;
828             }
829             else
830             {
831                 // The block size argument is a third argument to GT_STORE_DYN_BLK
832                 noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
833                 blkNode->gtLsraInfo.setSrcCount(3);
834                 GenTree* sizeNode = blkNode->AsDynBlk()->gtDynamicSize;
835                 sizeNode->gtLsraInfo.setSrcCandidates(this, RBM_ARG_2);
836             }
837         }
838     }
839     else
840     {
841         // CopyObj or CopyBlk
842         // Sources are src and dest and size if not constant.
843         if (source->gtOper == GT_IND)
844         {
845             srcAddrOrFill = blkNode->Data()->gtGetOp1();
846         }
847         if (blkNode->OperGet() == GT_STORE_OBJ)
848         {
849             // CopyObj
850             // We don't need to materialize the struct size but we still need
851             // a temporary register to perform the sequence of loads and stores.
852             blkNode->gtLsraInfo.internalIntCount = 1;
853
854             if (size >= 2 * REGSIZE_BYTES)
855             {
856                 // We will use ldp/stp to reduce code size and improve performance
857                 // so we need to reserve an extra internal register
858                 blkNode->gtLsraInfo.internalIntCount++;
859             }
860
861             // We can't use the special Write Barrier registers, so exclude them from the mask
862             regMaskTP internalIntCandidates = RBM_ALLINT & ~(RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF);
863             blkNode->gtLsraInfo.setInternalCandidates(this, internalIntCandidates);
864
865             // If we have a dest address we want it in RBM_WRITE_BARRIER_DST_BYREF.
866             dstAddr->gtLsraInfo.setSrcCandidates(this, RBM_WRITE_BARRIER_DST_BYREF);
867
868             // If we have a source address we want it in REG_WRITE_BARRIER_SRC_BYREF.
869             // Otherwise, if it is a local, codegen will put its address in REG_WRITE_BARRIER_SRC_BYREF,
870             // which is killed by a StoreObj (and thus needn't be reserved).
871             if (srcAddrOrFill != nullptr)
872             {
873                 srcAddrOrFill->gtLsraInfo.setSrcCandidates(this, RBM_WRITE_BARRIER_SRC_BYREF);
874             }
875         }
876         else
877         {
878             // CopyBlk
879             short     internalIntCount      = 0;
880             regMaskTP internalIntCandidates = RBM_NONE;
881
882             if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
883             {
884                 // TODO-ARM-CQ: cpblk loop unrolling is currently not implemented.
885                 // In case of a CpBlk with a constant size and less than CPBLK_UNROLL_LIMIT size
886                 // we should unroll the loop to improve CQ.
887                 // For reference see the code in lsraxarch.cpp.
888                 NYI_ARM("cpblk loop unrolling is currently not implemented.");
889
890 #ifdef _TARGET_ARM64_
891
892                 internalIntCount      = 1;
893                 internalIntCandidates = RBM_ALLINT;
894
895                 if (size >= 2 * REGSIZE_BYTES)
896                 {
897                     // We will use ldp/stp to reduce code size and improve performance
898                     // so we need to reserve an extra internal register
899                     internalIntCount++;
900                 }
901
902 #endif // _TARGET_ARM64_
903             }
904             else
905             {
906                 assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
907                 dstAddr->gtLsraInfo.setSrcCandidates(this, RBM_ARG_0);
908                 // The srcAddr goes in arg1.
909                 if (srcAddrOrFill != nullptr)
910                 {
911                     srcAddrOrFill->gtLsraInfo.setSrcCandidates(this, RBM_ARG_1);
912                 }
913                 if (size != 0)
914                 {
915                     // Reserve a temp register for the block size argument.
916                     internalIntCandidates |= RBM_ARG_2;
917                     internalIntCount++;
918                 }
919                 else
920                 {
921                     // The block size argument is a third argument to GT_STORE_DYN_BLK
922                     assert(blkNode->gtOper == GT_STORE_DYN_BLK);
923                     blkNode->gtLsraInfo.srcCount++;
924                     GenTree* blockSize = blkNode->AsDynBlk()->gtDynamicSize;
925                     blockSize->gtLsraInfo.setSrcCandidates(this, RBM_ARG_2);
926                 }
927             }
928             if (internalIntCount != 0)
929             {
930                 blkNode->gtLsraInfo.internalIntCount = internalIntCount;
931                 blkNode->gtLsraInfo.setInternalCandidates(this, internalIntCandidates);
932             }
933         }
934         blkNode->gtLsraInfo.srcCount += GetOperandSourceCount(source);
935     }
936 }
937
938 //------------------------------------------------------------------------
939 // GetOperandSourceCount: Get the source registers for an operand that might be contained.
940 //
941 // Arguments:
942 //    node      - The node of interest
943 //
944 // Return Value:
945 //    The number of source registers used by the *parent* of this node.
946 //
947 int LinearScan::GetOperandSourceCount(GenTree* node)
948 {
949     if (!node->isContained())
950     {
951         return 1;
952     }
953
954 #if !defined(_TARGET_64BIT_)
955     if (node->OperIs(GT_LONG))
956     {
957         return 2;
958     }
959 #endif // !defined(_TARGET_64BIT_)
960
961     if (node->OperIsIndir())
962     {
963         const unsigned srcCount = GetIndirSourceCount(node->AsIndir());
964         return srcCount;
965     }
966
967     return 0;
968 }
969
970 #endif // _TARGET_ARMARCH_
971
972 #endif // !LEGACY_BACKEND