Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / lsraarm64.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 ARM64                        XX
9 XX                                                                           XX
10 XX  This encapsulates all the logic for setting register requirements for    XX
11 XX  the ARM64 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_ARM64_
26
27 #include "jit.h"
28 #include "sideeffects.h"
29 #include "lower.h"
30
31 //------------------------------------------------------------------------
32 // BuildNode: Set the register requirements for RA.
33 //
34 // Notes:
35 //    Takes care of annotating the register requirements
36 //    for every TreeNodeInfo struct that maps to each tree node.
37 //
38 // Preconditions:
39 //    LSRA has been initialized and there is a TreeNodeInfo node
40 //    already allocated and initialized for every tree in the IR.
41 //
42 // Postconditions:
43 //    Every TreeNodeInfo instance has the right annotations on register
44 //    requirements needed by LSRA to build the Interval Table (source,
45 //    destination and internal [temp] register counts).
46 //
47 void LinearScan::BuildNode(GenTree* tree)
48 {
49     TreeNodeInfo* info         = currentNodeInfo;
50     unsigned      kind         = tree->OperKind();
51     RegisterType  registerType = TypeGet(tree);
52
53     if (tree->isContained())
54     {
55         info->dstCount = 0;
56         assert(info->srcCount == 0);
57         return;
58     }
59
60     // Set the default dstCount. This may be modified below.
61     if (tree->IsValue())
62     {
63         info->dstCount = 1;
64         if (tree->IsUnusedValue())
65         {
66             info->isLocalDefUse = true;
67         }
68     }
69     else
70     {
71         info->dstCount = 0;
72     }
73
74     switch (tree->OperGet())
75     {
76         GenTree* op1;
77         GenTree* op2;
78
79         default:
80             BuildSimple(tree);
81             break;
82
83         case GT_STORE_LCL_FLD:
84         case GT_STORE_LCL_VAR:
85             info->srcCount = 1;
86             assert(info->dstCount == 0);
87             BuildStoreLoc(tree->AsLclVarCommon());
88             break;
89
90         case GT_FIELD_LIST:
91             // These should always be contained. We don't correctly allocate or
92             // generate code for a non-contained GT_FIELD_LIST.
93             noway_assert(!"Non-contained GT_FIELD_LIST");
94             break;
95
96         case GT_LIST:
97         case GT_ARGPLACE:
98         case GT_NO_OP:
99         case GT_START_NONGC:
100         case GT_PROF_HOOK:
101             info->srcCount = 0;
102             assert(info->dstCount == 0);
103             break;
104
105         case GT_CNS_DBL:
106             info->srcCount = 0;
107             assert(info->dstCount == 1);
108             {
109                 GenTreeDblCon* dblConst   = tree->AsDblCon();
110                 double         constValue = dblConst->gtDblCon.gtDconVal;
111
112                 if (emitter::emitIns_valid_imm_for_fmov(constValue))
113                 {
114                     // Directly encode constant to instructions.
115                 }
116                 else
117                 {
118                     // Reserve int to load constant from memory (IF_LARGELDC)
119                     info->internalIntCount = 1;
120                 }
121             }
122             break;
123
124         case GT_BOX:
125         case GT_COMMA:
126         case GT_QMARK:
127         case GT_COLON:
128             info->srcCount = 0;
129             assert(info->dstCount == 0);
130             unreached();
131             break;
132
133         case GT_RETURN:
134             BuildReturn(tree);
135             break;
136
137         case GT_RETFILT:
138             if (tree->TypeGet() == TYP_VOID)
139             {
140                 info->srcCount = 0;
141                 assert(info->dstCount == 0);
142             }
143             else
144             {
145                 assert(tree->TypeGet() == TYP_INT);
146
147                 info->srcCount = 1;
148                 assert(info->dstCount == 0);
149
150                 info->setSrcCandidates(this, RBM_INTRET);
151                 LocationInfoListNode* locationInfo = getLocationInfo(tree->gtOp.gtOp1);
152                 locationInfo->info.setSrcCandidates(this, RBM_INTRET);
153                 useList.Append(locationInfo);
154             }
155             break;
156
157         case GT_NOP:
158             // A GT_NOP is either a passthrough (if it is void, or if it has
159             // a child), but must be considered to produce a dummy value if it
160             // has a type but no child
161             info->srcCount = 0;
162             if (tree->TypeGet() != TYP_VOID && tree->gtOp.gtOp1 == nullptr)
163             {
164                 assert(info->dstCount == 1);
165             }
166             else
167             {
168                 assert(info->dstCount == 0);
169             }
170             break;
171
172         case GT_JTRUE:
173             info->srcCount = 0;
174             assert(info->dstCount == 0);
175             break;
176
177         case GT_JMP:
178             info->srcCount = 0;
179             assert(info->dstCount == 0);
180             break;
181
182         case GT_SWITCH:
183             // This should never occur since switch nodes must not be visible at this
184             // point in the JIT.
185             info->srcCount = 0;
186             noway_assert(!"Switch must be lowered at this point");
187             break;
188
189         case GT_JMPTABLE:
190             info->srcCount = 0;
191             assert(info->dstCount == 1);
192             break;
193
194         case GT_SWITCH_TABLE:
195             info->srcCount         = appendBinaryLocationInfoToList(tree->AsOp());
196             info->internalIntCount = 1;
197             assert(info->dstCount == 0);
198             break;
199
200         case GT_ASG:
201             noway_assert(!"We should never hit any assignment operator in lowering");
202             info->srcCount = 0;
203             break;
204
205         case GT_ADD:
206         case GT_SUB:
207             if (varTypeIsFloating(tree->TypeGet()))
208             {
209                 // overflow operations aren't supported on float/double types.
210                 assert(!tree->gtOverflow());
211
212                 // No implicit conversions at this stage as the expectation is that
213                 // everything is made explicit by adding casts.
214                 assert(tree->gtOp.gtOp1->TypeGet() == tree->gtOp.gtOp2->TypeGet());
215             }
216
217             __fallthrough;
218
219         case GT_AND:
220         case GT_OR:
221         case GT_XOR:
222         case GT_LSH:
223         case GT_RSH:
224         case GT_RSZ:
225         case GT_ROR:
226             info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
227             assert(info->dstCount == 1);
228             break;
229
230         case GT_RETURNTRAP:
231             // this just turns into a compare of its child with an int
232             // + a conditional call
233             appendLocationInfoToList(tree->gtGetOp1());
234             info->srcCount = 1;
235             assert(info->dstCount == 0);
236             break;
237
238         case GT_MOD:
239         case GT_UMOD:
240             NYI_IF(varTypeIsFloating(tree->TypeGet()), "FP Remainder in ARM64");
241             assert(!"Shouldn't see an integer typed GT_MOD node in ARM64");
242             break;
243
244         case GT_MUL:
245             if (tree->gtOverflow())
246             {
247                 // Need a register different from target reg to check for overflow.
248                 info->internalIntCount       = 1;
249                 info->isInternalRegDelayFree = true;
250             }
251             __fallthrough;
252
253         case GT_DIV:
254         case GT_MULHI:
255         case GT_UDIV:
256         {
257             info->srcCount = appendBinaryLocationInfoToList(tree->AsOp());
258             assert(info->dstCount == 1);
259         }
260         break;
261
262         case GT_INTRINSIC:
263         {
264             noway_assert((tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Abs) ||
265                          (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Ceiling) ||
266                          (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Floor) ||
267                          (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round) ||
268                          (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Sqrt));
269
270             // Both operand and its result must be of the same floating point type.
271             op1 = tree->gtOp.gtOp1;
272             assert(varTypeIsFloating(op1));
273             assert(op1->TypeGet() == tree->TypeGet());
274
275             appendLocationInfoToList(op1);
276             info->srcCount = 1;
277             assert(info->dstCount == 1);
278         }
279         break;
280
281 #ifdef FEATURE_SIMD
282         case GT_SIMD:
283             BuildSIMD(tree->AsSIMD());
284             break;
285 #endif // FEATURE_SIMD
286
287 #ifdef FEATURE_HW_INTRINSICS
288         case GT_HWIntrinsic:
289             BuildHWIntrinsic(tree->AsHWIntrinsic());
290             break;
291 #endif // FEATURE_HW_INTRINSICS
292
293         case GT_CAST:
294         {
295             // TODO-ARM64-CQ: Int-To-Int conversions - castOp cannot be a memory op and must have an assigned
296             //                register.
297             //         see CodeGen::genIntToIntCast()
298
299             appendLocationInfoToList(tree->gtGetOp1());
300             info->srcCount = 1;
301             assert(info->dstCount == 1);
302
303             // Non-overflow casts to/from float/double are done using SSE2 instructions
304             // and that allow the source operand to be either a reg or memop. Given the
305             // fact that casts from small int to float/double are done as two-level casts,
306             // the source operand is always guaranteed to be of size 4 or 8 bytes.
307             var_types castToType = tree->CastToType();
308             GenTree*  castOp     = tree->gtCast.CastOp();
309             var_types castOpType = castOp->TypeGet();
310             if (tree->gtFlags & GTF_UNSIGNED)
311             {
312                 castOpType = genUnsignedType(castOpType);
313             }
314
315             // Some overflow checks need a temp reg
316
317             Lowering::CastInfo castInfo;
318             // Get information about the cast.
319             Lowering::getCastDescription(tree, &castInfo);
320
321             if (castInfo.requiresOverflowCheck)
322             {
323                 var_types srcType = castOp->TypeGet();
324                 emitAttr  cmpSize = EA_ATTR(genTypeSize(srcType));
325
326                 // If we cannot store the comparisons in an immediate for either
327                 // comparing against the max or min value, then we will need to
328                 // reserve a temporary register.
329
330                 bool canStoreMaxValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMax, cmpSize);
331                 bool canStoreMinValue = emitter::emitIns_valid_imm_for_cmp(castInfo.typeMin, cmpSize);
332
333                 if (!canStoreMaxValue || !canStoreMinValue)
334                 {
335                     info->internalIntCount = 1;
336                 }
337             }
338         }
339         break;
340
341         case GT_NEG:
342         case GT_NOT:
343             appendLocationInfoToList(tree->gtGetOp1());
344             info->srcCount = 1;
345             assert(info->dstCount == 1);
346             break;
347
348         case GT_EQ:
349         case GT_NE:
350         case GT_LT:
351         case GT_LE:
352         case GT_GE:
353         case GT_GT:
354         case GT_TEST_EQ:
355         case GT_TEST_NE:
356         case GT_JCMP:
357             BuildCmp(tree);
358             break;
359
360         case GT_CKFINITE:
361             appendLocationInfoToList(tree->gtOp.gtOp1);
362             info->srcCount = 1;
363             assert(info->dstCount == 1);
364             info->internalIntCount = 1;
365             break;
366
367         case GT_CMPXCHG:
368         {
369             GenTreeCmpXchg* cmpXchgNode = tree->AsCmpXchg();
370             info->srcCount              = cmpXchgNode->gtOpComparand->isContained() ? 2 : 3;
371             assert(info->dstCount == 1);
372
373             info->internalIntCount = 1;
374
375             // For ARMv8 exclusives the lifetime of the addr and data must be extended because
376             // it may be used used multiple during retries
377             LocationInfoListNode* locationInfo = getLocationInfo(tree->gtCmpXchg.gtOpLocation);
378             locationInfo->info.isDelayFree     = true;
379             useList.Append(locationInfo);
380             LocationInfoListNode* valueInfo = getLocationInfo(tree->gtCmpXchg.gtOpValue);
381             valueInfo->info.isDelayFree     = true;
382             useList.Append(valueInfo);
383             if (!cmpXchgNode->gtOpComparand->isContained())
384             {
385                 LocationInfoListNode* comparandInfo = getLocationInfo(tree->gtCmpXchg.gtOpComparand);
386                 comparandInfo->info.isDelayFree     = true;
387                 useList.Append(comparandInfo);
388             }
389             info->hasDelayFreeSrc = true;
390
391             // Internals may not collide with target
392             info->isInternalRegDelayFree = true;
393         }
394         break;
395
396         case GT_LOCKADD:
397         case GT_XADD:
398         case GT_XCHG:
399         {
400             assert(info->dstCount == (tree->TypeGet() == TYP_VOID) ? 0 : 1);
401             info->srcCount         = tree->gtOp.gtOp2->isContained() ? 1 : 2;
402             info->internalIntCount = (tree->OperGet() == GT_XCHG) ? 1 : 2;
403
404             // For ARMv8 exclusives the lifetime of the addr and data must be extended because
405             // it may be used used multiple during retries
406             assert(!tree->gtOp.gtOp1->isContained());
407             LocationInfoListNode* op1Info = getLocationInfo(tree->gtOp.gtOp1);
408             useList.Append(op1Info);
409             LocationInfoListNode* op2Info = nullptr;
410             if (!tree->gtOp.gtOp2->isContained())
411             {
412                 op2Info = getLocationInfo(tree->gtOp.gtOp2);
413                 useList.Append(op2Info);
414             }
415             if (info->dstCount != 0)
416             {
417                 op1Info->info.isDelayFree = true;
418                 if (op2Info != nullptr)
419                 {
420                     op2Info->info.isDelayFree = true;
421                 }
422                 // Internals may not collide with target
423                 info->isInternalRegDelayFree = true;
424                 info->hasDelayFreeSrc        = true;
425             }
426         }
427         break;
428
429         case GT_PUTARG_STK:
430             BuildPutArgStk(tree->AsPutArgStk());
431             break;
432
433         case GT_PUTARG_REG:
434             BuildPutArgReg(tree->AsUnOp());
435             break;
436
437         case GT_CALL:
438             BuildCall(tree->AsCall());
439             break;
440
441         case GT_ADDR:
442         {
443             // For a GT_ADDR, the child node should not be evaluated into a register
444             GenTree* child = tree->gtOp.gtOp1;
445             assert(!isCandidateLocalRef(child));
446             assert(child->isContained());
447             assert(info->dstCount == 1);
448             info->srcCount = 0;
449         }
450         break;
451
452         case GT_BLK:
453         case GT_DYN_BLK:
454             // These should all be eliminated prior to Lowering.
455             assert(!"Non-store block node in Lowering");
456             info->srcCount = 0;
457             break;
458
459         case GT_STORE_BLK:
460         case GT_STORE_OBJ:
461         case GT_STORE_DYN_BLK:
462             BuildBlockStore(tree->AsBlk());
463             break;
464
465         case GT_INIT_VAL:
466             // Always a passthrough of its child's value.
467             assert(!"INIT_VAL should always be contained");
468             break;
469
470         case GT_LCLHEAP:
471         {
472             assert(info->dstCount == 1);
473
474             // Need a variable number of temp regs (see genLclHeap() in codegenamd64.cpp):
475             // Here '-' means don't care.
476             //
477             //  Size?                   Init Memory?    # temp regs
478             //   0                          -               0
479             //   const and <=6 ptr words    -               0
480             //   const and <PageSize        No              0
481             //   >6 ptr words               Yes           hasPspSym ? 1 : 0
482             //   Non-const                  Yes           hasPspSym ? 1 : 0
483             //   Non-const                  No              2
484             //
485             // PSPSym - If the method has PSPSym increment internalIntCount by 1.
486             //
487             bool hasPspSym;
488 #if FEATURE_EH_FUNCLETS
489             hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
490 #else
491             hasPspSym = false;
492 #endif
493
494             GenTree* size = tree->gtOp.gtOp1;
495             if (size->IsCnsIntOrI())
496             {
497                 assert(size->isContained());
498                 info->srcCount = 0;
499
500                 size_t sizeVal = size->gtIntCon.gtIconVal;
501
502                 if (sizeVal == 0)
503                 {
504                     info->internalIntCount = 0;
505                 }
506                 else
507                 {
508                     // Compute the amount of memory to properly STACK_ALIGN.
509                     // Note: The Gentree node is not updated here as it is cheap to recompute stack aligned size.
510                     // This should also help in debugging as we can examine the original size specified with
511                     // localloc.
512                     sizeVal                          = AlignUp(sizeVal, STACK_ALIGN);
513                     size_t cntStackAlignedWidthItems = (sizeVal >> STACK_ALIGN_SHIFT);
514
515                     // For small allocations upto 4 'stp' instructions (i.e. 64 bytes of localloc)
516                     //
517                     if (cntStackAlignedWidthItems <= 4)
518                     {
519                         info->internalIntCount = 0;
520                     }
521                     else if (!compiler->info.compInitMem)
522                     {
523                         // No need to initialize allocated stack space.
524                         if (sizeVal < compiler->eeGetPageSize())
525                         {
526                             info->internalIntCount = 0;
527                         }
528                         else
529                         {
530                             // We need two registers: regCnt and RegTmp
531                             info->internalIntCount = 2;
532                         }
533                     }
534                     else
535                     {
536                         // greater than 4 and need to zero initialize allocated stack space.
537                         // If the method has PSPSym, we need an internal register to hold regCnt
538                         // since targetReg allocated to GT_LCLHEAP node could be the same as one of
539                         // the the internal registers.
540                         info->internalIntCount = hasPspSym ? 1 : 0;
541                     }
542                 }
543             }
544             else
545             {
546                 appendLocationInfoToList(size);
547                 info->srcCount = 1;
548                 if (!compiler->info.compInitMem)
549                 {
550                     info->internalIntCount = 2;
551                 }
552                 else
553                 {
554                     // If the method has PSPSym, we need an internal register to hold regCnt
555                     // since targetReg allocated to GT_LCLHEAP node could be the same as one of
556                     // the the internal registers.
557                     info->internalIntCount = hasPspSym ? 1 : 0;
558                 }
559             }
560
561             // If the method has PSPSym, we would need an addtional register to relocate it on stack.
562             if (hasPspSym)
563             {
564                 // Exclude const size 0
565                 if (!size->IsCnsIntOrI() || (size->gtIntCon.gtIconVal > 0))
566                     info->internalIntCount++;
567             }
568         }
569         break;
570
571         case GT_ARR_BOUNDS_CHECK:
572 #ifdef FEATURE_SIMD
573         case GT_SIMD_CHK:
574 #endif // FEATURE_SIMD
575         {
576             GenTreeBoundsChk* node = tree->AsBoundsChk();
577             // Consumes arrLen & index - has no result
578             assert(info->dstCount == 0);
579
580             GenTree* intCns = nullptr;
581             GenTree* other  = nullptr;
582             info->srcCount  = GetOperandInfo(tree->AsBoundsChk()->gtIndex);
583             info->srcCount += GetOperandInfo(tree->AsBoundsChk()->gtArrLen);
584         }
585         break;
586
587         case GT_ARR_ELEM:
588             // These must have been lowered to GT_ARR_INDEX
589             noway_assert(!"We should never see a GT_ARR_ELEM in lowering");
590             info->srcCount = 0;
591             assert(info->dstCount == 0);
592             break;
593
594         case GT_ARR_INDEX:
595         {
596             info->srcCount = 2;
597             assert(info->dstCount == 1);
598             info->internalIntCount       = 1;
599             info->isInternalRegDelayFree = true;
600
601             // For GT_ARR_INDEX, the lifetime of the arrObj must be extended because it is actually used multiple
602             // times while the result is being computed.
603             LocationInfoListNode* arrObjInfo = getLocationInfo(tree->AsArrIndex()->ArrObj());
604             arrObjInfo->info.isDelayFree     = true;
605             useList.Append(arrObjInfo);
606             useList.Append(getLocationInfo(tree->AsArrIndex()->IndexExpr()));
607             info->hasDelayFreeSrc = true;
608         }
609         break;
610
611         case GT_ARR_OFFSET:
612             // This consumes the offset, if any, the arrObj and the effective index,
613             // and produces the flattened offset for this dimension.
614             info->srcCount = 2;
615             if (!tree->gtArrOffs.gtOffset->isContained())
616             {
617                 appendLocationInfoToList(tree->AsArrOffs()->gtOffset);
618                 info->srcCount++;
619             }
620             appendLocationInfoToList(tree->AsArrOffs()->gtIndex);
621             appendLocationInfoToList(tree->AsArrOffs()->gtArrObj);
622             assert(info->dstCount == 1);
623             info->internalIntCount = 1;
624             break;
625
626         case GT_LEA:
627         {
628             GenTreeAddrMode* lea = tree->AsAddrMode();
629
630             GenTree* base  = lea->Base();
631             GenTree* index = lea->Index();
632             int      cns   = lea->Offset();
633
634             // This LEA is instantiating an address, so we set up the srcCount here.
635             info->srcCount = 0;
636             if (base != nullptr)
637             {
638                 info->srcCount++;
639                 appendLocationInfoToList(base);
640             }
641             if (index != nullptr)
642             {
643                 info->srcCount++;
644                 appendLocationInfoToList(index);
645             }
646             assert(info->dstCount == 1);
647
648             // On ARM64 we may need a single internal register
649             // (when both conditions are true then we still only need a single internal register)
650             if ((index != nullptr) && (cns != 0))
651             {
652                 // ARM64 does not support both Index and offset so we need an internal register
653                 info->internalIntCount = 1;
654             }
655             else if (!emitter::emitIns_valid_imm_for_add(cns, EA_8BYTE))
656             {
657                 // This offset can't be contained in the add instruction, so we need an internal register
658                 info->internalIntCount = 1;
659             }
660         }
661         break;
662
663         case GT_STOREIND:
664         {
665             assert(info->dstCount == 0);
666
667             if (compiler->codeGen->gcInfo.gcIsWriteBarrierAsgNode(tree))
668             {
669                 info->srcCount = 2;
670                 BuildGCWriteBarrier(tree);
671                 break;
672             }
673
674             BuildIndir(tree->AsIndir());
675             if (!tree->gtGetOp2()->isContained())
676             {
677                 appendLocationInfoToList(tree->gtGetOp2());
678                 info->srcCount++;
679             }
680         }
681         break;
682
683         case GT_NULLCHECK:
684             // Unlike ARM, ARM64 implements NULLCHECK as a load to REG_ZR, so no internal register
685             // is required, and it is not a localDefUse.
686             assert(info->dstCount == 0);
687             assert(!tree->gtGetOp1()->isContained());
688             appendLocationInfoToList(tree->gtOp.gtOp1);
689             info->srcCount = 1;
690             break;
691
692         case GT_IND:
693             assert(info->dstCount == 1);
694             BuildIndir(tree->AsIndir());
695             break;
696
697         case GT_CATCH_ARG:
698             info->srcCount = 0;
699             assert(info->dstCount == 1);
700             info->setDstCandidates(this, RBM_EXCEPTION_OBJECT);
701             break;
702
703         case GT_CLS_VAR:
704             info->srcCount = 0;
705             // GT_CLS_VAR, by the time we reach the backend, must always
706             // be a pure use.
707             // It will produce a result of the type of the
708             // node, and use an internal register for the address.
709
710             assert(info->dstCount == 1);
711             assert((tree->gtFlags & (GTF_VAR_DEF | GTF_VAR_USEASG)) == 0);
712             info->internalIntCount = 1;
713             break;
714
715         case GT_INDEX_ADDR:
716             assert(info->dstCount == 1);
717             info->srcCount         = appendBinaryLocationInfoToList(tree->AsOp());
718             info->internalIntCount = 1;
719             break;
720     } // end switch (tree->OperGet())
721
722     if (tree->IsUnusedValue() && (info->dstCount != 0))
723     {
724         info->isLocalDefUse = true;
725     }
726     // We need to be sure that we've set info->srcCount and info->dstCount appropriately
727     assert((info->dstCount < 2) || tree->IsMultiRegCall());
728     assert(info->isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
729     assert(!tree->IsUnusedValue() || (info->dstCount != 0));
730     assert(info->dstCount == tree->GetRegisterDstCount());
731 }
732
733 #ifdef FEATURE_SIMD
734 //------------------------------------------------------------------------
735 // BuildSIMD: Set the NodeInfo for a GT_SIMD tree.
736 //
737 // Arguments:
738 //    tree       - The GT_SIMD node of interest
739 //
740 // Return Value:
741 //    None.
742
743 void LinearScan::BuildSIMD(GenTreeSIMD* simdTree)
744 {
745     TreeNodeInfo* info = currentNodeInfo;
746     // Only SIMDIntrinsicInit can be contained
747     if (simdTree->isContained())
748     {
749         assert(simdTree->gtSIMDIntrinsicID == SIMDIntrinsicInit);
750     }
751     assert(info->dstCount == 1);
752
753     GenTree* op1 = simdTree->gtOp.gtOp1;
754     GenTree* op2 = simdTree->gtOp.gtOp2;
755     if (!op1->OperIs(GT_LIST))
756     {
757         info->srcCount += GetOperandInfo(op1);
758     }
759     if ((op2 != nullptr) && !op2->isContained())
760     {
761         info->srcCount += GetOperandInfo(op2);
762     }
763
764     switch (simdTree->gtSIMDIntrinsicID)
765     {
766         case SIMDIntrinsicInit:
767             assert(info->srcCount == (simdTree->gtGetOp1()->isContained() ? 0 : 1));
768             break;
769
770         case SIMDIntrinsicCast:
771         case SIMDIntrinsicSqrt:
772         case SIMDIntrinsicAbs:
773         case SIMDIntrinsicConvertToSingle:
774         case SIMDIntrinsicConvertToInt32:
775         case SIMDIntrinsicConvertToDouble:
776         case SIMDIntrinsicConvertToInt64:
777         case SIMDIntrinsicWidenLo:
778         case SIMDIntrinsicWidenHi:
779             assert(info->srcCount == 1);
780             break;
781
782         case SIMDIntrinsicGetItem:
783         {
784             op1 = simdTree->gtGetOp1();
785             op2 = simdTree->gtGetOp2();
786
787             // We have an object and an index, either of which may be contained.
788             if (!op2->IsCnsIntOrI() && (!op1->isContained() || op1->OperIsLocal()))
789             {
790                 // If the index is not a constant and not contained or is a local
791                 // we will need a general purpose register to calculate the address
792                 info->internalIntCount = 1;
793
794                 // internal register must not clobber input index
795                 LocationInfoListNode* op2Info =
796                     (op1->isContained()) ? useList.Begin() : useList.GetSecond(INDEBUG(op2));
797                 op2Info->info.isDelayFree = true;
798                 info->hasDelayFreeSrc     = true;
799             }
800
801             if (!op2->IsCnsIntOrI() && (!op1->isContained()))
802             {
803                 // If vector is not already in memory (contained) and the index is not a constant,
804                 // we will use the SIMD temp location to store the vector.
805                 compiler->getSIMDInitTempVarNum();
806             }
807         }
808         break;
809
810         case SIMDIntrinsicAdd:
811         case SIMDIntrinsicSub:
812         case SIMDIntrinsicMul:
813         case SIMDIntrinsicDiv:
814         case SIMDIntrinsicBitwiseAnd:
815         case SIMDIntrinsicBitwiseAndNot:
816         case SIMDIntrinsicBitwiseOr:
817         case SIMDIntrinsicBitwiseXor:
818         case SIMDIntrinsicMin:
819         case SIMDIntrinsicMax:
820         case SIMDIntrinsicEqual:
821         case SIMDIntrinsicLessThan:
822         case SIMDIntrinsicGreaterThan:
823         case SIMDIntrinsicLessThanOrEqual:
824         case SIMDIntrinsicGreaterThanOrEqual:
825             assert(info->srcCount == 2);
826             break;
827
828         case SIMDIntrinsicSetX:
829         case SIMDIntrinsicSetY:
830         case SIMDIntrinsicSetZ:
831         case SIMDIntrinsicSetW:
832         case SIMDIntrinsicNarrow:
833             assert(info->srcCount == 2);
834
835             // Op1 will write to dst before Op2 is free
836             useList.GetSecond(INDEBUG(simdTree->gtGetOp2()))->info.isDelayFree = true;
837             info->hasDelayFreeSrc                                              = true;
838             break;
839
840         case SIMDIntrinsicInitN:
841         {
842             var_types baseType = simdTree->gtSIMDBaseType;
843             info->srcCount     = (short)(simdTree->gtSIMDSize / genTypeSize(baseType));
844             int initCount      = 0;
845             for (GenTree* list = op1; list != nullptr; list = list->gtGetOp2())
846             {
847                 assert(list->OperGet() == GT_LIST);
848                 GenTree* listItem = list->gtGetOp1();
849                 assert(listItem->TypeGet() == baseType);
850                 assert(!listItem->isContained());
851                 appendLocationInfoToList(listItem);
852                 initCount++;
853             }
854             assert(initCount == info->srcCount);
855
856             if (varTypeIsFloating(simdTree->gtSIMDBaseType))
857             {
858                 // Need an internal register to stitch together all the values into a single vector in a SIMD reg.
859                 info->setInternalCandidates(this, RBM_ALLFLOAT);
860                 info->internalFloatCount = 1;
861             }
862             break;
863         }
864
865         case SIMDIntrinsicInitArray:
866             // We have an array and an index, which may be contained.
867             assert(info->srcCount == (simdTree->gtGetOp2()->isContained() ? 1 : 2));
868             break;
869
870         case SIMDIntrinsicOpEquality:
871         case SIMDIntrinsicOpInEquality:
872             assert(info->srcCount == (simdTree->gtGetOp2()->isContained() ? 1 : 2));
873             info->setInternalCandidates(this, RBM_ALLFLOAT);
874             info->internalFloatCount = 1;
875             break;
876
877         case SIMDIntrinsicDotProduct:
878             assert(info->srcCount == 2);
879             info->setInternalCandidates(this, RBM_ALLFLOAT);
880             info->internalFloatCount = 1;
881             break;
882
883         case SIMDIntrinsicSelect:
884             // TODO-ARM64-CQ Allow lowering to see SIMDIntrinsicSelect so we can generate BSL VC, VA, VB
885             // bsl target register must be VC.  Reserve a temp in case we need to shuffle things.
886             // This will require a different approach, as GenTreeSIMD has only two operands.
887             assert(!"SIMDIntrinsicSelect not yet supported");
888             assert(info->srcCount == 3);
889             info->setInternalCandidates(this, RBM_ALLFLOAT);
890             info->internalFloatCount = 1;
891             break;
892
893         case SIMDIntrinsicInitArrayX:
894         case SIMDIntrinsicInitFixed:
895         case SIMDIntrinsicCopyToArray:
896         case SIMDIntrinsicCopyToArrayX:
897         case SIMDIntrinsicNone:
898         case SIMDIntrinsicGetCount:
899         case SIMDIntrinsicGetOne:
900         case SIMDIntrinsicGetZero:
901         case SIMDIntrinsicGetAllOnes:
902         case SIMDIntrinsicGetX:
903         case SIMDIntrinsicGetY:
904         case SIMDIntrinsicGetZ:
905         case SIMDIntrinsicGetW:
906         case SIMDIntrinsicInstEquals:
907         case SIMDIntrinsicHWAccel:
908         case SIMDIntrinsicWiden:
909         case SIMDIntrinsicInvalid:
910             assert(!"These intrinsics should not be seen during register allocation");
911             __fallthrough;
912
913         default:
914             noway_assert(!"Unimplemented SIMD node type.");
915             unreached();
916     }
917 }
918 #endif // FEATURE_SIMD
919
920 #ifdef FEATURE_HW_INTRINSICS
921 #include "hwintrinsicArm64.h"
922 //------------------------------------------------------------------------
923 // BuildHWIntrinsic: Set the NodeInfo for a GT_HWIntrinsic tree.
924 //
925 // Arguments:
926 //    tree       - The GT_HWIntrinsic node of interest
927 //
928 // Return Value:
929 //    None.
930
931 void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
932 {
933     TreeNodeInfo*  info        = currentNodeInfo;
934     NamedIntrinsic intrinsicID = intrinsicTree->gtHWIntrinsicId;
935
936     GenTreeArgList* argList = nullptr;
937     GenTree*        op1     = intrinsicTree->gtOp.gtOp1;
938     GenTree*        op2     = intrinsicTree->gtOp.gtOp2;
939
940     if (op1->OperIs(GT_LIST))
941     {
942         argList = op1->AsArgList();
943         op1     = argList->Current();
944         op2     = argList->Rest()->Current();
945
946         for (GenTreeArgList* list = argList; list != nullptr; list = list->Rest())
947         {
948             info->srcCount += GetOperandInfo(list->Current());
949         }
950     }
951     else
952     {
953         info->srcCount += GetOperandInfo(op1);
954         if (op2 != nullptr)
955         {
956             info->srcCount += GetOperandInfo(op2);
957         }
958     }
959
960     switch (compiler->getHWIntrinsicInfo(intrinsicID).form)
961     {
962         case HWIntrinsicInfo::Sha1HashOp:
963             info->setInternalCandidates(this, RBM_ALLFLOAT);
964             info->internalFloatCount = 1;
965             if (!op2->isContained())
966             {
967                 LocationInfoListNode* op2Info = useList.Begin()->Next();
968                 op2Info->info.isDelayFree     = true;
969                 GenTree* op3                  = intrinsicTree->gtOp.gtOp1->AsArgList()->Rest()->Rest()->Current();
970                 assert(!op3->isContained());
971                 LocationInfoListNode* op3Info = op2Info->Next();
972                 op3Info->info.isDelayFree     = true;
973                 info->hasDelayFreeSrc         = true;
974                 info->isInternalRegDelayFree  = true;
975             }
976             break;
977         case HWIntrinsicInfo::SimdTernaryRMWOp:
978             if (!op2->isContained())
979             {
980                 LocationInfoListNode* op2Info = useList.Begin()->Next();
981                 op2Info->info.isDelayFree     = true;
982                 GenTree* op3                  = intrinsicTree->gtOp.gtOp1->AsArgList()->Rest()->Rest()->Current();
983                 assert(!op3->isContained());
984                 LocationInfoListNode* op3Info = op2Info->Next();
985                 op3Info->info.isDelayFree     = true;
986                 info->hasDelayFreeSrc         = true;
987             }
988             break;
989         case HWIntrinsicInfo::Sha1RotateOp:
990             info->setInternalCandidates(this, RBM_ALLFLOAT);
991             info->internalFloatCount = 1;
992             break;
993
994         case HWIntrinsicInfo::SimdExtractOp:
995         case HWIntrinsicInfo::SimdInsertOp:
996             if (!op2->isContained())
997             {
998                 // We need a temp to create a switch table
999                 info->internalIntCount = 1;
1000                 info->setInternalCandidates(this, allRegs(TYP_INT));
1001             }
1002             break;
1003
1004         default:
1005             break;
1006     }
1007 }
1008 #endif
1009
1010 #endif // _TARGET_ARM64_
1011
1012 #endif // !LEGACY_BACKEND