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