Merge pull request #12535 from adityamandaleeka/dispatcher_queues_coreclr
[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 // TreeNodeInfoInitReturn: Set the NodeInfo for a GT_RETURN.
34 //
35 // Arguments:
36 //    tree - The node of interest
37 //
38 // Return Value:
39 //    None.
40 //
41 void Lowering::TreeNodeInfoInitReturn(GenTree* tree)
42 {
43     TreeNodeInfo* info     = &(tree->gtLsraInfo);
44     LinearScan*   l        = m_lsra;
45     Compiler*     compiler = comp;
46
47     if (tree->TypeGet() == TYP_LONG)
48     {
49         GenTree* op1 = tree->gtGetOp1();
50         noway_assert(op1->OperGet() == GT_LONG);
51         op1->SetContained();
52         GenTree* loVal = op1->gtGetOp1();
53         GenTree* hiVal = op1->gtGetOp2();
54         info->srcCount = 2;
55         loVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_LO);
56         hiVal->gtLsraInfo.setSrcCandidates(l, RBM_LNGRET_HI);
57         info->dstCount = 0;
58     }
59     else
60     {
61         GenTree*  op1           = tree->gtGetOp1();
62         regMaskTP useCandidates = RBM_NONE;
63
64         info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
65         info->dstCount = 0;
66
67         if (varTypeIsStruct(tree))
68         {
69             // op1 has to be either an lclvar or a multi-reg returning call
70             if (op1->OperGet() == GT_LCL_VAR)
71             {
72                 GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon();
73                 LclVarDsc*           varDsc       = &(compiler->lvaTable[lclVarCommon->gtLclNum]);
74                 assert(varDsc->lvIsMultiRegRet);
75
76                 // Mark var as contained if not enregistrable.
77                 if (!varTypeIsEnregisterableStruct(op1))
78                 {
79                     MakeSrcContained(tree, op1);
80                 }
81             }
82             else
83             {
84                 noway_assert(op1->IsMultiRegCall());
85
86                 ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc();
87                 info->srcCount              = retTypeDesc->GetReturnRegCount();
88                 useCandidates               = retTypeDesc->GetABIReturnRegs();
89             }
90         }
91         else
92         {
93             // Non-struct type return - determine useCandidates
94             switch (tree->TypeGet())
95             {
96                 case TYP_VOID:
97                     useCandidates = RBM_NONE;
98                     break;
99                 case TYP_FLOAT:
100                     useCandidates = RBM_FLOATRET;
101                     break;
102                 case TYP_DOUBLE:
103                     useCandidates = RBM_DOUBLERET;
104                     break;
105                 case TYP_LONG:
106                     useCandidates = RBM_LNGRET;
107                     break;
108                 default:
109                     useCandidates = RBM_INTRET;
110                     break;
111             }
112         }
113
114         if (useCandidates != RBM_NONE)
115         {
116             tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, useCandidates);
117         }
118     }
119 }
120
121 void Lowering::TreeNodeInfoInitLclHeap(GenTree* tree)
122 {
123     TreeNodeInfo* info     = &(tree->gtLsraInfo);
124     LinearScan*   l        = m_lsra;
125     Compiler*     compiler = comp;
126
127     info->srcCount = 1;
128     info->dstCount = 1;
129
130     // Need a variable number of temp regs (see genLclHeap() in codegenarm.cpp):
131     // Here '-' means don't care.
132     //
133     //  Size?                   Init Memory?    # temp regs
134     //   0                          -               0
135     //   const and <=4 str instr    -             hasPspSym ? 1 : 0
136     //   const and <PageSize        No            hasPspSym ? 1 : 0
137     //   >4 ptr words               Yes           hasPspSym ? 2 : 1
138     //   Non-const                  Yes           hasPspSym ? 2 : 1
139     //   Non-const                  No            hasPspSym ? 2 : 1
140
141     bool hasPspSym;
142 #if FEATURE_EH_FUNCLETS
143     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
144 #else
145     hasPspSym = false;
146 #endif
147
148     GenTreePtr size = tree->gtOp.gtOp1;
149     if (size->IsCnsIntOrI())
150     {
151         MakeSrcContained(tree, size);
152
153         size_t sizeVal = size->gtIntCon.gtIconVal;
154         if (sizeVal == 0)
155         {
156             info->internalIntCount = 0;
157         }
158         else
159         {
160             sizeVal                          = AlignUp(sizeVal, STACK_ALIGN);
161             size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
162
163             // For small allocations up to 4 store instructions
164             if (cntStackAlignedWidthItems <= 4)
165             {
166                 info->internalIntCount = 0;
167             }
168             else if (!compiler->info.compInitMem)
169             {
170                 // No need to initialize allocated stack space.
171                 if (sizeVal < compiler->eeGetPageSize())
172                 {
173                     info->internalIntCount = 0;
174                 }
175                 else
176                 {
177                     info->internalIntCount = 1;
178                 }
179             }
180             else
181             {
182                 info->internalIntCount = 1;
183             }
184
185             if (hasPspSym)
186             {
187                 info->internalIntCount++;
188             }
189         }
190     }
191     else
192     {
193         // target (regCnt) + tmp + [psp]
194         info->internalIntCount = hasPspSym ? 2 : 1;
195     }
196
197     // If we are needed in temporary registers we should be sure that
198     // it's different from target (regCnt)
199     if (info->internalIntCount > 0)
200     {
201         info->isInternalRegDelayFree = true;
202     }
203 }
204
205 //------------------------------------------------------------------------
206 // TreeNodeInfoInit: Set the register requirements for RA.
207 //
208 // Notes:
209 //    Takes care of annotating the register requirements
210 //    for every TreeNodeInfo struct that maps to each tree node.
211 //
212 // Preconditions:
213 //    LSRA has been initialized and there is a TreeNodeInfo node
214 //    already allocated and initialized for every tree in the IR.
215 //
216 // Postconditions:
217 //    Every TreeNodeInfo instance has the right annotations on register
218 //    requirements needed by LSRA to build the Interval Table (source,
219 //    destination and internal [temp] register counts).
220 //
221 void Lowering::TreeNodeInfoInit(GenTree* tree)
222 {
223     LinearScan* l        = m_lsra;
224     Compiler*   compiler = comp;
225
226     unsigned      kind         = tree->OperKind();
227     TreeNodeInfo* info         = &(tree->gtLsraInfo);
228     RegisterType  registerType = TypeGet(tree);
229
230     JITDUMP("TreeNodeInfoInit for: ");
231     DISPNODE(tree);
232
233     switch (tree->OperGet())
234     {
235         GenTree* op1;
236         GenTree* op2;
237
238         case GT_STORE_LCL_FLD:
239         case GT_STORE_LCL_VAR:
240             if (varTypeIsLong(tree->gtGetOp1()))
241             {
242                 info->srcCount = 2;
243             }
244             else
245             {
246                 info->srcCount = 1;
247             }
248             info->dstCount = 0;
249             LowerStoreLoc(tree->AsLclVarCommon());
250             TreeNodeInfoInitStoreLoc(tree->AsLclVarCommon());
251             break;
252
253         case GT_NOP:
254             // A GT_NOP is either a passthrough (if it is void, or if it has
255             // a child), but must be considered to produce a dummy value if it
256             // has a type but no child
257             info->srcCount = 0;
258             if (tree->TypeGet() != TYP_VOID && tree->gtOp.gtOp1 == nullptr)
259             {
260                 info->dstCount = 1;
261             }
262             else
263             {
264                 info->dstCount = 0;
265             }
266             break;
267
268         case GT_INTRINSIC:
269         {
270             // TODO-ARM: Implement other type of intrinsics (round, sqrt and etc.)
271             // Both operand and its result must be of the same floating point type.
272             op1 = tree->gtOp.gtOp1;
273             assert(varTypeIsFloating(op1));
274             assert(op1->TypeGet() == tree->TypeGet());
275
276             switch (tree->gtIntrinsic.gtIntrinsicId)
277             {
278                 case CORINFO_INTRINSIC_Abs:
279                 case CORINFO_INTRINSIC_Sqrt:
280                     info->srcCount = 1;
281                     info->dstCount = 1;
282                     break;
283                 default:
284                     NYI_ARM("Lowering::TreeNodeInfoInit for GT_INTRINSIC");
285                     break;
286             }
287         }
288         break;
289
290         case GT_CAST:
291         {
292             info->srcCount = 1;
293             info->dstCount = 1;
294
295             // Non-overflow casts to/from float/double are done using SSE2 instructions
296             // and that allow the source operand to be either a reg or memop. Given the
297             // fact that casts from small int to float/double are done as two-level casts,
298             // the source operand is always guaranteed to be of size 4 or 8 bytes.
299             var_types  castToType = tree->CastToType();
300             GenTreePtr castOp     = tree->gtCast.CastOp();
301             var_types  castOpType = castOp->TypeGet();
302             if (tree->gtFlags & GTF_UNSIGNED)
303             {
304                 castOpType = genUnsignedType(castOpType);
305             }
306 #ifdef DEBUG
307             if (!tree->gtOverflow() && (varTypeIsFloating(castToType) || varTypeIsFloating(castOpType)))
308             {
309                 // If converting to float/double, the operand must be 4 or 8 byte in size.
310                 if (varTypeIsFloating(castToType))
311                 {
312                     unsigned opSize = genTypeSize(castOpType);
313                     assert(opSize == 4 || opSize == 8);
314                 }
315             }
316 #endif // DEBUG
317
318             if (varTypeIsLong(castOpType))
319             {
320                 noway_assert(castOp->OperGet() == GT_LONG);
321                 castOp->SetContained();
322                 info->srcCount = 2;
323             }
324
325             // FloatToIntCast needs a temporary register
326             if (varTypeIsFloating(castOpType) && varTypeIsIntOrI(tree))
327             {
328                 info->setInternalCandidates(m_lsra, RBM_ALLFLOAT);
329                 info->internalFloatCount     = 1;
330                 info->isInternalRegDelayFree = true;
331             }
332
333             CastInfo castInfo;
334
335             // Get information about the cast.
336             getCastDescription(tree, &castInfo);
337
338             if (castInfo.requiresOverflowCheck)
339             {
340                 var_types srcType = castOp->TypeGet();
341                 emitAttr  cmpSize = EA_ATTR(genTypeSize(srcType));
342
343                 // If we cannot store data in an immediate for instructions,
344                 // then we will need to reserve a temporary register.
345
346                 if (!castInfo.signCheckOnly) // In case of only sign check, temp regs are not needeed.
347                 {
348                     if (castInfo.unsignedSource || castInfo.unsignedDest)
349                     {
350                         // check typeMask
351                         bool canStoreTypeMask = emitter::emitIns_valid_imm_for_alu(castInfo.typeMask);
352                         if (!canStoreTypeMask)
353                         {
354                             info->internalIntCount = 1;
355                         }
356                     }
357                     else
358                     {
359                         // For comparing against the max or min value
360                         bool canStoreMaxValue =
361                             emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, INS_FLAGS_DONT_CARE);
362                         bool canStoreMinValue =
363                             emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, INS_FLAGS_DONT_CARE);
364
365                         if (!canStoreMaxValue || !canStoreMinValue)
366                         {
367                             info->internalIntCount = 1;
368                         }
369                     }
370                 }
371             }
372         }
373         break;
374
375         case GT_JTRUE:
376             info->srcCount = 0;
377             info->dstCount = 0;
378             l->clearDstCount(tree->gtOp.gtOp1);
379             break;
380
381         case GT_JMP:
382             info->srcCount = 0;
383             info->dstCount = 0;
384             break;
385
386         case GT_SWITCH:
387             // This should never occur since switch nodes must not be visible at this
388             // point in the JIT.
389             info->srcCount = 0;
390             info->dstCount = 0; // To avoid getting uninit errors.
391             noway_assert(!"Switch must be lowered at this point");
392             break;
393
394         case GT_JMPTABLE:
395             info->srcCount = 0;
396             info->dstCount = 1;
397             break;
398
399         case GT_SWITCH_TABLE:
400             info->srcCount = 2;
401             info->dstCount = 0;
402             break;
403
404         case GT_ASG:
405         case GT_ASG_ADD:
406         case GT_ASG_SUB:
407             noway_assert(!"We should never hit any assignment operator in lowering");
408             info->srcCount = 0;
409             info->dstCount = 0;
410             break;
411
412         case GT_ADD_LO:
413         case GT_ADD_HI:
414         case GT_SUB_LO:
415         case GT_SUB_HI:
416         case GT_ADD:
417         case GT_SUB:
418             if (varTypeIsFloating(tree->TypeGet()))
419             {
420                 // overflow operations aren't supported on float/double types.
421                 assert(!tree->gtOverflow());
422
423                 // No implicit conversions at this stage as the expectation is that
424                 // everything is made explicit by adding casts.
425                 assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
426
427                 info->srcCount = 2;
428                 info->dstCount = 1;
429
430                 break;
431             }
432
433             __fallthrough;
434
435         case GT_AND:
436         case GT_OR:
437         case GT_XOR:
438             info->srcCount = 2;
439             info->dstCount = 1;
440             // Check and make op2 contained (if it is a containable immediate)
441             CheckImmedAndMakeContained(tree, tree->gtOp.gtOp2);
442             break;
443
444         case GT_RETURNTRAP:
445             // this just turns into a compare of its child with an int
446             // + a conditional call
447             info->srcCount = 1;
448             info->dstCount = 0;
449             break;
450
451         case GT_MUL:
452             if (tree->gtOverflow())
453             {
454                 // Need a register different from target reg to check for overflow.
455                 info->internalIntCount       = 1;
456                 info->isInternalRegDelayFree = true;
457             }
458             __fallthrough;
459
460         case GT_DIV:
461         case GT_MULHI:
462         case GT_UDIV:
463         {
464             info->srcCount = 2;
465             info->dstCount = 1;
466         }
467         break;
468
469         case GT_MUL_LONG:
470             info->srcCount = 2;
471             info->dstCount = 2;
472             break;
473
474         case GT_LIST:
475         case GT_FIELD_LIST:
476         case GT_ARGPLACE:
477         case GT_NO_OP:
478         case GT_START_NONGC:
479         case GT_PROF_HOOK:
480             info->srcCount = 0;
481             info->dstCount = 0;
482             break;
483
484         case GT_LONG:
485             if ((tree->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0)
486             {
487                 // An unused GT_LONG node needs to consume its sources.
488                 info->srcCount = 2;
489             }
490             else
491             {
492                 // Passthrough
493                 info->srcCount = 0;
494             }
495
496             info->dstCount = 0;
497             break;
498
499         case GT_CNS_DBL:
500             info->srcCount = 0;
501             info->dstCount = 1;
502             if (tree->TypeGet() == TYP_FLOAT)
503             {
504                 // An int register for float constant
505                 info->internalIntCount = 1;
506             }
507             else
508             {
509                 // TYP_DOUBLE
510                 assert(tree->TypeGet() == TYP_DOUBLE);
511
512                 // Two int registers for double constant
513                 info->internalIntCount = 2;
514             }
515             break;
516
517         case GT_RETURN:
518             TreeNodeInfoInitReturn(tree);
519             break;
520
521         case GT_RETFILT:
522             if (tree->TypeGet() == TYP_VOID)
523             {
524                 info->srcCount = 0;
525                 info->dstCount = 0;
526             }
527             else
528             {
529                 assert(tree->TypeGet() == TYP_INT);
530
531                 info->srcCount = 1;
532                 info->dstCount = 0;
533
534                 info->setSrcCandidates(l, RBM_INTRET);
535                 tree->gtOp.gtOp1->gtLsraInfo.setSrcCandidates(l, RBM_INTRET);
536             }
537             break;
538
539         case GT_ARR_BOUNDS_CHECK:
540 #ifdef FEATURE_SIMD
541         case GT_SIMD_CHK:
542 #endif // FEATURE_SIMD
543         {
544             // Consumes arrLen & index - has no result
545             info->srcCount = 2;
546             info->dstCount = 0;
547         }
548         break;
549
550         case GT_ARR_ELEM:
551             // These must have been lowered to GT_ARR_INDEX
552             noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
553             info->srcCount = 0;
554             info->dstCount = 0;
555             break;
556
557         case GT_ARR_INDEX:
558             info->srcCount               = 2;
559             info->dstCount               = 1;
560             info->internalIntCount       = 1;
561             info->isInternalRegDelayFree = true;
562
563             // For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
564             // times while the result is being computed.
565             tree->AsArrIndex()->ArrObj()->gtLsraInfo.isDelayFree = true;
566             info->hasDelayFreeSrc                                = true;
567             break;
568
569         case GT_ARR_OFFSET:
570             // This consumes the offset, if any, the arrObj and the effective index,
571             // and produces the flattened offset for this dimension.
572             info->srcCount = 3;
573             info->dstCount = 1;
574
575             // we don't want to generate code for this
576             if (tree->gtArrOffs.gtOffset->IsIntegralConst(0))
577             {
578                 MakeSrcContained(tree, tree->gtArrOffs.gtOffset);
579             }
580             else
581             {
582                 // Here we simply need an internal register, which must be different
583                 // from any of the operand's registers, but may be the same as targetReg.
584                 info->internalIntCount = 1;
585             }
586             break;
587
588         case GT_LEA:
589         {
590             GenTreeAddrMode* lea    = tree->AsAddrMode();
591             unsigned         offset = lea->gtOffset;
592
593             // This LEA is instantiating an address, so we set up the srcCount and dstCount here.
594             info->srcCount = 0;
595             if (lea->HasBase())
596             {
597                 info->srcCount++;
598             }
599             if (lea->HasIndex())
600             {
601                 info->srcCount++;
602             }
603             info->dstCount = 1;
604
605             // An internal register may be needed too; the logic here should be in sync with the
606             // genLeaInstruction()'s requirements for a such register.
607             if (lea->HasBase() && lea->HasIndex())
608             {
609                 if (offset != 0)
610                 {
611                     // We need a register when we have all three: base reg, index reg and a non-zero offset.
612                     info->internalIntCount = 1;
613                 }
614             }
615             else if (lea->HasBase())
616             {
617                 if (!emitter::emitIns_valid_imm_for_add(offset, INS_FLAGS_DONT_CARE))
618                 {
619                     // We need a register when we have an offset that is too large to encode in the add instruction.
620                     info->internalIntCount = 1;
621                 }
622             }
623         }
624         break;
625
626         case GT_NEG:
627             info->srcCount = 1;
628             info->dstCount = 1;
629             break;
630
631         case GT_NOT:
632             info->srcCount = 1;
633             info->dstCount = 1;
634             break;
635
636         case GT_LSH:
637         case GT_RSH:
638         case GT_RSZ:
639         case GT_ROR:
640         case GT_LSH_HI:
641         case GT_RSH_LO:
642             TreeNodeInfoInitShiftRotate(tree);
643             break;
644
645         case GT_EQ:
646         case GT_NE:
647         case GT_LT:
648         case GT_LE:
649         case GT_GE:
650         case GT_GT:
651         case GT_CMP:
652             TreeNodeInfoInitCmp(tree);
653             break;
654
655         case GT_CKFINITE:
656             info->srcCount         = 1;
657             info->dstCount         = 1;
658             info->internalIntCount = 1;
659             break;
660
661         case GT_CALL:
662             TreeNodeInfoInitCall(tree->AsCall());
663             break;
664
665         case GT_STORE_BLK:
666         case GT_STORE_OBJ:
667         case GT_STORE_DYN_BLK:
668             LowerBlockStore(tree->AsBlk());
669             TreeNodeInfoInitBlockStore(tree->AsBlk());
670             break;
671
672         case GT_INIT_VAL:
673             // Always a passthrough of its child's value.
674             info->srcCount = 0;
675             info->dstCount = 0;
676             break;
677
678         case GT_LCLHEAP:
679             TreeNodeInfoInitLclHeap(tree);
680             break;
681
682         case GT_STOREIND:
683         {
684             info->srcCount = 2;
685             info->dstCount = 0;
686             GenTree* src   = tree->gtOp.gtOp2;
687
688             if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
689             {
690                 TreeNodeInfoInitGCWriteBarrier(tree);
691                 break;
692             }
693
694             TreeNodeInfoInitIndir(tree);
695         }
696         break;
697
698         case GT_NULLCHECK:
699             info->dstCount      = 0;
700             info->srcCount      = 1;
701             info->isLocalDefUse = true;
702             // null check is an indirection on an addr
703             TreeNodeInfoInitIndir(tree);
704             break;
705
706         case GT_IND:
707             info->dstCount = 1;
708             info->srcCount = 1;
709             TreeNodeInfoInitIndir(tree);
710             break;
711
712         case GT_CATCH_ARG:
713             info->srcCount = 0;
714             info->dstCount = 1;
715             info->setDstCandidates(l, RBM_EXCEPTION_OBJECT);
716             break;
717
718         case GT_CLS_VAR:
719             info->srcCount = 0;
720             // GT_CLS_VAR, by the time we reach the backend, must always
721             // be a pure use.
722             // It will produce a result of the type of the
723             // node, and use an internal register for the address.
724
725             info->dstCount = 1;
726             assert((tree->gtFlags & (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_USEDEF)) == 0);
727             info->internalIntCount = 1;
728             break;
729
730         case GT_COPY:
731             info->srcCount = 1;
732             info->dstCount = 1;
733 #ifdef ARM_SOFTFP
734             // This case currently only occurs for double types that are passed as TYP_LONG;
735             // actual long types would have been decomposed by now.
736             if (tree->TypeGet() == TYP_LONG)
737             {
738                 info->dstCount = 2;
739             }
740 #endif
741             break;
742
743         case GT_PUTARG_REG:
744 #ifdef ARM_SOFTFP
745             // This case currently only occurs for double types that are passed as TYP_LONG;
746             // actual long types would have been decomposed by now.
747             if (tree->TypeGet() == TYP_LONG)
748             {
749                 info->srcCount = 2;
750             }
751             else
752 #endif
753             {
754                 info->srcCount = 1;
755             }
756             info->dstCount = info->srcCount;
757             break;
758
759         default:
760 #ifdef DEBUG
761             char message[256];
762             _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
763                         GenTree::OpName(tree->OperGet()));
764             NYIRAW(message);
765 #else
766             NYI_ARM("TreeNodeInfoInit default case");
767 #endif
768         case GT_LCL_FLD:
769         case GT_LCL_FLD_ADDR:
770         case GT_LCL_VAR:
771         case GT_LCL_VAR_ADDR:
772         case GT_PHYSREG:
773         case GT_CLS_VAR_ADDR:
774         case GT_IL_OFFSET:
775         case GT_CNS_INT:
776         case GT_PUTARG_STK:
777         case GT_LABEL:
778         case GT_PINVOKE_PROLOG:
779         case GT_JCC:
780         case GT_SETCC:
781         case GT_MEMORYBARRIER:
782         case GT_OBJ:
783         case GT_PUTARG_SPLIT:
784             info->dstCount = tree->IsValue() ? 1 : 0;
785             if (kind & (GTK_CONST | GTK_LEAF))
786             {
787                 info->srcCount = 0;
788             }
789             else if (kind & (GTK_SMPOP))
790             {
791                 if (tree->gtGetOp2IfPresent() != nullptr)
792                 {
793                     info->srcCount = 2;
794                 }
795                 else
796                 {
797                     info->srcCount = 1;
798                 }
799             }
800             else
801             {
802                 unreached();
803             }
804             break;
805     } // end switch (tree->OperGet())
806
807     // We need to be sure that we've set info->srcCount and info->dstCount appropriately
808     assert((info->dstCount < 2) || tree->IsMultiRegNode());
809 }
810
811 #endif // _TARGET_ARM_
812
813 #endif // !LEGACY_BACKEND