Merge pull request #10609 from alpencolt/ryu-arm-locallock
[platform/upstream/coreclr.git] / src / jit / lsraarm.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                         XX
9 XX                                                                           XX
10 XX  This encapsulates all the logic for setting register requirements for    XX
11 XX  the ARM  architecture.                                                   XX
12 XX                                                                           XX
13 XX                                                                           XX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
16 */
17
18 #include "jitpch.h"
19 #ifdef _MSC_VER
20 #pragma hdrstop
21 #endif
22
23 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
24
25 #ifdef _TARGET_ARM_
26
27 #include "jit.h"
28 #include "sideeffects.h"
29 #include "lower.h"
30 #include "lsra.h"
31
32 //------------------------------------------------------------------------
33 // TreeNodeInfoInitStoreLoc: Lower a store of a lclVar
34 //
35 // Arguments:
36 //    storeLoc - the local store (GT_STORE_LCL_FLD or GT_STORE_LCL_VAR)
37 //
38 // Notes:
39 //    This involves:
40 //    - Setting the appropriate candidates for a store of a multi-reg call return value.
41 //    - Handling of contained immediates and widening operations of unsigneds.
42 //
43 void Lowering::TreeNodeInfoInitStoreLoc(GenTreeLclVarCommon* storeLoc)
44 {
45     TreeNodeInfo* info = &(storeLoc->gtLsraInfo);
46
47     // Is this the case of var = call where call is returning
48     // a value in multiple return registers?
49     GenTree* op1 = storeLoc->gtGetOp1();
50     if (op1->IsMultiRegCall())
51     {
52         // backend expects to see this case only for store lclvar.
53         assert(storeLoc->OperGet() == GT_STORE_LCL_VAR);
54
55         // srcCount = number of registers in which the value is returned by call
56         GenTreeCall*    call        = op1->AsCall();
57         ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
58         info->srcCount              = retTypeDesc->GetReturnRegCount();
59
60         // Call node srcCandidates = Bitwise-OR(allregs(GetReturnRegType(i))) for all i=0..RetRegCount-1
61         regMaskTP srcCandidates = m_lsra->allMultiRegCallNodeRegs(call);
62         op1->gtLsraInfo.setSrcCandidates(m_lsra, srcCandidates);
63         return;
64     }
65
66     CheckImmedAndMakeContained(storeLoc, op1);
67 }
68
69 //------------------------------------------------------------------------
70 // TreeNodeInfoInitCmp: Lower a GT comparison node.
71 //
72 // Arguments:
73 //    tree - the node to lower
74 //
75 // Return Value:
76 //    None.
77 //
78 void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
79 {
80     TreeNodeInfo* info = &(tree->gtLsraInfo);
81
82     info->srcCount = 2;
83     info->dstCount = 1;
84
85     GenTreePtr op1     = tree->gtOp.gtOp1;
86     GenTreePtr op2     = tree->gtOp.gtOp2;
87     var_types  op1Type = op1->TypeGet();
88     var_types  op2Type = op2->TypeGet();
89
90     // Long compares will consume GT_LONG nodes, each of which produces two results.
91     // Thus for each long operand there will be an additional source.
92     // TODO-ARM-CQ: Mark hiOp2 and loOp2 as contained if it is a constant.
93     if (varTypeIsLong(op1Type))
94     {
95         info->srcCount++;
96     }
97     if (varTypeIsLong(op2Type))
98     {
99         info->srcCount++;
100     }
101
102     CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
103 }
104
105 //------------------------------------------------------------------------
106 // TreeNodeInfoInitGCWriteBarrier: GC lowering helper.
107 //
108 // Arguments:
109 //    tree - the node to lower
110 //
111 // Return Value:
112 //    None.
113 //
114 void Lowering::TreeNodeInfoInitGCWriteBarrier(GenTree* tree)
115 {
116     GenTreePtr dst  = tree;
117     GenTreePtr addr = tree->gtOp.gtOp1;
118     GenTreePtr src  = tree->gtOp.gtOp2;
119
120     if (addr->OperGet() == GT_LEA)
121     {
122         // In the case where we are doing a helper assignment, if the dst
123         // is an indir through an lea, we need to actually instantiate the
124         // lea in a register
125         GenTreeAddrMode* lea = addr->AsAddrMode();
126
127         short leaSrcCount = 0;
128         if (lea->Base() != nullptr)
129         {
130             leaSrcCount++;
131         }
132         if (lea->Index() != nullptr)
133         {
134             leaSrcCount++;
135         }
136         lea->gtLsraInfo.srcCount = leaSrcCount;
137         lea->gtLsraInfo.dstCount = 1;
138     }
139
140 #if NOGC_WRITE_BARRIERS
141     NYI_ARM("NOGC_WRITE_BARRIERS");
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(m_lsra, RBM_ARG_0);
148     src->gtLsraInfo.setSrcCandidates(m_lsra, 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 Lowering::TreeNodeInfoInitIndir(GenTreePtr indirTree)
165 {
166     assert(indirTree->OperIsIndir());
167     // If this is the rhs of a block copy (i.e. non-enregisterable struct),
168     // it has no register requirements.
169     if (indirTree->TypeGet() == TYP_STRUCT)
170     {
171         return;
172     }
173
174     GenTreePtr    addr = indirTree->gtGetOp1();
175     TreeNodeInfo* info = &(indirTree->gtLsraInfo);
176
177     GenTreePtr base  = nullptr;
178     GenTreePtr index = nullptr;
179     unsigned   cns   = 0;
180     unsigned   mul;
181     bool       rev;
182     bool       modifiedSources = false;
183
184     if ((addr->OperGet() == GT_LEA) && IsSafeToContainMem(indirTree, addr))
185     {
186         GenTreeAddrMode* lea = addr->AsAddrMode();
187         base                 = lea->Base();
188         index                = lea->Index();
189         cns                  = lea->gtOffset;
190
191         m_lsra->clearOperandCounts(addr);
192         // The srcCount is decremented because addr is now "contained",
193         // then we account for the base and index below, if they are non-null.
194         info->srcCount--;
195     }
196     else if (comp->codeGen->genCreateAddrMode(addr, -1, true, 0, &rev, &base, &index, &mul, &cns, true /*nogen*/) &&
197              !(modifiedSources = AreSourcesPossiblyModifiedLocals(indirTree, base, index)))
198     {
199         // An addressing mode will be constructed that may cause some
200         // nodes to not need a register, and cause others' lifetimes to be extended
201         // to the GT_IND or even its parent if it's an assignment
202
203         assert(base != addr);
204         m_lsra->clearOperandCounts(addr);
205
206         GenTreePtr arrLength = nullptr;
207
208         // Traverse the computation below GT_IND to find the operands
209         // for the addressing mode, marking the various constants and
210         // intermediate results as not consuming/producing.
211         // If the traversal were more complex, we might consider using
212         // a traversal function, but the addressing mode is only made
213         // up of simple arithmetic operators, and the code generator
214         // only traverses one leg of each node.
215
216         bool       foundBase  = (base == nullptr);
217         bool       foundIndex = (index == nullptr);
218         GenTreePtr nextChild  = nullptr;
219         for (GenTreePtr child = addr; child != nullptr && !child->OperIsLeaf(); child = nextChild)
220         {
221             nextChild      = nullptr;
222             GenTreePtr op1 = child->gtOp.gtOp1;
223             GenTreePtr op2 = (child->OperIsBinary()) ? child->gtOp.gtOp2 : nullptr;
224
225             if (op1 == base)
226             {
227                 foundBase = true;
228             }
229             else if (op1 == index)
230             {
231                 foundIndex = true;
232             }
233             else
234             {
235                 m_lsra->clearOperandCounts(op1);
236                 if (!op1->OperIsLeaf())
237                 {
238                     nextChild = op1;
239                 }
240             }
241
242             if (op2 != nullptr)
243             {
244                 if (op2 == base)
245                 {
246                     foundBase = true;
247                 }
248                 else if (op2 == index)
249                 {
250                     foundIndex = true;
251                 }
252                 else
253                 {
254                     m_lsra->clearOperandCounts(op2);
255                     if (!op2->OperIsLeaf())
256                     {
257                         assert(nextChild == nullptr);
258                         nextChild = op2;
259                     }
260                 }
261             }
262         }
263         assert(foundBase && foundIndex);
264         info->srcCount--; // it gets incremented below.
265     }
266     else if (addr->gtOper == GT_ARR_ELEM)
267     {
268         // The GT_ARR_ELEM consumes all the indices and produces the offset.
269         // The array object lives until the mem access.
270         // We also consume the target register to which the address is
271         // computed
272
273         info->srcCount++;
274         assert(addr->gtLsraInfo.srcCount >= 2);
275         addr->gtLsraInfo.srcCount -= 1;
276     }
277     else
278     {
279         // it is nothing but a plain indir
280         info->srcCount--; // base gets added in below
281         base = addr;
282     }
283
284     if (base != nullptr)
285     {
286         info->srcCount++;
287     }
288
289     if (index != nullptr && !modifiedSources)
290     {
291         info->srcCount++;
292         info->internalIntCount++;
293     }
294 }
295
296 //------------------------------------------------------------------------
297 // TreeNodeInfoInitReturn: Set the NodeInfo for a GT_RETURN.
298 //
299 // Arguments:
300 //    tree - The node of interest
301 //
302 // Return Value:
303 //    None.
304 //
305 void Lowering::TreeNodeInfoInitReturn(GenTree* tree)
306 {
307     TreeNodeInfo* info     = &(tree->gtLsraInfo);
308     LinearScan*   l        = m_lsra;
309     Compiler*     compiler = comp;
310
311     if (tree->TypeGet() == TYP_LONG)
312     {
313         GenTree* op1 = tree->gtGetOp1();
314         noway_assert(op1->OperGet() == GT_LONG);
315         GenTree* loVal = op1->gtGetOp1();
316         GenTree* hiVal = op1->gtGetOp2();
317         info->srcCount = 2;
318         loVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_LO);
319         hiVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_HI);
320         info->dstCount = 0;
321     }
322     else
323     {
324         GenTree*  op1           = tree->gtGetOp1();
325         regMaskTP useCandidates = RBM_NONE;
326
327         info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
328         info->dstCount = 0;
329
330         if (varTypeIsStruct(tree))
331         {
332             // op1 has to be either an lclvar or a multi-reg returning call
333             if (op1->OperGet() == GT_LCL_VAR)
334             {
335                 GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon();
336                 LclVarDsc*           varDsc       = &(compiler->lvaTable[lclVarCommon->gtLclNum]);
337                 assert(varDsc->lvIsMultiRegRet);
338
339                 // Mark var as contained if not enregistrable.
340                 if (!varTypeIsEnregisterableStruct(op1))
341                 {
342                     MakeSrcContained(tree, op1);
343                 }
344             }
345             else
346             {
347                 noway_assert(op1->IsMultiRegCall());
348
349                 ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc();
350                 info->srcCount              = retTypeDesc->GetReturnRegCount();
351                 useCandidates               = retTypeDesc->GetABIReturnRegs();
352             }
353         }
354         else
355         {
356             // Non-struct type return - determine useCandidates
357             switch (tree->TypeGet())
358             {
359                 case TYP_VOID:
360                     useCandidates = RBM_NONE;
361                     break;
362                 case TYP_FLOAT:
363                     useCandidates = RBM_FLOATRET;
364                     break;
365                 case TYP_DOUBLE:
366                     useCandidates = RBM_DOUBLERET;
367                     break;
368                 case TYP_LONG:
369                     useCandidates = RBM_LNGRET;
370                     break;
371                 default:
372                     useCandidates = RBM_INTRET;
373                     break;
374             }
375         }
376
377         if (useCandidates != RBM_NONE)
378         {
379             tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, useCandidates);
380         }
381     }
382 }
383
384 //------------------------------------------------------------------------
385 // TreeNodeInfoInitShiftRotate: Set the NodeInfo for a shift or rotate.
386 //
387 // Arguments:
388 //    tree      - The node of interest
389 //
390 // Return Value:
391 //    None.
392 //
393 void Lowering::TreeNodeInfoInitShiftRotate(GenTree* tree)
394 {
395     TreeNodeInfo* info = &(tree->gtLsraInfo);
396     LinearScan*   l    = m_lsra;
397
398     info->srcCount = 2;
399     info->dstCount = 1;
400
401     GenTreePtr shiftBy = tree->gtOp.gtOp2;
402     GenTreePtr source  = tree->gtOp.gtOp1;
403     if (shiftBy->IsCnsIntOrI())
404     {
405         l->clearDstCount(shiftBy);
406         info->srcCount--;
407     }
408
409     // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
410     // we can have a three operand form. Increment the srcCount.
411     if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
412     {
413         assert(source->OperGet() == GT_LONG);
414
415         info->srcCount++;
416
417         if (tree->OperGet() == GT_LSH_HI)
418         {
419             GenTreePtr sourceLo              = source->gtOp.gtOp1;
420             sourceLo->gtLsraInfo.isDelayFree = true;
421         }
422         else
423         {
424             GenTreePtr sourceHi              = source->gtOp.gtOp2;
425             sourceHi->gtLsraInfo.isDelayFree = true;
426         }
427
428         source->gtLsraInfo.hasDelayFreeSrc = true;
429         info->hasDelayFreeSrc              = true;
430     }
431 }
432
433 //------------------------------------------------------------------------
434 // TreeNodeInfoInitPutArgReg: Set the NodeInfo for a PUTARG_REG.
435 //
436 // Arguments:
437 //    node                - The PUTARG_REG node.
438 //    argReg              - The register in which to pass the argument.
439 //    info                - The info for the node's using call.
440 //    isVarArgs           - True if the call uses a varargs calling convention.
441 //    callHasFloatRegArgs - Set to true if this PUTARG_REG uses an FP register.
442 //
443 // Return Value:
444 //    None.
445 //
446 void Lowering::TreeNodeInfoInitPutArgReg(
447     GenTreeUnOp* node, regNumber argReg, TreeNodeInfo& info, bool isVarArgs, bool* callHasFloatRegArgs)
448 {
449     assert(node != nullptr);
450     assert(node->OperIsPutArgReg());
451     assert(argReg != REG_NA);
452
453     // Each register argument corresponds to one source.
454     info.srcCount++;
455
456     // Set the register requirements for the node.
457     const regMaskTP argMask = genRegMask(argReg);
458     node->gtLsraInfo.setDstCandidates(m_lsra, argMask);
459     node->gtLsraInfo.setSrcCandidates(m_lsra, argMask);
460
461     // To avoid redundant moves, have the argument operand computed in the
462     // register in which the argument is passed to the call.
463     node->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(m_lsra, m_lsra->getUseCandidates(node));
464
465     *callHasFloatRegArgs |= varTypeIsFloating(node->TypeGet());
466 }
467
468 //------------------------------------------------------------------------
469 // TreeNodeInfoInitCall: Set the NodeInfo for a call.
470 //
471 // Arguments:
472 //    call - The call node of interest
473 //
474 // Return Value:
475 //    None.
476 //
477 void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
478 {
479     TreeNodeInfo*   info              = &(call->gtLsraInfo);
480     LinearScan*     l                 = m_lsra;
481     Compiler*       compiler          = comp;
482     bool            hasMultiRegRetVal = false;
483     ReturnTypeDesc* retTypeDesc       = nullptr;
484
485     info->srcCount = 0;
486     if (call->TypeGet() != TYP_VOID)
487     {
488         hasMultiRegRetVal = call->HasMultiRegRetVal();
489         if (hasMultiRegRetVal)
490         {
491             // dst count = number of registers in which the value is returned by call
492             retTypeDesc    = call->GetReturnTypeDesc();
493             info->dstCount = retTypeDesc->GetReturnRegCount();
494         }
495         else
496         {
497             info->dstCount = 1;
498         }
499     }
500     else
501     {
502         info->dstCount = 0;
503     }
504
505     GenTree* ctrlExpr = call->gtControlExpr;
506     if (call->gtCallType == CT_INDIRECT)
507     {
508         // either gtControlExpr != null or gtCallAddr != null.
509         // Both cannot be non-null at the same time.
510         assert(ctrlExpr == nullptr);
511         assert(call->gtCallAddr != nullptr);
512         ctrlExpr = call->gtCallAddr;
513     }
514
515     // set reg requirements on call target represented as control sequence.
516     if (ctrlExpr != nullptr)
517     {
518         // we should never see a gtControlExpr whose type is void.
519         assert(ctrlExpr->TypeGet() != TYP_VOID);
520
521         info->srcCount++;
522         // In case of fast tail implemented as jmp, make sure that gtControlExpr is
523         // computed into a register.
524         if (call->IsFastTailCall())
525         {
526             NYI_ARM("tail call");
527         }
528     }
529     else
530     {
531         info->internalIntCount = 1;
532     }
533
534     RegisterType registerType = call->TypeGet();
535
536     // Set destination candidates for return value of the call.
537     if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
538     {
539         // The ARM CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
540         // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers.
541         info->setDstCandidates(l, RBM_PINVOKE_TCB);
542     }
543     else if (hasMultiRegRetVal)
544     {
545         assert(retTypeDesc != nullptr);
546         info->setDstCandidates(l, retTypeDesc->GetABIReturnRegs());
547     }
548     else if (varTypeIsFloating(registerType))
549     {
550         info->setDstCandidates(l, RBM_FLOATRET);
551     }
552     else if (registerType == TYP_LONG)
553     {
554         info->setDstCandidates(l, RBM_LNGRET);
555     }
556     else
557     {
558         info->setDstCandidates(l, RBM_INTRET);
559     }
560
561     // If there is an explicit this pointer, we don't want that node to produce anything
562     // as it is redundant
563     if (call->gtCallObjp != nullptr)
564     {
565         GenTreePtr thisPtrNode = call->gtCallObjp;
566
567         if (thisPtrNode->gtOper == GT_PUTARG_REG)
568         {
569             l->clearOperandCounts(thisPtrNode);
570             l->clearDstCount(thisPtrNode->gtOp.gtOp1);
571         }
572         else
573         {
574             l->clearDstCount(thisPtrNode);
575         }
576     }
577
578     // First, count reg args
579     bool callHasFloatRegArgs = false;
580
581     for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
582     {
583         assert(list->OperIsList());
584
585         GenTreePtr argNode = list->Current();
586
587         fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
588         assert(curArgTabEntry);
589
590         if (curArgTabEntry->regNum == REG_STK)
591         {
592             // late arg that is not passed in a register
593             assert(argNode->gtOper == GT_PUTARG_STK);
594
595             TreeNodeInfoInitPutArgStk(argNode->AsPutArgStk(), curArgTabEntry);
596             continue;
597         }
598
599         // A GT_FIELD_LIST has a TYP_VOID, but is used to represent a multireg struct
600         if (argNode->OperGet() == GT_FIELD_LIST)
601         {
602             // There could be up to 2-4 PUTARG_REGs in the list (3 or 4 can only occur for HFAs)
603             regNumber argReg = curArgTabEntry->regNum;
604             for (GenTreeFieldList* entry = argNode->AsFieldList(); entry != nullptr; entry = entry->Rest())
605             {
606                 TreeNodeInfoInitPutArgReg(entry->Current()->AsUnOp(), argReg, *info, false, &callHasFloatRegArgs);
607
608                 // Update argReg for the next putarg_reg (if any)
609                 argReg = genRegArgNext(argReg);
610             }
611         }
612         else
613         {
614             TreeNodeInfoInitPutArgReg(argNode->AsUnOp(), curArgTabEntry->regNum, *info, false, &callHasFloatRegArgs);
615         }
616     }
617
618     // Now, count stack args
619     // Note that these need to be computed into a register, but then
620     // they're just stored to the stack - so the reg doesn't
621     // need to remain live until the call.  In fact, it must not
622     // because the code generator doesn't actually consider it live,
623     // so it can't be spilled.
624
625     GenTreePtr args = call->gtCallArgs;
626     while (args)
627     {
628         GenTreePtr arg = args->gtOp.gtOp1;
629
630         // Skip arguments that have been moved to the Late Arg list
631         if (!(args->gtFlags & GTF_LATE_ARG))
632         {
633             if (arg->gtOper == GT_PUTARG_STK)
634             {
635                 fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
636                 assert(curArgTabEntry);
637
638                 assert(curArgTabEntry->regNum == REG_STK);
639
640                 TreeNodeInfoInitPutArgStk(arg->AsPutArgStk(), curArgTabEntry);
641             }
642             else
643             {
644                 TreeNodeInfo* argInfo = &(arg->gtLsraInfo);
645                 if (argInfo->dstCount != 0)
646                 {
647                     argInfo->isLocalDefUse = true;
648                 }
649
650                 argInfo->dstCount = 0;
651             }
652         }
653         args = args->gtOp.gtOp2;
654     }
655
656     if (call->IsVarargs() && callHasFloatRegArgs && !call->IsFastTailCall() && (ctrlExpr != nullptr))
657     {
658         NYI_ARM("float reg varargs");
659     }
660
661     if (call->NeedsNullCheck())
662     {
663         info->internalIntCount++;
664     }
665 }
666
667 //------------------------------------------------------------------------
668 // TreeNodeInfoInitPutArgStk: Set the NodeInfo for a GT_PUTARG_STK node
669 //
670 // Arguments:
671 //    argNode - a GT_PUTARG_STK node
672 //
673 // Return Value:
674 //    None.
675 //
676 // Notes:
677 //    Set the child node(s) to be contained when we have a multireg arg
678 //
679 void Lowering::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntryPtr info)
680 {
681     assert(argNode->gtOper == GT_PUTARG_STK);
682
683     GenTreePtr putArgChild = argNode->gtOp.gtOp1;
684
685     // Initialize 'argNode' as not contained, as this is both the default case
686     //  and how MakeSrcContained expects to find things setup.
687     //
688     argNode->gtLsraInfo.srcCount = 1;
689     argNode->gtLsraInfo.dstCount = 0;
690
691     // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct
692     if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_FIELD_LIST))
693     {
694         // We will use store instructions that each write a register sized value
695
696         if (putArgChild->OperGet() == GT_FIELD_LIST)
697         {
698             // We consume all of the items in the GT_FIELD_LIST
699             argNode->gtLsraInfo.srcCount = info->numSlots;
700         }
701         else
702         {
703             // We could use a ldp/stp sequence so we need two internal registers
704             argNode->gtLsraInfo.internalIntCount = 2;
705
706             if (putArgChild->OperGet() == GT_OBJ)
707             {
708                 GenTreePtr objChild = putArgChild->gtOp.gtOp1;
709                 if (objChild->OperGet() == GT_LCL_VAR_ADDR)
710                 {
711                     // We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR
712                     // as one contained operation
713                     //
714                     MakeSrcContained(putArgChild, objChild);
715                 }
716             }
717
718             // We will generate all of the code for the GT_PUTARG_STK and it's child node
719             // as one contained operation
720             //
721             MakeSrcContained(argNode, putArgChild);
722         }
723     }
724     else
725     {
726         // We must not have a multi-reg struct
727         assert(info->numSlots == 1);
728     }
729 }
730
731 void Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
732 {
733     TreeNodeInfo* info     = &(tree->gtLsraInfo);
734     LinearScan*   l        = m_lsra;
735     Compiler*     compiler = comp;
736
737     info->srcCount = 1;
738     info->dstCount = 1;
739
740     // Need a variable number of temp regs (see genLclHeap() in codegenarm.cpp):
741     // Here '-' means don't care.
742     //
743     //  Size?                   Init Memory?    # temp regs
744     //   0                          -               0
745     //   const and <=4 ptr words    -             hasPspSym ? 1 : 0
746     //   const and <PageSize        No            hasPspSym ? 1 : 0
747     //   >4 ptr words               Yes           hasPspSym ? 2 : 1
748     //   Non-const                  Yes           hasPspSym ? 2 : 1
749     //   Non-const                  No            hasPspSym ? 2 : 1
750
751     bool hasPspSym;
752 #if FEATURE_EH_FUNCLETS
753     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
754 #else
755     hasPspSym = false;
756 #endif
757
758     GenTreePtr size = tree->gtOp.gtOp1;
759     if (size->IsCnsIntOrI())
760     {
761         MakeSrcContained(tree, size);
762
763         size_t sizeVal = size->gtIntCon.gtIconVal;
764         if (sizeVal == 0)
765         {
766             info->internalIntCount = 0;
767         }
768         else
769         {
770             sizeVal                          = AlignUp(sizeVal, STACK_ALIGN);
771             size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
772
773             // For small allocations up to 4 store instructions
774             if (cntStackAlignedWidthItems <= 4)
775             {
776                 info->internalIntCount = 0;
777             }
778             else if (!compiler->info.compInitMem)
779             {
780                 // No need to initialize allocated stack space.
781                 if (sizeVal < compiler->eeGetPageSize())
782                 {
783                     info->internalIntCount = 0;
784                 }
785                 else
786                 {
787                     // target (regCnt) + tmp + [psp]
788                     info->internalIntCount       = 1;
789                     info->isInternalRegDelayFree = true;
790                 }
791             }
792             else
793             {
794                 // target (regCnt) + tmp + [psp]
795                 info->internalIntCount       = 1;
796                 info->isInternalRegDelayFree = true;
797             }
798
799             if (hasPspSym)
800             {
801                 info->internalIntCount++;
802             }
803         }
804     }
805     else
806     {
807         // target (regCnt) + tmp + [psp]
808         info->internalIntCount       = hasPspSym ? 2 : 1;
809         info->isInternalRegDelayFree = true;
810     }
811 }
812
813 //------------------------------------------------------------------------
814 // TreeNodeInfoInitBlockStore: Set the NodeInfo for a block store.
815 //
816 // Arguments:
817 //    blkNode       - The block store node of interest
818 //
819 // Return Value:
820 //    None.
821 void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
822 {
823     GenTree*    dstAddr  = blkNode->Addr();
824     unsigned    size     = blkNode->gtBlkSize;
825     GenTree*    source   = blkNode->Data();
826     LinearScan* l        = m_lsra;
827     Compiler*   compiler = comp;
828
829     // Sources are dest address and initVal or source.
830     // We may require an additional source or temp register for the size.
831     blkNode->gtLsraInfo.srcCount = 2;
832     blkNode->gtLsraInfo.dstCount = 0;
833     GenTreePtr srcAddrOrFill     = nullptr;
834     bool       isInitBlk         = blkNode->OperIsInitBlkOp();
835
836     if (!isInitBlk)
837     {
838         // CopyObj or CopyBlk
839         if (source->gtOper == GT_IND)
840         {
841             srcAddrOrFill = blkNode->Data()->gtGetOp1();
842             // We're effectively setting source as contained, but can't call MakeSrcContained, because the
843             // "inheritance" of the srcCount is to a child not a parent - it would "just work" but could be misleading.
844             // If srcAddr is already non-contained, we don't need to change it.
845             if (srcAddrOrFill->gtLsraInfo.getDstCount() == 0)
846             {
847                 srcAddrOrFill->gtLsraInfo.setDstCount(1);
848                 srcAddrOrFill->gtLsraInfo.setSrcCount(source->gtLsraInfo.srcCount);
849             }
850             m_lsra->clearOperandCounts(source);
851         }
852         else if (!source->IsMultiRegCall() && !source->OperIsSIMD())
853         {
854             assert(source->IsLocal());
855             MakeSrcContained(blkNode, source);
856         }
857     }
858
859     if (isInitBlk)
860     {
861         GenTreePtr initVal = source;
862         if (initVal->OperIsInitVal())
863         {
864             initVal = initVal->gtGetOp1();
865         }
866         srcAddrOrFill = initVal;
867
868         if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
869         {
870             // TODO-ARM-CQ: Currently we generate a helper call for every
871             // initblk we encounter.  Later on we should implement loop unrolling
872             // code sequences to improve CQ.
873             // For reference see the code in lsraxarch.cpp.
874             NYI_ARM("initblk loop unrolling is currently not implemented.");
875         }
876         else
877         {
878             assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
879             // The helper follows the regular ABI.
880             dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
881             initVal->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
882             if (size != 0)
883             {
884                 // Reserve a temp register for the block size argument.
885                 blkNode->gtLsraInfo.setInternalCandidates(l, RBM_ARG_2);
886                 blkNode->gtLsraInfo.internalIntCount = 1;
887             }
888             else
889             {
890                 // The block size argument is a third argument to GT_STORE_DYN_BLK
891                 noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
892                 blkNode->gtLsraInfo.setSrcCount(3);
893                 GenTree* sizeNode = blkNode->AsDynBlk()->gtDynamicSize;
894                 sizeNode->gtLsraInfo.setSrcCandidates(l, RBM_ARG_2);
895             }
896         }
897     }
898     else
899     {
900         // CopyObj or CopyBlk
901         // Sources are src and dest and size if not constant.
902         if (blkNode->OperGet() == GT_STORE_OBJ)
903         {
904             // CopyObj
905             NYI_ARM("GT_STORE_OBJ is needed of write barriers implementation");
906         }
907         else
908         {
909             // CopyBlk
910             short     internalIntCount      = 0;
911             regMaskTP internalIntCandidates = RBM_NONE;
912
913             if (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)
914             {
915                 // TODO-ARM-CQ: cpblk loop unrolling is currently not implemented.
916                 // In case of a CpBlk with a constant size and less than CPBLK_UNROLL_LIMIT size
917                 // we should unroll the loop to improve CQ.
918                 // For reference see the code in lsraxarch.cpp.
919                 NYI_ARM("cpblk loop unrolling is currently not implemented.");
920             }
921             else
922             {
923                 assert(blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindHelper);
924                 dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
925                 // The srcAddr goes in arg1.
926                 if (srcAddrOrFill != nullptr)
927                 {
928                     srcAddrOrFill->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
929                 }
930                 if (size != 0)
931                 {
932                     // Reserve a temp register for the block size argument.
933                     internalIntCandidates |= RBM_ARG_2;
934                     internalIntCount++;
935                 }
936                 else
937                 {
938                     // The block size argument is a third argument to GT_STORE_DYN_BLK
939                     noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
940                     blkNode->gtLsraInfo.setSrcCount(3);
941                     GenTree* blockSize = blkNode->AsDynBlk()->gtDynamicSize;
942                     blockSize->gtLsraInfo.setSrcCandidates(l, RBM_ARG_2);
943                 }
944             }
945             if (internalIntCount != 0)
946             {
947                 blkNode->gtLsraInfo.internalIntCount = internalIntCount;
948                 blkNode->gtLsraInfo.setInternalCandidates(l, internalIntCandidates);
949             }
950         }
951     }
952 }
953
954 //------------------------------------------------------------------------
955 // TreeNodeInfoInit: Set the register requirements for RA.
956 //
957 // Notes:
958 //    Takes care of annotating the register requirements
959 //    for every TreeNodeInfo struct that maps to each tree node.
960 //
961 // Preconditions:
962 //    LSRA has been initialized and there is a TreeNodeInfo node
963 //    already allocated and initialized for every tree in the IR.
964 //
965 // Postconditions:
966 //    Every TreeNodeInfo instance has the right annotations on register
967 //    requirements needed by LSRA to build the Interval Table (source,
968 //    destination and internal [temp] register counts).
969 //
970 void Lowering::TreeNodeInfoInit(GenTree* tree)
971 {
972     LinearScan* l        = m_lsra;
973     Compiler*   compiler = comp;
974
975     unsigned      kind         = tree->OperKind();
976     TreeNodeInfo* info         = &(tree->gtLsraInfo);
977     RegisterType  registerType = TypeGet(tree);
978
979     JITDUMP("TreeNodeInfoInit for: ");
980     DISPNODE(tree);
981
982     NYI_IF(tree->TypeGet() == TYP_DOUBLE, "lowering double");
983
984     switch (tree->OperGet())
985     {
986         GenTree* op1;
987         GenTree* op2;
988
989         case GT_STORE_LCL_FLD:
990         case GT_STORE_LCL_VAR:
991             if (tree->gtGetOp1()->OperGet() == GT_LONG)
992             {
993                 info->srcCount = 2;
994             }
995             else
996             {
997                 info->srcCount = 1;
998             }
999             info->dstCount = 0;
1000             LowerStoreLoc(tree->AsLclVarCommon());
1001             TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon());
1002             break;
1003
1004         case GT_NOP:
1005             // A GT_NOP is either a passthrough (if it is void, or if it has
1006             // a child), but must be considered to produce a dummy value if it
1007             // has a type but no child
1008             info->srcCount = 0;
1009             if (tree->TypeGet() != TYP_VOID && tree->gtOp.gtOp1 == nullptr)
1010             {
1011                 info->dstCount = 1;
1012             }
1013             else
1014             {
1015                 info->dstCount = 0;
1016             }
1017             break;
1018
1019         case GT_INTRINSIC:
1020         {
1021             // TODO-ARM: Implement other type of intrinsics (round, sqrt and etc.)
1022             // Both operand and its result must be of the same floating point type.
1023             op1 = tree->gtOp.gtOp1;
1024             assert(varTypeIsFloating(op1));
1025             assert(op1->TypeGet() == tree->TypeGet());
1026
1027             switch (tree->gtIntrinsic.gtIntrinsicId)
1028             {
1029                 case CORINFO_INTRINSIC_Abs:
1030                 case CORINFO_INTRINSIC_Sqrt:
1031                     info->srcCount = 1;
1032                     info->dstCount = 1;
1033                     break;
1034                 default:
1035                     NYI_ARM("Lowering::TreeNodeInfoInit for GT_INTRINSIC");
1036                     break;
1037             }
1038         }
1039         break;
1040
1041         case GT_CAST:
1042         {
1043             info->srcCount = 1;
1044             info->dstCount = 1;
1045
1046             // Non-overflow casts to/from float/double are done using SSE2 instructions
1047             // and that allow the source operand to be either a reg or memop. Given the
1048             // fact that casts from small int to float/double are done as two-level casts,
1049             // the source operand is always guaranteed to be of size 4 or 8 bytes.
1050             var_types  castToType = tree->CastToType();
1051             GenTreePtr castOp     = tree->gtCast.CastOp();
1052             var_types  castOpType = castOp->TypeGet();
1053             if (tree->gtFlags & GTF_UNSIGNED)
1054             {
1055                 castOpType = genUnsignedType(castOpType);
1056             }
1057 #ifdef DEBUG
1058             if (!tree->gtOverflow() && (varTypeIsFloating(castToType) || varTypeIsFloating(castOpType)))
1059             {
1060                 // If converting to float/double, the operand must be 4 or 8 byte in size.
1061                 if (varTypeIsFloating(castToType))
1062                 {
1063                     unsigned opSize = genTypeSize(castOpType);
1064                     assert(opSize == 4 || opSize == 8);
1065                 }
1066             }
1067 #endif // DEBUG
1068
1069             if (varTypeIsLong(castOpType))
1070             {
1071                 noway_assert(castOp->OperGet() == GT_LONG);
1072                 info->srcCount = 2;
1073             }
1074
1075             CastInfo castInfo;
1076
1077             // Get information about the cast.
1078             getCastDescription(tree, &castInfo);
1079
1080             if (castInfo.requiresOverflowCheck)
1081             {
1082                 var_types srcType = castOp->TypeGet();
1083                 emitAttr  cmpSize = EA_ATTR(genTypeSize(srcType));
1084
1085                 // If we cannot store the comparisons in an immediate for either
1086                 // comparing against the max or min value, then we will need to
1087                 // reserve a temporary register.
1088
1089                 bool canStoreMaxValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE);
1090                 bool canStoreMinValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE);
1091
1092                 if (!canStoreMaxValue || !canStoreMinValue)
1093                 {
1094                     info->internalIntCount = 1;
1095                 }
1096             }
1097         }
1098         break;
1099
1100         case GT_JTRUE:
1101             info->srcCount = 0;
1102             info->dstCount = 0;
1103             l->clearDstCount(tree->gtOp.gtOp1);
1104             break;
1105
1106         case GT_JMP:
1107             info->srcCount = 0;
1108             info->dstCount = 0;
1109             break;
1110
1111         case GT_SWITCH:
1112             // This should never occur since switch nodes must not be visible at this
1113             // point in the JIT.
1114             info->srcCount = 0;
1115             info->dstCount = 0; // To avoid getting uninit errors.
1116             noway_assert(!"Switch must be lowered at this point");
1117             break;
1118
1119         case GT_JMPTABLE:
1120             info->srcCount = 0;
1121             info->dstCount = 1;
1122             break;
1123
1124         case GT_SWITCH_TABLE:
1125             info->srcCount = 2;
1126             info->dstCount = 0;
1127             break;
1128
1129         case GT_ASG:
1130         case GT_ASG_ADD:
1131         case GT_ASG_SUB:
1132             noway_assert(!"We should never hit any assignment operator in lowering");
1133             info->srcCount = 0;
1134             info->dstCount = 0;
1135             break;
1136
1137         case GT_ADD_LO:
1138         case GT_ADD_HI:
1139         case GT_SUB_LO:
1140         case GT_SUB_HI:
1141         case GT_ADD:
1142         case GT_SUB:
1143             if (varTypeIsFloating(tree->TypeGet()))
1144             {
1145                 // overflow operations aren't supported on float/double types.
1146                 assert(!tree->gtOverflow());
1147
1148                 // No implicit conversions at this stage as the expectation is that
1149                 // everything is made explicit by adding casts.
1150                 assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
1151
1152                 info->srcCount = 2;
1153                 info->dstCount = 1;
1154
1155                 break;
1156             }
1157
1158             __fallthrough;
1159
1160         case GT_AND:
1161         case GT_OR:
1162         case GT_XOR:
1163             info->srcCount = 2;
1164             info->dstCount = 1;
1165             // Check and make op2 contained (if it is a containable immediate)
1166             CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
1167             break;
1168
1169         case GT_RETURNTRAP:
1170             // this just turns into a compare of its child with an int
1171             // + a conditional call
1172             info->srcCount = 1;
1173             info->dstCount = 0;
1174             break;
1175
1176         case GT_MUL:
1177             if (tree->gtOverflow())
1178             {
1179                 // Need a register different from target reg to check for overflow.
1180                 info->internalIntCount = 2;
1181             }
1182             __fallthrough;
1183
1184         case GT_DIV:
1185         case GT_MULHI:
1186         case GT_UDIV:
1187         {
1188             info->srcCount = 2;
1189             info->dstCount = 1;
1190         }
1191         break;
1192
1193         case GT_LIST:
1194         case GT_FIELD_LIST:
1195         case GT_ARGPLACE:
1196         case GT_NO_OP:
1197         case GT_START_NONGC:
1198         case GT_PROF_HOOK:
1199             info->srcCount = 0;
1200             info->dstCount = 0;
1201             break;
1202
1203         case GT_LONG:
1204             if ((tree->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0)
1205             {
1206                 // An unused GT_LONG node needs to consume its sources.
1207                 info->srcCount = 2;
1208             }
1209             else
1210             {
1211                 // Passthrough
1212                 info->srcCount = 0;
1213             }
1214
1215             info->dstCount = 0;
1216             break;
1217
1218         case GT_CNS_DBL:
1219             info->srcCount = 0;
1220             info->dstCount = 1;
1221             if (tree->TypeGet() == TYP_FLOAT)
1222             {
1223                 // An int register for float constant
1224                 info->internalIntCount = 1;
1225             }
1226             else
1227             {
1228                 // TYP_DOUBLE
1229                 assert(tree->TypeGet() == TYP_DOUBLE);
1230
1231                 // Two int registers for double constant
1232                 info->internalIntCount = 2;
1233             }
1234             break;
1235
1236         case GT_RETURN:
1237             TreeNodeInfoInitReturn(tree);
1238             break;
1239
1240         case GT_RETFILT:
1241             if (tree->TypeGet() == TYP_VOID)
1242             {
1243                 info->srcCount = 0;
1244                 info->dstCount = 0;
1245             }
1246             else
1247             {
1248                 assert(tree->TypeGet() == TYP_INT);
1249
1250                 info->srcCount = 1;
1251                 info->dstCount = 0;
1252
1253                 info->setSrcCandidates(l, RBM_INTRET);
1254                 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, RBM_INTRET);
1255             }
1256             break;
1257
1258         case GT_ARR_BOUNDS_CHECK:
1259 #ifdef FEATURE_SIMD
1260         case GT_SIMD_CHK:
1261 #endif // FEATURE_SIMD
1262         {
1263             // Consumes arrLen & index - has no result
1264             info->srcCount = 2;
1265             info->dstCount = 0;
1266         }
1267         break;
1268
1269         case GT_ARR_ELEM:
1270             // These must have been lowered to GT_ARR_INDEX
1271             noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
1272             info->srcCount = 0;
1273             info->dstCount = 0;
1274             break;
1275
1276         case GT_ARR_INDEX:
1277             info->srcCount = 2;
1278             info->dstCount = 1;
1279
1280             // We need one internal register when generating code for GT_ARR_INDEX, however the
1281             // register allocator always may just give us the same one as it gives us for the 'dst'
1282             // as a workaround we will just ask for two internal registers.
1283             //
1284             info->internalIntCount = 2;
1285
1286             // For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
1287             // times while the result is being computed.
1288             tree->AsArrIndex()->ArrObj()->gtLsraInfo.isDelayFree = true;
1289             info->hasDelayFreeSrc                                = true;
1290             break;
1291
1292         case GT_ARR_OFFSET:
1293             // This consumes the offset, if any, the arrObj and the effective index,
1294             // and produces the flattened offset for this dimension.
1295             info->srcCount         = 3;
1296             info->dstCount         = 1;
1297             info->internalIntCount = 1;
1298
1299             // we don't want to generate code for this
1300             if (tree->gtArrOffs.gtOffset->IsIntegralConst(0))
1301             {
1302                 MakeSrcContained(tree, tree->gtArrOffs.gtOffset);
1303             }
1304             break;
1305
1306         case GT_LEA:
1307         {
1308             GenTreeAddrMode* lea = tree->AsAddrMode();
1309
1310             GenTree* base  = lea->Base();
1311             GenTree* index = lea->Index();
1312             unsigned cns   = lea->gtOffset;
1313
1314             // This LEA is instantiating an address,
1315             // so we set up the srcCount and dstCount here.
1316             info->srcCount = 0;
1317             if (base != nullptr)
1318             {
1319                 info->srcCount++;
1320             }
1321             if (index != nullptr)
1322             {
1323                 info->srcCount++;
1324             }
1325             info->dstCount = 1;
1326
1327             // On ARM we may need a single internal register
1328             // (when both conditions are true then we still only need a single internal register)
1329             if ((index != nullptr) && (cns != 0))
1330             {
1331                 // ARM does not support both Index and offset so we need an internal register
1332                 info->internalIntCount = 1;
1333             }
1334             else if (!emitter::emitIns_valid_imm_for_add(cns, INS_FLAGS_DONT_CARE))
1335             {
1336                 // This offset can't be contained in the add instruction, so we need an internal register
1337                 info->internalIntCount = 1;
1338             }
1339         }
1340         break;
1341
1342         case GT_NEG:
1343             info->srcCount = 1;
1344             info->dstCount = 1;
1345             break;
1346
1347         case GT_NOT:
1348             info->srcCount = 1;
1349             info->dstCount = 1;
1350             break;
1351
1352         case GT_LSH:
1353         case GT_RSH:
1354         case GT_RSZ:
1355         case GT_ROR:
1356         case GT_LSH_HI:
1357         case GT_RSH_LO:
1358             TreeNodeInfoInitShiftRotate(tree);
1359             break;
1360
1361         case GT_EQ:
1362         case GT_NE:
1363         case GT_LT:
1364         case GT_LE:
1365         case GT_GE:
1366         case GT_GT:
1367             TreeNodeInfoInitCmp(tree);
1368             break;
1369
1370         case GT_CALL:
1371             TreeNodeInfoInitCall(tree->AsCall());
1372             break;
1373
1374         case GT_STORE_BLK:
1375         case GT_STORE_OBJ:
1376         case GT_STORE_DYN_BLK:
1377             LowerBlockStore(tree->AsBlk());
1378             TreeNodeInfoInitBlockStore(tree->AsBlk());
1379             break;
1380
1381         case GT_LCLHEAP:
1382             TreeNodeInfoInitLclHeap(tree);
1383             break;
1384
1385         case GT_STOREIND:
1386         {
1387             info->srcCount = 2;
1388             info->dstCount = 0;
1389             GenTree* src   = tree->gtOp.gtOp2;
1390
1391             if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
1392             {
1393                 TreeNodeInfoInitGCWriteBarrier(tree);
1394                 break;
1395             }
1396
1397             TreeNodeInfoInitIndir(tree);
1398         }
1399         break;
1400
1401         case GT_NULLCHECK:
1402             info->dstCount      = 0;
1403             info->srcCount      = 1;
1404             info->isLocalDefUse = true;
1405             // null check is an indirection on an addr
1406             TreeNodeInfoInitIndir(tree);
1407             break;
1408
1409         case GT_IND:
1410             info->dstCount = 1;
1411             info->srcCount = 1;
1412             TreeNodeInfoInitIndir(tree);
1413             break;
1414
1415         case GT_CATCH_ARG:
1416             info->srcCount = 0;
1417             info->dstCount = 1;
1418             info->setDstCandidates(l, RBM_EXCEPTION_OBJECT);
1419             break;
1420
1421         case GT_CLS_VAR:
1422             info->srcCount = 0;
1423             // GT_CLS_VAR, by the time we reach the backend, must always
1424             // be a pure use.
1425             // It will produce a result of the type of the
1426             // node, and use an internal register for the address.
1427
1428             info->dstCount = 1;
1429             assert((tree->gtFlags & (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_USEDEF)) == 0);
1430             info->internalIntCount = 1;
1431             break;
1432
1433         default:
1434 #ifdef DEBUG
1435             char message[256];
1436             _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
1437                         GenTree::NodeName(tree->OperGet()));
1438             NYIRAW(message);
1439 #else
1440             NYI_ARM("TreeNodeInfoInit default case");
1441 #endif
1442         case GT_LCL_FLD:
1443         case GT_LCL_FLD_ADDR:
1444         case GT_LCL_VAR:
1445         case GT_LCL_VAR_ADDR:
1446         case GT_PHYSREG:
1447         case GT_CLS_VAR_ADDR:
1448         case GT_IL_OFFSET:
1449         case GT_CNS_INT:
1450         case GT_PUTARG_REG:
1451         case GT_PUTARG_STK:
1452         case GT_LABEL:
1453         case GT_PINVOKE_PROLOG:
1454         case GT_JCC:
1455         case GT_MEMORYBARRIER:
1456             info->dstCount = tree->IsValue() ? 1 : 0;
1457             if (kind & (GTK_CONST | GTK_LEAF))
1458             {
1459                 info->srcCount = 0;
1460             }
1461             else if (kind & (GTK_SMPOP))
1462             {
1463                 if (tree->gtGetOp2IfPresent() != nullptr)
1464                 {
1465                     info->srcCount = 2;
1466                 }
1467                 else
1468                 {
1469                     info->srcCount = 1;
1470                 }
1471             }
1472             else
1473             {
1474                 unreached();
1475             }
1476             break;
1477     } // end switch (tree->OperGet())
1478
1479     // We need to be sure that we've set info->srcCount and info->dstCount appropriately
1480     assert((info->dstCount < 2) || tree->IsMultiRegCall());
1481 }
1482
1483 #endif // _TARGET_ARM_
1484
1485 #endif // !LEGACY_BACKEND