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