373f881a8a2ff64e996fd865703d5c8a75470bfd
[platform/upstream/coreclr.git] / src / jit / lowerxarch.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                           Lowering for AMD64, x86                         XX
9 XX                                                                           XX
10 XX  This encapsulates all the logic for lowering trees for the AMD64         XX
11 XX  architecture.  For a more detailed view of what is lowering, please      XX
12 XX  take a look at Lower.cpp                                                 XX
13 XX                                                                           XX
14 XX                                                                           XX
15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
16 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17 */
18
19 #include "jitpch.h"
20 #ifdef _MSC_VER
21 #pragma hdrstop
22 #endif
23
24 #ifdef _TARGET_XARCH_ // This file is only used for xarch
25
26 #include "jit.h"
27 #include "sideeffects.h"
28 #include "lower.h"
29
30 // xarch supports both ROL and ROR instructions so no lowering is required.
31 void Lowering::LowerRotate(GenTree* tree)
32 {
33     ContainCheckShiftRotate(tree->AsOp());
34 }
35
36 //------------------------------------------------------------------------
37 // LowerStoreLoc: Lower a store of a lclVar
38 //
39 // Arguments:
40 //    storeLoc - the local store (GT_STORE_LCL_FLD or GT_STORE_LCL_VAR)
41 //
42 // Notes:
43 //    This involves:
44 //    - Handling of contained immediates.
45 //    - Widening operations of unsigneds.
46
47 void Lowering::LowerStoreLoc(GenTreeLclVarCommon* storeLoc)
48 {
49     // Try to widen the ops if they are going into a local var.
50     if ((storeLoc->gtOper == GT_STORE_LCL_VAR) && (storeLoc->gtOp1->gtOper == GT_CNS_INT))
51     {
52         GenTreeIntCon* con  = storeLoc->gtOp1->AsIntCon();
53         ssize_t        ival = con->gtIconVal;
54
55         unsigned   varNum = storeLoc->gtLclNum;
56         LclVarDsc* varDsc = comp->lvaTable + varNum;
57
58         if (varDsc->lvIsSIMDType())
59         {
60             noway_assert(storeLoc->gtType != TYP_STRUCT);
61         }
62         unsigned size = genTypeSize(storeLoc);
63         // If we are storing a constant into a local variable
64         // we extend the size of the store here
65         if ((size < 4) && !varTypeIsStruct(varDsc))
66         {
67             if (!varTypeIsUnsigned(varDsc))
68             {
69                 if (genTypeSize(storeLoc) == 1)
70                 {
71                     if ((ival & 0x7f) != ival)
72                     {
73                         ival = ival | 0xffffff00;
74                     }
75                 }
76                 else
77                 {
78                     assert(genTypeSize(storeLoc) == 2);
79                     if ((ival & 0x7fff) != ival)
80                     {
81                         ival = ival | 0xffff0000;
82                     }
83                 }
84             }
85
86             // A local stack slot is at least 4 bytes in size, regardless of
87             // what the local var is typed as, so auto-promote it here
88             // unless it is a field of a promoted struct
89             // TODO-XArch-CQ: if the field is promoted shouldn't we also be able to do this?
90             if (!varDsc->lvIsStructField)
91             {
92                 storeLoc->gtType = TYP_INT;
93                 con->SetIconValue(ival);
94             }
95         }
96     }
97     if (storeLoc->OperIs(GT_STORE_LCL_FLD))
98     {
99         // We should only encounter this for lclVars that are lvDoNotEnregister.
100         verifyLclFldDoNotEnregister(storeLoc->gtLclNum);
101     }
102     ContainCheckStoreLoc(storeLoc);
103 }
104
105 //------------------------------------------------------------------------
106 // LowerStoreIndir: Determine addressing mode for an indirection, and whether operands are contained.
107 //
108 // Arguments:
109 //    node       - The indirect store node (GT_STORE_IND) of interest
110 //
111 // Return Value:
112 //    None.
113 //
114 void Lowering::LowerStoreIndir(GenTreeIndir* node)
115 {
116     // Mark all GT_STOREIND nodes to indicate that it is not known
117     // whether it represents a RMW memory op.
118     node->AsStoreInd()->SetRMWStatusDefault();
119
120     if (!varTypeIsFloating(node))
121     {
122         // Perform recognition of trees with the following structure:
123         //        StoreInd(addr, BinOp(expr, GT_IND(addr)))
124         // to be able to fold this into an instruction of the form
125         //        BINOP [addr], register
126         // where register is the actual place where 'expr' is computed.
127         //
128         // SSE2 doesn't support RMW form of instructions.
129         if (LowerRMWMemOp(node))
130         {
131             return;
132         }
133     }
134     ContainCheckStoreIndir(node);
135 }
136
137 //------------------------------------------------------------------------
138 // LowerBlockStore: Set block store type
139 //
140 // Arguments:
141 //    blkNode       - The block store node of interest
142 //
143 // Return Value:
144 //    None.
145 //
146 void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
147 {
148     GenTree*  dstAddr       = blkNode->Addr();
149     unsigned  size          = blkNode->gtBlkSize;
150     GenTree*  source        = blkNode->Data();
151     Compiler* compiler      = comp;
152     GenTree*  srcAddrOrFill = nullptr;
153     bool      isInitBlk     = blkNode->OperIsInitBlkOp();
154
155     if (!isInitBlk)
156     {
157         // CopyObj or CopyBlk
158         if ((blkNode->OperGet() == GT_STORE_OBJ) && ((blkNode->AsObj()->gtGcPtrCount == 0) || blkNode->gtBlkOpGcUnsafe))
159         {
160             blkNode->SetOper(GT_STORE_BLK);
161         }
162         if (source->gtOper == GT_IND)
163         {
164             srcAddrOrFill = blkNode->Data()->gtGetOp1();
165         }
166     }
167
168     if (isInitBlk)
169     {
170         GenTree* initVal = source;
171         if (initVal->OperIsInitVal())
172         {
173             initVal->SetContained();
174             initVal = initVal->gtGetOp1();
175         }
176         srcAddrOrFill = initVal;
177         // If we have an InitBlk with constant block size we can optimize several ways:
178         // a) If the size is smaller than a small memory page but larger than INITBLK_UNROLL_LIMIT bytes
179         //    we use rep stosb since this reduces the register pressure in LSRA and we have
180         //    roughly the same performance as calling the helper.
181         // b) If the size is <= INITBLK_UNROLL_LIMIT bytes and the fill byte is a constant,
182         //    we can speed this up by unrolling the loop using SSE2 stores.  The reason for
183         //    this threshold is because our last investigation (Fall 2013), more than 95% of initblks
184         //    in our framework assemblies are actually <= INITBLK_UNROLL_LIMIT bytes size, so this is the
185         //    preferred code sequence for the vast majority of cases.
186
187         // This threshold will decide from using the helper or let the JIT decide to inline
188         // a code sequence of its choice.
189         unsigned helperThreshold = max(INITBLK_STOS_LIMIT, INITBLK_UNROLL_LIMIT);
190
191         // TODO-X86-CQ: Investigate whether a helper call would be beneficial on x86
192         if (size != 0 && size <= helperThreshold)
193         {
194             // Always favor unrolling vs rep stos.
195             if (size <= INITBLK_UNROLL_LIMIT && initVal->IsCnsIntOrI())
196             {
197                 // The fill value of an initblk is interpreted to hold a
198                 // value of (unsigned int8) however a constant of any size
199                 // may practically reside on the evaluation stack. So extract
200                 // the lower byte out of the initVal constant and replicate
201                 // it to a larger constant whose size is sufficient to support
202                 // the largest width store of the desired inline expansion.
203
204                 ssize_t fill = initVal->gtIntCon.gtIconVal & 0xFF;
205 #ifdef _TARGET_AMD64_
206                 if (size < REGSIZE_BYTES)
207                 {
208                     initVal->gtIntCon.gtIconVal = 0x01010101 * fill;
209                 }
210                 else
211                 {
212                     initVal->gtIntCon.gtIconVal = 0x0101010101010101LL * fill;
213                     initVal->gtType             = TYP_LONG;
214                     if ((fill == 0) && ((size & 0xf) == 0))
215                     {
216                         MakeSrcContained(blkNode, source);
217                     }
218                 }
219 #else  // !_TARGET_AMD64_
220                 initVal->gtIntCon.gtIconVal = 0x01010101 * fill;
221 #endif // !_TARGET_AMD64_
222
223                 if ((fill == 0) && ((size & 0xf) == 0))
224                 {
225                     MakeSrcContained(blkNode, source);
226                 }
227                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll;
228             }
229             else
230             {
231                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindRepInstr;
232             }
233         }
234         else
235         {
236 #ifdef _TARGET_AMD64_
237             blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindHelper;
238 #else  // !_TARGET_AMD64_
239             blkNode->gtBlkOpKind            = GenTreeBlk::BlkOpKindRepInstr;
240 #endif // !_TARGET_AMD64_
241         }
242     }
243     else
244     {
245         if (blkNode->gtOper == GT_STORE_OBJ)
246         {
247             // CopyObj
248
249             GenTreeObj* cpObjNode = blkNode->AsObj();
250
251             unsigned slots = cpObjNode->gtSlots;
252
253 #ifdef DEBUG
254             // CpObj must always have at least one GC-Pointer as a member.
255             assert(cpObjNode->gtGcPtrCount > 0);
256
257             assert(dstAddr->gtType == TYP_BYREF || dstAddr->gtType == TYP_I_IMPL);
258
259             CORINFO_CLASS_HANDLE clsHnd    = cpObjNode->gtClass;
260             size_t               classSize = comp->info.compCompHnd->getClassSize(clsHnd);
261             size_t               blkSize   = roundUp(classSize, TARGET_POINTER_SIZE);
262
263             // Currently, the EE always round up a class data structure so
264             // we are not handling the case where we have a non multiple of pointer sized
265             // struct. This behavior may change in the future so in order to keeps things correct
266             // let's assert it just to be safe. Going forward we should simply
267             // handle this case.
268             assert(classSize == blkSize);
269             assert((blkSize / TARGET_POINTER_SIZE) == slots);
270             assert(cpObjNode->HasGCPtr());
271 #endif
272
273             bool IsRepMovsProfitable = false;
274
275             // If the destination is not on the stack, let's find out if we
276             // can improve code size by using rep movsq instead of generating
277             // sequences of movsq instructions.
278             if (!dstAddr->OperIsLocalAddr())
279             {
280                 // Let's inspect the struct/class layout and determine if it's profitable
281                 // to use rep movsq for copying non-gc memory instead of using single movsq
282                 // instructions for each memory slot.
283                 unsigned i      = 0;
284                 BYTE*    gcPtrs = cpObjNode->gtGcPtrs;
285
286                 do
287                 {
288                     unsigned nonGCSlots = 0;
289                     // Measure a contiguous non-gc area inside the struct and note the maximum.
290                     while (i < slots && gcPtrs[i] == TYPE_GC_NONE)
291                     {
292                         nonGCSlots++;
293                         i++;
294                     }
295
296                     while (i < slots && gcPtrs[i] != TYPE_GC_NONE)
297                     {
298                         i++;
299                     }
300
301                     if (nonGCSlots >= CPOBJ_NONGC_SLOTS_LIMIT)
302                     {
303                         IsRepMovsProfitable = true;
304                         break;
305                     }
306                 } while (i < slots);
307             }
308             else if (slots >= CPOBJ_NONGC_SLOTS_LIMIT)
309             {
310                 IsRepMovsProfitable = true;
311             }
312
313             // There are two cases in which we need to materialize the
314             // struct size:
315             // a) When the destination is on the stack we don't need to use the
316             //    write barrier, we can just simply call rep movsq and get a win in codesize.
317             // b) If we determine we have contiguous non-gc regions in the struct where it's profitable
318             //    to use rep movsq instead of a sequence of single movsq instructions.  According to the
319             //    Intel Manual, the sweet spot for small structs is between 4 to 12 slots of size where
320             //    the entire operation takes 20 cycles and encodes in 5 bytes (moving RCX, and calling rep movsq).
321             if (IsRepMovsProfitable)
322             {
323                 // We need the size of the contiguous Non-GC-region to be in RCX to call rep movsq.
324                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindRepInstr;
325             }
326             else
327             {
328                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll;
329             }
330         }
331         else
332         {
333             assert((blkNode->OperGet() == GT_STORE_BLK) || (blkNode->OperGet() == GT_STORE_DYN_BLK));
334             // CopyBlk
335             // In case of a CpBlk with a constant size and less than CPBLK_MOVS_LIMIT size
336             // we can use rep movs to generate code instead of the helper call.
337
338             // This threshold will decide between using the helper or let the JIT decide to inline
339             // a code sequence of its choice.
340             unsigned helperThreshold = max(CPBLK_MOVS_LIMIT, CPBLK_UNROLL_LIMIT);
341
342             // TODO-X86-CQ: Investigate whether a helper call would be beneficial on x86
343             if ((size != 0) && (size <= helperThreshold))
344             {
345                 // If we have a buffer between XMM_REGSIZE_BYTES and CPBLK_UNROLL_LIMIT bytes, we'll use SSE2.
346                 // Structs and buffer with sizes <= CPBLK_UNROLL_LIMIT bytes are occurring in more than 95% of
347                 // our framework assemblies, so this is the main code generation scheme we'll use.
348                 if (size <= CPBLK_UNROLL_LIMIT)
349                 {
350                     blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll;
351
352                     // If src or dst are on stack, we don't have to generate the address
353                     // into a register because it's just some constant+SP.
354                     if ((srcAddrOrFill != nullptr) && srcAddrOrFill->OperIsLocalAddr())
355                     {
356                         MakeSrcContained(blkNode, srcAddrOrFill);
357                     }
358
359                     if (dstAddr->OperIsLocalAddr())
360                     {
361                         MakeSrcContained(blkNode, dstAddr);
362                     }
363                 }
364                 else
365                 {
366                     blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindRepInstr;
367                 }
368             }
369 #ifdef _TARGET_AMD64_
370             else
371             {
372                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindHelper;
373             }
374 #elif defined(_TARGET_X86_)
375             else
376             {
377                 blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindRepInstr;
378             }
379 #endif // _TARGET_X86_
380             assert(blkNode->gtBlkOpKind != GenTreeBlk::BlkOpKindInvalid);
381         }
382
383         // CopyObj or CopyBlk
384         if (source->gtOper == GT_IND)
385         {
386             // The GT_IND is contained, but the address must be in a register unless it is local.
387             MakeSrcContained(blkNode, source);
388             GenTree* addr = source->AsIndir()->Addr();
389             if (!addr->OperIsLocalAddr())
390             {
391                 addr->ClearContained();
392             }
393         }
394         else if (!source->IsMultiRegCall() && !source->OperIsSimdOrHWintrinsic())
395         {
396             assert(source->IsLocal());
397             MakeSrcContained(blkNode, source);
398         }
399     }
400 }
401
402 //------------------------------------------------------------------------
403 // LowerPutArgStk: Lower a GT_PUTARG_STK.
404 //
405 // Arguments:
406 //    tree      - The node of interest
407 //
408 // Return Value:
409 //    None.
410 //
411 void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
412 {
413 #ifdef _TARGET_X86_
414     if (putArgStk->gtOp1->gtOper == GT_FIELD_LIST)
415     {
416         putArgStk->gtNumberReferenceSlots = 0;
417         putArgStk->gtPutArgStkKind        = GenTreePutArgStk::Kind::Invalid;
418
419         GenTreeFieldList* fieldList = putArgStk->gtOp1->AsFieldList();
420
421         // The code generator will push these fields in reverse order by offset. Reorder the list here s.t. the order
422         // of uses is visible to LSRA.
423         unsigned          fieldCount = 0;
424         GenTreeFieldList* head       = nullptr;
425         for (GenTreeFieldList *current = fieldList, *next; current != nullptr; current = next)
426         {
427             next = current->Rest();
428
429             // First, insert the field node into the sorted list.
430             GenTreeFieldList* prev = nullptr;
431             for (GenTreeFieldList* cursor = head;; cursor = cursor->Rest())
432             {
433                 // If the offset of the current list node is greater than the offset of the cursor or if we have
434                 // reached the end of the list, insert the current node before the cursor and terminate.
435                 if ((cursor == nullptr) || (current->gtFieldOffset > cursor->gtFieldOffset))
436                 {
437                     if (prev == nullptr)
438                     {
439                         assert(cursor == head);
440                         head = current;
441                     }
442                     else
443                     {
444                         prev->Rest() = current;
445                     }
446
447                     current->Rest() = cursor;
448                     break;
449                 }
450             }
451
452             fieldCount++;
453         }
454
455         // In theory, the upper bound for the size of a field list is 8: these constructs only appear when passing the
456         // collection of lclVars that represent the fields of a promoted struct lclVar, and we do not promote struct
457         // lclVars with more than 4 fields. If each of these lclVars is of type long, decomposition will split the
458         // corresponding field list nodes in two, giving an upper bound of 8.
459         //
460         // The reason that this is important is that the algorithm we use above to sort the field list is O(N^2): if
461         // the maximum size of a field list grows significantly, we will need to reevaluate it.
462         assert(fieldCount <= 8);
463
464         // The sort above may have changed which node is at the head of the list. Update the PUTARG_STK node if
465         // necessary.
466         if (head != fieldList)
467         {
468             head->gtFlags |= GTF_FIELD_LIST_HEAD;
469             head->SetContained();
470
471             fieldList->ClearContained();
472             fieldList->gtFlags &= ~GTF_FIELD_LIST_HEAD;
473
474 #ifdef DEBUG
475             head->gtSeqNum = fieldList->gtSeqNum;
476 #endif // DEBUG
477
478             BlockRange().InsertAfter(fieldList, head);
479             BlockRange().Remove(fieldList);
480
481             fieldList         = head;
482             putArgStk->gtOp1  = fieldList;
483             putArgStk->gtType = fieldList->gtType;
484         }
485
486         // Now that the fields have been sorted, the kind of code we will generate.
487         bool     allFieldsAreSlots = true;
488         unsigned prevOffset        = putArgStk->getArgSize();
489         for (GenTreeFieldList* current = fieldList; current != nullptr; current = current->Rest())
490         {
491             GenTree* const  fieldNode   = current->Current();
492             const var_types fieldType   = fieldNode->TypeGet();
493             const unsigned  fieldOffset = current->gtFieldOffset;
494             assert(fieldType != TYP_LONG);
495
496             // We can treat as a slot any field that is stored at a slot boundary, where the previous
497             // field is not in the same slot. (Note that we store the fields in reverse order.)
498             const bool fieldIsSlot = ((fieldOffset % 4) == 0) && ((prevOffset - fieldOffset) >= 4);
499             if (!fieldIsSlot)
500             {
501                 allFieldsAreSlots = false;
502             }
503
504             if (varTypeIsGC(fieldType))
505             {
506                 putArgStk->gtNumberReferenceSlots++;
507             }
508
509             // For x86 we must mark all integral fields as contained or reg-optional, and handle them
510             // accordingly in code generation, since we may have up to 8 fields, which cannot all be in
511             // registers to be consumed atomically by the call.
512             if (varTypeIsIntegralOrI(fieldNode))
513             {
514                 if (fieldNode->OperGet() == GT_LCL_VAR)
515                 {
516                     LclVarDsc* varDsc = &(comp->lvaTable[fieldNode->AsLclVarCommon()->gtLclNum]);
517                     if (!varDsc->lvDoNotEnregister)
518                     {
519                         fieldNode->SetRegOptional();
520                     }
521                     else
522                     {
523                         MakeSrcContained(putArgStk, fieldNode);
524                     }
525                 }
526                 else if (fieldNode->IsIntCnsFitsInI32())
527                 {
528                     MakeSrcContained(putArgStk, fieldNode);
529                 }
530                 else
531                 {
532                     // For the case where we cannot directly push the value, if we run out of registers,
533                     // it would be better to defer computation until we are pushing the arguments rather
534                     // than spilling, but this situation is not all that common, as most cases of promoted
535                     // structs do not have a large number of fields, and of those most are lclVars or
536                     // copy-propagated constants.
537                     fieldNode->SetRegOptional();
538                 }
539             }
540
541             prevOffset = fieldOffset;
542         }
543
544         // Set the copy kind.
545         // TODO-X86-CQ: Even if we are using push, if there are contiguous floating point fields, we should
546         // adjust the stack once for those fields. The latter is really best done in code generation, but
547         // this tuning should probably be undertaken as a whole.
548         // Also, if there are  floating point fields, it may be better to use the "Unroll" mode
549         // of copying the struct as a whole, if the fields are not register candidates.
550         if (allFieldsAreSlots)
551         {
552             putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::PushAllSlots;
553         }
554         else
555         {
556             putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Push;
557         }
558         return;
559     }
560 #endif // _TARGET_X86_
561
562     GenTree* src = putArgStk->gtOp1;
563
564 #ifdef FEATURE_PUT_STRUCT_ARG_STK
565     if (src->TypeGet() != TYP_STRUCT)
566 #endif // FEATURE_PUT_STRUCT_ARG_STK
567     {
568         // If the child of GT_PUTARG_STK is a constant, we don't need a register to
569         // move it to memory (stack location).
570         //
571         // On AMD64, we don't want to make 0 contained, because we can generate smaller code
572         // by zeroing a register and then storing it. E.g.:
573         //      xor rdx, rdx
574         //      mov gword ptr [rsp+28H], rdx
575         // is 2 bytes smaller than:
576         //      mov gword ptr [rsp+28H], 0
577         //
578         // On x86, we push stack arguments; we don't use 'mov'. So:
579         //      push 0
580         // is 1 byte smaller than:
581         //      xor rdx, rdx
582         //      push rdx
583
584         if (IsContainableImmed(putArgStk, src)
585 #if defined(_TARGET_AMD64_)
586             && !src->IsIntegralConst(0)
587 #endif // _TARGET_AMD64_
588                 )
589         {
590             MakeSrcContained(putArgStk, src);
591         }
592         return;
593     }
594
595 #ifdef FEATURE_PUT_STRUCT_ARG_STK
596     GenTree* dst     = putArgStk;
597     GenTree* srcAddr = nullptr;
598
599     bool haveLocalAddr = false;
600     if ((src->OperGet() == GT_OBJ) || (src->OperGet() == GT_IND))
601     {
602         srcAddr = src->gtOp.gtOp1;
603         assert(srcAddr != nullptr);
604         haveLocalAddr = srcAddr->OperIsLocalAddr();
605     }
606     else
607     {
608         assert(varTypeIsSIMD(putArgStk));
609     }
610
611     // In case of a CpBlk we could use a helper call. In case of putarg_stk we
612     // can't do that since the helper call could kill some already set up outgoing args.
613     // TODO-Amd64-Unix: converge the code for putarg_stk with cpyblk/cpyobj.
614     // The cpyXXXX code is rather complex and this could cause it to be more complex, but
615     // it might be the right thing to do.
616
617     // This threshold will decide from using the helper or let the JIT decide to inline
618     // a code sequence of its choice.
619     ssize_t helperThreshold = max(CPBLK_MOVS_LIMIT, CPBLK_UNROLL_LIMIT);
620     ssize_t size            = putArgStk->gtNumSlots * TARGET_POINTER_SIZE;
621
622     // TODO-X86-CQ: The helper call either is not supported on x86 or required more work
623     // (I don't know which).
624
625     // If we have a buffer between XMM_REGSIZE_BYTES and CPBLK_UNROLL_LIMIT bytes, we'll use SSE2.
626     // Structs and buffer with sizes <= CPBLK_UNROLL_LIMIT bytes are occurring in more than 95% of
627     // our framework assemblies, so this is the main code generation scheme we'll use.
628     if (size <= CPBLK_UNROLL_LIMIT && putArgStk->gtNumberReferenceSlots == 0)
629     {
630 #ifdef _TARGET_X86_
631         if (size < XMM_REGSIZE_BYTES)
632         {
633             putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Push;
634         }
635         else
636 #endif // _TARGET_X86_
637         {
638             putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Unroll;
639         }
640     }
641 #ifdef _TARGET_X86_
642     else if (putArgStk->gtNumberReferenceSlots != 0)
643     {
644         // On x86, we must use `push` to store GC references to the stack in order for the emitter to properly update
645         // the function's GC info. These `putargstk` nodes will generate a sequence of `push` instructions.
646         putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Push;
647     }
648 #endif // _TARGET_X86_
649     else
650     {
651         putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::RepInstr;
652     }
653     // Always mark the OBJ and ADDR as contained trees by the putarg_stk. The codegen will deal with this tree.
654     MakeSrcContained(putArgStk, src);
655     if (haveLocalAddr)
656     {
657         // If the source address is the address of a lclVar, make the source address contained to avoid unnecessary
658         // copies.
659         //
660         MakeSrcContained(putArgStk, srcAddr);
661     }
662 #endif // FEATURE_PUT_STRUCT_ARG_STK
663 }
664
665 /* Lower GT_CAST(srcType, DstType) nodes.
666  *
667  * Casts from small int type to float/double are transformed as follows:
668  * GT_CAST(byte, float/double)     =   GT_CAST(GT_CAST(byte, int32), float/double)
669  * GT_CAST(sbyte, float/double)    =   GT_CAST(GT_CAST(sbyte, int32), float/double)
670  * GT_CAST(int16, float/double)    =   GT_CAST(GT_CAST(int16, int32), float/double)
671  * GT_CAST(uint16, float/double)   =   GT_CAST(GT_CAST(uint16, int32), float/double)
672  *
673  * SSE2 conversion instructions operate on signed integers. casts from Uint32/Uint64
674  * are morphed as follows by front-end and hence should not be seen here.
675  * GT_CAST(uint32, float/double)   =   GT_CAST(GT_CAST(uint32, long), float/double)
676  * GT_CAST(uint64, float)          =   GT_CAST(GT_CAST(uint64, double), float)
677  *
678  *
679  * Similarly casts from float/double to a smaller int type are transformed as follows:
680  * GT_CAST(float/double, byte)     =   GT_CAST(GT_CAST(float/double, int32), byte)
681  * GT_CAST(float/double, sbyte)    =   GT_CAST(GT_CAST(float/double, int32), sbyte)
682  * GT_CAST(float/double, int16)    =   GT_CAST(GT_CAST(double/double, int32), int16)
683  * GT_CAST(float/double, uint16)   =   GT_CAST(GT_CAST(double/double, int32), uint16)
684  *
685  * SSE2 has instructions to convert a float/double vlaue into a signed 32/64-bit
686  * integer.  The above transformations help us to leverage those instructions.
687  *
688  * Note that for the following conversions we still depend on helper calls and
689  * don't expect to see them here.
690  *  i) GT_CAST(float/double, uint64)
691  * ii) GT_CAST(float/double, int type with overflow detection)
692  *
693  * TODO-XArch-CQ: (Low-pri): Jit64 generates in-line code of 8 instructions for (i) above.
694  * There are hardly any occurrences of this conversion operation in platform
695  * assemblies or in CQ perf benchmarks (1 occurrence in mscorlib, microsoft.jscript,
696  * 1 occurence in Roslyn and no occurrences in system, system.core, system.numerics
697  * system.windows.forms, scimark, fractals, bio mums). If we ever find evidence that
698  * doing this optimization is a win, should consider generating in-lined code.
699  */
700 void Lowering::LowerCast(GenTree* tree)
701 {
702     assert(tree->OperGet() == GT_CAST);
703
704     GenTree*  castOp     = tree->gtCast.CastOp();
705     var_types castToType = tree->CastToType();
706     var_types srcType    = castOp->TypeGet();
707     var_types tmpType    = TYP_UNDEF;
708
709     // force the srcType to unsigned if GT_UNSIGNED flag is set
710     if (tree->gtFlags & GTF_UNSIGNED)
711     {
712         srcType = genUnsignedType(srcType);
713     }
714
715     // We should never see the following casts as they are expected to be lowered
716     // apropriately or converted into helper calls by front-end.
717     //   srcType = float/double                    castToType = * and overflow detecting cast
718     //       Reason: must be converted to a helper call
719     //   srcType = float/double,                   castToType = ulong
720     //       Reason: must be converted to a helper call
721     //   srcType = uint                            castToType = float/double
722     //       Reason: uint -> float/double = uint -> long -> float/double
723     //   srcType = ulong                           castToType = float
724     //       Reason: ulong -> float = ulong -> double -> float
725     if (varTypeIsFloating(srcType))
726     {
727         noway_assert(!tree->gtOverflow());
728         noway_assert(castToType != TYP_ULONG);
729     }
730     else if (srcType == TYP_UINT)
731     {
732         noway_assert(!varTypeIsFloating(castToType));
733     }
734     else if (srcType == TYP_ULONG)
735     {
736         noway_assert(castToType != TYP_FLOAT);
737     }
738
739     // Case of src is a small type and dst is a floating point type.
740     if (varTypeIsSmall(srcType) && varTypeIsFloating(castToType))
741     {
742         // These conversions can never be overflow detecting ones.
743         noway_assert(!tree->gtOverflow());
744         tmpType = TYP_INT;
745     }
746     // case of src is a floating point type and dst is a small type.
747     else if (varTypeIsFloating(srcType) && varTypeIsSmall(castToType))
748     {
749         tmpType = TYP_INT;
750     }
751
752     if (tmpType != TYP_UNDEF)
753     {
754         GenTree* tmp = comp->gtNewCastNode(tmpType, castOp, tree->IsUnsigned(), tmpType);
755         tmp->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW | GTF_EXCEPT));
756
757         tree->gtFlags &= ~GTF_UNSIGNED;
758         tree->gtOp.gtOp1 = tmp;
759         BlockRange().InsertAfter(castOp, tmp);
760         ContainCheckCast(tmp->AsCast());
761     }
762
763     // Now determine if we have operands that should be contained.
764     ContainCheckCast(tree->AsCast());
765 }
766
767 #ifdef FEATURE_SIMD
768 //----------------------------------------------------------------------------------------------
769 // Lowering::LowerSIMD: Perform containment analysis for a SIMD intrinsic node.
770 //
771 //  Arguments:
772 //     simdNode - The SIMD intrinsic node.
773 //
774 void Lowering::LowerSIMD(GenTreeSIMD* simdNode)
775 {
776     if (simdNode->TypeGet() == TYP_SIMD12)
777     {
778         // GT_SIMD node requiring to produce TYP_SIMD12 in fact
779         // produces a TYP_SIMD16 result
780         simdNode->gtType = TYP_SIMD16;
781     }
782
783     if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
784     {
785         assert(simdNode->gtSIMDBaseType == TYP_FLOAT);
786
787         int   argCount      = 0;
788         int   constArgCount = 0;
789         float constArgValues[4]{0, 0, 0, 0};
790
791         for (GenTreeArgList* list = simdNode->gtGetOp1()->AsArgList(); list != nullptr; list = list->Rest())
792         {
793             GenTree* arg = list->Current();
794
795             assert(arg->TypeGet() == simdNode->gtSIMDBaseType);
796             assert(argCount < _countof(constArgValues));
797
798             if (arg->IsCnsFltOrDbl())
799             {
800                 constArgValues[constArgCount] = static_cast<float>(arg->AsDblCon()->gtDconVal);
801                 constArgCount++;
802             }
803
804             argCount++;
805         }
806
807         if (constArgCount == argCount)
808         {
809             for (GenTreeArgList* list = simdNode->gtGetOp1()->AsArgList(); list != nullptr; list = list->Rest())
810             {
811                 BlockRange().Remove(list->Current());
812             }
813
814             CORINFO_FIELD_HANDLE hnd =
815                 comp->getEmitter()->emitAnyConst(constArgValues, sizeof(constArgValues), emitDataAlignment::Required);
816             GenTree* clsVarAddr = new (comp, GT_CLS_VAR_ADDR) GenTreeClsVar(GT_CLS_VAR_ADDR, TYP_I_IMPL, hnd, nullptr);
817             BlockRange().InsertBefore(simdNode, clsVarAddr);
818             simdNode->ChangeOper(GT_IND);
819             simdNode->gtOp1 = clsVarAddr;
820             ContainCheckIndir(simdNode->AsIndir());
821
822             return;
823         }
824     }
825
826 #ifdef _TARGET_XARCH_
827     if ((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGetItem) && (simdNode->gtGetOp1()->OperGet() == GT_IND))
828     {
829         // If SIMD vector is already in memory, we force its
830         // addr to be evaluated into a reg.  This would allow
831         // us to generate [regBase] or [regBase+offset] or
832         // [regBase+sizeOf(SIMD vector baseType)*regIndex]
833         // to access the required SIMD vector element directly
834         // from memory.
835         //
836         // TODO-CQ-XARCH: If addr of GT_IND is GT_LEA, we
837         // might be able update GT_LEA to fold the regIndex
838         // or offset in some cases.  Instead with this
839         // approach we always evaluate GT_LEA into a reg.
840         // Ideally, we should be able to lower GetItem intrinsic
841         // into GT_IND(newAddr) where newAddr combines
842         // the addr of SIMD vector with the given index.
843         simdNode->gtOp1->gtFlags |= GTF_IND_REQ_ADDR_IN_REG;
844     }
845     else if (simdNode->IsSIMDEqualityOrInequality())
846     {
847         LIR::Use simdUse;
848
849         if (BlockRange().TryGetUse(simdNode, &simdUse))
850         {
851             //
852             // Try to transform JTRUE(EQ|NE(SIMD<OpEquality|OpInEquality>(x, y), 0|1)) into
853             // JCC(SIMD<OpEquality|OpInEquality>(x, y)). SIMD<OpEquality|OpInEquality>(x, y)
854             // is expected to set the Zero flag appropriately.
855             // All the involved nodes must form a continuous range, there's no other way to
856             // guarantee that condition flags aren't changed between the SIMD node and the JCC
857             // node.
858             //
859
860             bool     transformed = false;
861             GenTree* simdUser    = simdUse.User();
862
863             if (simdUser->OperIs(GT_EQ, GT_NE) && simdUser->gtGetOp2()->IsCnsIntOrI() &&
864                 (simdNode->gtNext == simdUser->gtGetOp2()) && (simdUser->gtGetOp2()->gtNext == simdUser))
865             {
866                 ssize_t relopOp2Value = simdUser->gtGetOp2()->AsIntCon()->IconValue();
867
868                 if ((relopOp2Value == 0) || (relopOp2Value == 1))
869                 {
870                     GenTree* jtrue = simdUser->gtNext;
871
872                     if ((jtrue != nullptr) && jtrue->OperIs(GT_JTRUE) && (jtrue->gtGetOp1() == simdUser))
873                     {
874                         if ((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) != simdUser->OperIs(GT_EQ))
875                         {
876                             relopOp2Value ^= 1;
877                         }
878
879                         jtrue->ChangeOper(GT_JCC);
880                         GenTreeCC* jcc = jtrue->AsCC();
881                         jcc->gtFlags |= GTF_USE_FLAGS;
882                         jcc->gtCondition = (relopOp2Value == 0) ? GenCondition::NE : GenCondition::EQ;
883
884                         BlockRange().Remove(simdUser->gtGetOp2());
885                         BlockRange().Remove(simdUser);
886                         transformed = true;
887                     }
888                 }
889             }
890
891             if (!transformed)
892             {
893                 //
894                 // The code generated for SIMD SIMD<OpEquality|OpInEquality>(x, y) nodes sets
895                 // the Zero flag like integer compares do so we can simply use SETCC<EQ|NE>
896                 // to produce the desired result. This avoids the need for subsequent phases
897                 // to have to handle 2 cases (set flags/set destination register).
898                 //
899
900                 GenCondition condition =
901                     (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) ? GenCondition::EQ : GenCondition::NE;
902                 GenTreeCC* setcc = new (comp, GT_SETCC) GenTreeCC(GT_SETCC, condition, simdNode->TypeGet());
903                 setcc->gtFlags |= GTF_USE_FLAGS;
904                 BlockRange().InsertAfter(simdNode, setcc);
905                 simdUse.ReplaceWith(comp, setcc);
906             }
907         }
908
909         simdNode->gtFlags |= GTF_SET_FLAGS;
910         simdNode->gtType = TYP_VOID;
911     }
912 #endif
913     ContainCheckSIMD(simdNode);
914 }
915 #endif // FEATURE_SIMD
916
917 #ifdef FEATURE_HW_INTRINSICS
918 //----------------------------------------------------------------------------------------------
919 // Lowering::LowerHWIntrinsic: Perform containment analysis for a hardware intrinsic node.
920 //
921 //  Arguments:
922 //     node - The hardware intrinsic node.
923 //
924 void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node)
925 {
926     ContainCheckHWIntrinsic(node);
927 }
928 #endif // FEATURE_HW_INTRINSICS
929
930 //----------------------------------------------------------------------------------------------
931 // Lowering::IsRMWIndirCandidate:
932 //    Returns true if the given operand is a candidate indirection for a read-modify-write
933 //    operator.
934 //
935 //  Arguments:
936 //     operand - The operand to consider.
937 //     storeInd - The indirect store that roots the possible RMW operator.
938 //
939 bool Lowering::IsRMWIndirCandidate(GenTree* operand, GenTree* storeInd)
940 {
941     // If the operand isn't an indirection, it's trivially not a candidate.
942     if (operand->OperGet() != GT_IND)
943     {
944         return false;
945     }
946
947     // If the indirection's source address isn't equivalent to the destination address of the storeIndir, then the
948     // indirection is not a candidate.
949     GenTree* srcAddr = operand->gtGetOp1();
950     GenTree* dstAddr = storeInd->gtGetOp1();
951     if ((srcAddr->OperGet() != dstAddr->OperGet()) || !IndirsAreEquivalent(operand, storeInd))
952     {
953         return false;
954     }
955
956     // If it is not safe to contain the entire tree rooted at the indirection, then the indirection is not a
957     // candidate. Crawl the IR from the node immediately preceding the storeIndir until the last node in the
958     // indirection's tree is visited and check the side effects at each point.
959
960     m_scratchSideEffects.Clear();
961
962     assert((operand->gtLIRFlags & LIR::Flags::Mark) == 0);
963     operand->gtLIRFlags |= LIR::Flags::Mark;
964
965     unsigned markCount = 1;
966     GenTree* node;
967     for (node = storeInd->gtPrev; markCount > 0; node = node->gtPrev)
968     {
969         assert(node != nullptr);
970
971         if ((node->gtLIRFlags & LIR::Flags::Mark) == 0)
972         {
973             m_scratchSideEffects.AddNode(comp, node);
974         }
975         else
976         {
977             node->gtLIRFlags &= ~LIR::Flags::Mark;
978             markCount--;
979
980             if (m_scratchSideEffects.InterferesWith(comp, node, false))
981             {
982                 // The indirection's tree contains some node that can't be moved to the storeInder. The indirection is
983                 // not a candidate. Clear any leftover mark bits and return.
984                 for (; markCount > 0; node = node->gtPrev)
985                 {
986                     if ((node->gtLIRFlags & LIR::Flags::Mark) != 0)
987                     {
988                         node->gtLIRFlags &= ~LIR::Flags::Mark;
989                         markCount--;
990                     }
991                 }
992                 return false;
993             }
994
995             node->VisitOperands([&markCount](GenTree* nodeOperand) -> GenTree::VisitResult {
996                 assert((nodeOperand->gtLIRFlags & LIR::Flags::Mark) == 0);
997                 nodeOperand->gtLIRFlags |= LIR::Flags::Mark;
998                 markCount++;
999                 return GenTree::VisitResult::Continue;
1000             });
1001         }
1002     }
1003
1004     // At this point we've verified that the operand is an indirection, its address is equivalent to the storeIndir's
1005     // destination address, and that it and the transitive closure of its operand can be safely contained by the
1006     // storeIndir. This indirection is therefore a candidate for an RMW op.
1007     return true;
1008 }
1009
1010 //----------------------------------------------------------------------------------------------
1011 // Returns true if this tree is bin-op of a GT_STOREIND of the following form
1012 //      storeInd(subTreeA, binOp(gtInd(subTreeA), subtreeB)) or
1013 //      storeInd(subTreeA, binOp(subtreeB, gtInd(subTreeA)) in case of commutative bin-ops
1014 //
1015 // The above form for storeInd represents a read-modify-write memory binary operation.
1016 //
1017 // Parameters
1018 //     tree   -   GentreePtr of binOp
1019 //
1020 // Return Value
1021 //     True if 'tree' is part of a RMW memory operation pattern
1022 //
1023 bool Lowering::IsBinOpInRMWStoreInd(GenTree* tree)
1024 {
1025     // Must be a non floating-point type binary operator since SSE2 doesn't support RMW memory ops
1026     assert(!varTypeIsFloating(tree));
1027     assert(GenTree::OperIsBinary(tree->OperGet()));
1028
1029     // Cheap bail out check before more expensive checks are performed.
1030     // RMW memory op pattern requires that one of the operands of binOp to be GT_IND.
1031     if (tree->gtGetOp1()->OperGet() != GT_IND && tree->gtGetOp2()->OperGet() != GT_IND)
1032     {
1033         return false;
1034     }
1035
1036     LIR::Use use;
1037     if (!BlockRange().TryGetUse(tree, &use) || use.User()->OperGet() != GT_STOREIND || use.User()->gtGetOp2() != tree)
1038     {
1039         return false;
1040     }
1041
1042     // Since it is not relatively cheap to recognize RMW memory op pattern, we
1043     // cache the result in GT_STOREIND node so that while lowering GT_STOREIND
1044     // we can use the result.
1045     GenTree* indirCandidate = nullptr;
1046     GenTree* indirOpSource  = nullptr;
1047     return IsRMWMemOpRootedAtStoreInd(use.User(), &indirCandidate, &indirOpSource);
1048 }
1049
1050 //----------------------------------------------------------------------------------------------
1051 // This method recognizes the case where we have a treeNode with the following structure:
1052 //         storeInd(IndirDst, binOp(gtInd(IndirDst), indirOpSource)) OR
1053 //         storeInd(IndirDst, binOp(indirOpSource, gtInd(IndirDst)) in case of commutative operations OR
1054 //         storeInd(IndirDst, unaryOp(gtInd(IndirDst)) in case of unary operations
1055 //
1056 // Terminology:
1057 //         indirDst = memory write of an addr mode  (i.e. storeind destination)
1058 //         indirSrc = value being written to memory (i.e. storeind source which could either be a binary or unary op)
1059 //         indirCandidate = memory read i.e. a gtInd of an addr mode
1060 //         indirOpSource = source operand used in binary/unary op (i.e. source operand of indirSrc node)
1061 //
1062 // In x86/x64 this storeInd pattern can be effectively encoded in a single instruction of the
1063 // following form in case of integer operations:
1064 //         binOp [addressing mode], RegIndirOpSource
1065 //         binOp [addressing mode], immediateVal
1066 // where RegIndirOpSource is the register where indirOpSource was computed.
1067 //
1068 // Right now, we recognize few cases:
1069 //     a) The gtInd child is a lea/lclVar/lclVarAddr/clsVarAddr/constant
1070 //     b) BinOp is either add, sub, xor, or, and, shl, rsh, rsz.
1071 //     c) unaryOp is either not/neg
1072 //
1073 // Implementation Note: The following routines need to be in sync for RMW memory op optimization
1074 // to be correct and functional.
1075 //     IndirsAreEquivalent()
1076 //     NodesAreEquivalentLeaves()
1077 //     Codegen of GT_STOREIND and genCodeForShiftRMW()
1078 //     emitInsRMW()
1079 //
1080 //  TODO-CQ: Enable support for more complex indirections (if needed) or use the value numbering
1081 //  package to perform more complex tree recognition.
1082 //
1083 //  TODO-XArch-CQ: Add support for RMW of lcl fields (e.g. lclfield binop= source)
1084 //
1085 //  Parameters:
1086 //     tree               -  GT_STOREIND node
1087 //     outIndirCandidate  -  out param set to indirCandidate as described above
1088 //     ouutIndirOpSource  -  out param set to indirOpSource as described above
1089 //
1090 //  Return value
1091 //     True if there is a RMW memory operation rooted at a GT_STOREIND tree
1092 //     and out params indirCandidate and indirOpSource are set to non-null values.
1093 //     Otherwise, returns false with indirCandidate and indirOpSource set to null.
1094 //     Also updates flags of GT_STOREIND tree with its RMW status.
1095 //
1096 bool Lowering::IsRMWMemOpRootedAtStoreInd(GenTree* tree, GenTree** outIndirCandidate, GenTree** outIndirOpSource)
1097 {
1098     assert(!varTypeIsFloating(tree));
1099     assert(outIndirCandidate != nullptr);
1100     assert(outIndirOpSource != nullptr);
1101
1102     *outIndirCandidate = nullptr;
1103     *outIndirOpSource  = nullptr;
1104
1105     // Early out if storeInd is already known to be a non-RMW memory op
1106     GenTreeStoreInd* storeInd = tree->AsStoreInd();
1107     if (storeInd->IsNonRMWMemoryOp())
1108     {
1109         return false;
1110     }
1111
1112     GenTree*   indirDst = storeInd->gtGetOp1();
1113     GenTree*   indirSrc = storeInd->gtGetOp2();
1114     genTreeOps oper     = indirSrc->OperGet();
1115
1116     // Early out if it is already known to be a RMW memory op
1117     if (storeInd->IsRMWMemoryOp())
1118     {
1119         if (GenTree::OperIsBinary(oper))
1120         {
1121             if (storeInd->IsRMWDstOp1())
1122             {
1123                 *outIndirCandidate = indirSrc->gtGetOp1();
1124                 *outIndirOpSource  = indirSrc->gtGetOp2();
1125             }
1126             else
1127             {
1128                 assert(storeInd->IsRMWDstOp2());
1129                 *outIndirCandidate = indirSrc->gtGetOp2();
1130                 *outIndirOpSource  = indirSrc->gtGetOp1();
1131             }
1132             assert(IndirsAreEquivalent(*outIndirCandidate, storeInd));
1133         }
1134         else
1135         {
1136             assert(GenTree::OperIsUnary(oper));
1137             assert(IndirsAreEquivalent(indirSrc->gtGetOp1(), storeInd));
1138             *outIndirCandidate = indirSrc->gtGetOp1();
1139             *outIndirOpSource  = indirSrc->gtGetOp1();
1140         }
1141
1142         return true;
1143     }
1144
1145     // If reached here means that we do not know RMW status of tree rooted at storeInd
1146     assert(storeInd->IsRMWStatusUnknown());
1147
1148     // Early out if indirDst is not one of the supported memory operands.
1149     if (indirDst->OperGet() != GT_LEA && indirDst->OperGet() != GT_LCL_VAR && indirDst->OperGet() != GT_LCL_VAR_ADDR &&
1150         indirDst->OperGet() != GT_CLS_VAR_ADDR && indirDst->OperGet() != GT_CNS_INT)
1151     {
1152         storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_ADDR);
1153         return false;
1154     }
1155
1156     // We can not use Read-Modify-Write instruction forms with overflow checking instructions
1157     // because we are not allowed to modify the target until after the overflow check.
1158     if (indirSrc->gtOverflowEx())
1159     {
1160         storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_OPER);
1161         return false;
1162     }
1163
1164     // At this point we can match one of two patterns:
1165     //
1166     //     t_ind = indir t_addr_0
1167     //       ...
1168     //     t_value = binop t_ind, t_other
1169     //       ...
1170     //     storeIndir t_addr_1, t_value
1171     //
1172     // or
1173     //
1174     //     t_ind = indir t_addr_0
1175     //       ...
1176     //     t_value = unop t_ind
1177     //       ...
1178     //     storeIndir t_addr_1, t_value
1179     //
1180     // In all cases, we will eventually make the binop that produces t_value and the entire dataflow tree rooted at
1181     // t_ind contained by t_value.
1182
1183     GenTree*  indirCandidate = nullptr;
1184     GenTree*  indirOpSource  = nullptr;
1185     RMWStatus status         = STOREIND_RMW_STATUS_UNKNOWN;
1186     if (GenTree::OperIsBinary(oper))
1187     {
1188         // Return if binary op is not one of the supported operations for RMW of memory.
1189         if (!GenTree::OperIsRMWMemOp(oper))
1190         {
1191             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_OPER);
1192             return false;
1193         }
1194
1195         if (GenTree::OperIsShiftOrRotate(oper) && varTypeIsSmall(storeInd))
1196         {
1197             // In ldind, Integer values smaller than 4 bytes, a boolean, or a character converted to 4 bytes
1198             // by sign or zero-extension as appropriate. If we directly shift the short type data using sar, we
1199             // will lose the sign or zero-extension bits.
1200             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_TYPE);
1201             return false;
1202         }
1203
1204         // In the common case, the second operand to the binop will be the indir candidate.
1205         GenTreeOp* binOp = indirSrc->AsOp();
1206         if (GenTree::OperIsCommutative(oper) && IsRMWIndirCandidate(binOp->gtOp2, storeInd))
1207         {
1208             indirCandidate = binOp->gtOp2;
1209             indirOpSource  = binOp->gtOp1;
1210             status         = STOREIND_RMW_DST_IS_OP2;
1211         }
1212         else if (IsRMWIndirCandidate(binOp->gtOp1, storeInd))
1213         {
1214             indirCandidate = binOp->gtOp1;
1215             indirOpSource  = binOp->gtOp2;
1216             status         = STOREIND_RMW_DST_IS_OP1;
1217         }
1218         else
1219         {
1220             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_ADDR);
1221             return false;
1222         }
1223     }
1224     else if (GenTree::OperIsUnary(oper))
1225     {
1226         // Nodes other than GT_NOT and GT_NEG are not yet supported.
1227         if (oper != GT_NOT && oper != GT_NEG)
1228         {
1229             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_OPER);
1230             return false;
1231         }
1232
1233         if (indirSrc->gtGetOp1()->OperGet() != GT_IND)
1234         {
1235             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_ADDR);
1236             return false;
1237         }
1238
1239         GenTreeUnOp* unOp = indirSrc->AsUnOp();
1240         if (IsRMWIndirCandidate(unOp->gtOp1, storeInd))
1241         {
1242             // src and dest are the same in case of unary ops
1243             indirCandidate = unOp->gtOp1;
1244             indirOpSource  = unOp->gtOp1;
1245             status         = STOREIND_RMW_DST_IS_OP1;
1246         }
1247         else
1248         {
1249             storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_ADDR);
1250             return false;
1251         }
1252     }
1253     else
1254     {
1255         storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_OPER);
1256         return false;
1257     }
1258
1259     // By this point we've verified that we have a supported operand with a supported address. Now we need to ensure
1260     // that we're able to move the destination address for the source indirection forwards.
1261     if (!IsSafeToContainMem(storeInd, indirDst))
1262     {
1263         storeInd->SetRMWStatus(STOREIND_RMW_UNSUPPORTED_ADDR);
1264         return false;
1265     }
1266
1267     assert(indirCandidate != nullptr);
1268     assert(indirOpSource != nullptr);
1269     assert(status != STOREIND_RMW_STATUS_UNKNOWN);
1270
1271     *outIndirCandidate = indirCandidate;
1272     *outIndirOpSource  = indirOpSource;
1273     storeInd->SetRMWStatus(status);
1274     return true;
1275 }
1276
1277 // anything is in range for AMD64
1278 bool Lowering::IsCallTargetInRange(void* addr)
1279 {
1280     return true;
1281 }
1282
1283 // return true if the immediate can be folded into an instruction, for example small enough and non-relocatable
1284 bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode)
1285 {
1286     if (!childNode->IsIntCnsFitsInI32())
1287     {
1288         return false;
1289     }
1290
1291     // At this point we know that it is an int const fits within 4-bytes and hence can safely cast to IntConCommon.
1292     // Icons that need relocation should never be marked as contained immed
1293     if (childNode->AsIntConCommon()->ImmedValNeedsReloc(comp))
1294     {
1295         return false;
1296     }
1297
1298     return true;
1299 }
1300
1301 //-----------------------------------------------------------------------
1302 // PreferredRegOptionalOperand: returns one of the operands of given
1303 // binary oper that is to be preferred for marking as reg optional.
1304 //
1305 // Since only one of op1 or op2 can be a memory operand on xarch, only
1306 // one of  them have to be marked as reg optional.  Since Lower doesn't
1307 // know apriori which of op1 or op2 is not likely to get a register, it
1308 // has to make a guess. This routine encapsulates heuristics that
1309 // guess whether it is likely to be beneficial to mark op1 or op2 as
1310 // reg optional.
1311 //
1312 //
1313 // Arguments:
1314 //     tree  -  a binary-op tree node that is either commutative
1315 //              or a compare oper.
1316 //
1317 // Returns:
1318 //     Returns op1 or op2 of tree node that is preferred for
1319 //     marking as reg optional.
1320 //
1321 // Note: if the tree oper is neither commutative nor a compare oper
1322 // then only op2 can be reg optional on xarch and hence no need to
1323 // call this routine.
1324 GenTree* Lowering::PreferredRegOptionalOperand(GenTree* tree)
1325 {
1326     assert(GenTree::OperIsBinary(tree->OperGet()));
1327     assert(tree->OperIsCommutative() || tree->OperIsCompare() || tree->OperIs(GT_CMP));
1328
1329     GenTree* op1 = tree->gtGetOp1();
1330     GenTree* op2 = tree->gtGetOp2();
1331     assert(!op1->IsRegOptional() && !op2->IsRegOptional());
1332
1333     // We default to op1, as op2 is likely to have the shorter lifetime.
1334     GenTree* preferredOp = op1;
1335
1336     // This routine uses the following heuristics:
1337     //
1338     // a) If both are register candidates, marking the one with lower weighted
1339     // ref count as reg-optional would likely be beneficial as it has
1340     // higher probability of not getting a register. Note that we use !lvDoNotEnregister
1341     // here because this is being done while we are adding lclVars for Lowering.
1342     //
1343     // b) op1 = tracked local and op2 = untracked local: LSRA creates two
1344     // ref positions for op2: a def and use position. op2's def position
1345     // requires a reg and it is allocated a reg by spilling another
1346     // interval (if required) and that could be even op1.  For this reason
1347     // it is beneficial to mark op1 as reg optional.
1348     //
1349     // TODO: It is not always mandatory for a def position of an untracked
1350     // local to be allocated a register if it is on rhs of an assignment
1351     // and its use position is reg-optional and has not been assigned a
1352     // register.  Reg optional def positions is currently not yet supported.
1353     //
1354     // c) op1 = untracked local and op2 = tracked local: marking op1 as
1355     // reg optional is beneficial, since its use position is less likely
1356     // to get a register.
1357     //
1358     // d) If both are untracked locals (i.e. treated like tree temps by
1359     // LSRA): though either of them could be marked as reg optional,
1360     // marking op1 as reg optional is likely to be beneficial because
1361     // while allocating op2's def position, there is a possibility of
1362     // spilling op1's def and in which case op1 is treated as contained
1363     // memory operand rather than requiring to reload.
1364     //
1365     // e) If only one of them is a local var, prefer to mark it as
1366     // reg-optional.  This is heuristic is based on the results
1367     // obtained against CQ perf benchmarks.
1368     //
1369     // f) If neither of them are local vars (i.e. tree temps), prefer to
1370     // mark op1 as reg optional for the same reason as mentioned in (d) above.
1371     if (op1->OperGet() == GT_LCL_VAR && op2->OperGet() == GT_LCL_VAR)
1372     {
1373         LclVarDsc* v1 = comp->lvaTable + op1->AsLclVarCommon()->GetLclNum();
1374         LclVarDsc* v2 = comp->lvaTable + op2->AsLclVarCommon()->GetLclNum();
1375
1376         bool v1IsRegCandidate = !v1->lvDoNotEnregister;
1377         bool v2IsRegCandidate = !v2->lvDoNotEnregister;
1378         if (v1IsRegCandidate && v2IsRegCandidate)
1379         {
1380             // Both are enregisterable locals.  The one with lower weight is less likely
1381             // to get a register and hence beneficial to mark the one with lower
1382             // weight as reg optional.
1383             // If either is not tracked, it may be that it was introduced after liveness
1384             // was run, in which case we will always prefer op1 (should we use raw refcnt??).
1385             if (v1->lvTracked && v2->lvTracked && (v1->lvRefCntWtd() >= v2->lvRefCntWtd()))
1386             {
1387                 preferredOp = op2;
1388             }
1389         }
1390     }
1391     else if (!(op1->OperGet() == GT_LCL_VAR) && (op2->OperGet() == GT_LCL_VAR))
1392     {
1393         preferredOp = op2;
1394     }
1395
1396     return preferredOp;
1397 }
1398
1399 //------------------------------------------------------------------------
1400 // Containment analysis
1401 //------------------------------------------------------------------------
1402
1403 //------------------------------------------------------------------------
1404 // ContainCheckCallOperands: Determine whether operands of a call should be contained.
1405 //
1406 // Arguments:
1407 //    call       - The call node of interest
1408 //
1409 // Return Value:
1410 //    None.
1411 //
1412 void Lowering::ContainCheckCallOperands(GenTreeCall* call)
1413 {
1414     GenTree* ctrlExpr = call->gtControlExpr;
1415     if (call->gtCallType == CT_INDIRECT)
1416     {
1417         // either gtControlExpr != null or gtCallAddr != null.
1418         // Both cannot be non-null at the same time.
1419         assert(ctrlExpr == nullptr);
1420         assert(call->gtCallAddr != nullptr);
1421         ctrlExpr = call->gtCallAddr;
1422
1423 #ifdef _TARGET_X86_
1424         // Fast tail calls aren't currently supported on x86, but if they ever are, the code
1425         // below that handles indirect VSD calls will need to be fixed.
1426         assert(!call->IsFastTailCall() || !call->IsVirtualStub());
1427 #endif // _TARGET_X86_
1428     }
1429
1430     // set reg requirements on call target represented as control sequence.
1431     if (ctrlExpr != nullptr)
1432     {
1433         // we should never see a gtControlExpr whose type is void.
1434         assert(ctrlExpr->TypeGet() != TYP_VOID);
1435
1436         // In case of fast tail implemented as jmp, make sure that gtControlExpr is
1437         // computed into a register.
1438         if (!call->IsFastTailCall())
1439         {
1440 #ifdef _TARGET_X86_
1441             // On x86, we need to generate a very specific pattern for indirect VSD calls:
1442             //
1443             //    3-byte nop
1444             //    call dword ptr [eax]
1445             //
1446             // Where EAX is also used as an argument to the stub dispatch helper. Make
1447             // sure that the call target address is computed into EAX in this case.
1448             if (call->IsVirtualStub() && (call->gtCallType == CT_INDIRECT))
1449             {
1450                 assert(ctrlExpr->isIndir());
1451                 MakeSrcContained(call, ctrlExpr);
1452             }
1453             else
1454 #endif // _TARGET_X86_
1455                 if (ctrlExpr->isIndir())
1456             {
1457                 // We may have cases where we have set a register target on the ctrlExpr, but if it
1458                 // contained we must clear it.
1459                 ctrlExpr->gtRegNum = REG_NA;
1460                 MakeSrcContained(call, ctrlExpr);
1461             }
1462         }
1463     }
1464
1465     GenTree* args = call->gtCallArgs;
1466     while (args)
1467     {
1468         GenTree* arg = args->gtOp.gtOp1;
1469         if (arg->gtOper == GT_PUTARG_STK)
1470         {
1471             LowerPutArgStk(arg->AsPutArgStk());
1472         }
1473         args = args->gtOp.gtOp2;
1474     }
1475     args = call->gtCallLateArgs;
1476     while (args)
1477     {
1478         GenTree* arg = args->gtOp.gtOp1;
1479         if (arg->gtOper == GT_PUTARG_STK)
1480         {
1481             LowerPutArgStk(arg->AsPutArgStk());
1482         }
1483         args = args->gtOp.gtOp2;
1484     }
1485 }
1486
1487 //------------------------------------------------------------------------
1488 // ContainCheckIndir: Determine whether operands of an indir should be contained.
1489 //
1490 // Arguments:
1491 //    node       - The indirection node of interest
1492 //
1493 // Notes:
1494 //    This is called for both store and load indirections. In the former case, it is assumed that
1495 //    LowerStoreIndir() has already been called to check for RMW opportunities.
1496 //
1497 // Return Value:
1498 //    None.
1499 //
1500 void Lowering::ContainCheckIndir(GenTreeIndir* node)
1501 {
1502     GenTree* addr = node->Addr();
1503
1504     // If this is the rhs of a block copy it will be handled when we handle the store.
1505     if (node->TypeGet() == TYP_STRUCT)
1506     {
1507         return;
1508     }
1509
1510 #ifdef FEATURE_SIMD
1511     // If indirTree is of TYP_SIMD12, don't mark addr as contained
1512     // so that it always get computed to a register.  This would
1513     // mean codegen side logic doesn't need to handle all possible
1514     // addr expressions that could be contained.
1515     //
1516     // TODO-XArch-CQ: handle other addr mode expressions that could be marked
1517     // as contained.
1518     if (node->TypeGet() == TYP_SIMD12)
1519     {
1520         return;
1521     }
1522 #endif // FEATURE_SIMD
1523
1524     if ((node->gtFlags & GTF_IND_REQ_ADDR_IN_REG) != 0)
1525     {
1526         // The address of an indirection that requires its address in a reg.
1527         // Skip any further processing that might otherwise make it contained.
1528     }
1529     else if ((addr->OperGet() == GT_CLS_VAR_ADDR) || (addr->OperGet() == GT_LCL_VAR_ADDR))
1530     {
1531         // These nodes go into an addr mode:
1532         // - GT_CLS_VAR_ADDR turns into a constant.
1533         // - GT_LCL_VAR_ADDR is a stack addr mode.
1534
1535         // make this contained, it turns into a constant that goes into an addr mode
1536         MakeSrcContained(node, addr);
1537     }
1538     else if (addr->IsCnsIntOrI() && addr->AsIntConCommon()->FitsInAddrBase(comp))
1539     {
1540         // Amd64:
1541         // We can mark any pc-relative 32-bit addr as containable, except for a direct VSD call address.
1542         // (i.e. those VSD calls for which stub addr is known during JIT compilation time).  In this case,
1543         // VM requires us to pass stub addr in VirtualStubParam.reg - see LowerVirtualStubCall().  For
1544         // that reason we cannot mark such an addr as contained.  Note that this is not an issue for
1545         // indirect VSD calls since morphArgs() is explicitly materializing hidden param as a non-standard
1546         // argument.
1547         //
1548         // Workaround:
1549         // Note that LowerVirtualStubCall() sets addr->gtRegNum to VirtualStubParam.reg and Lowering::doPhase()
1550         // sets destination candidates on such nodes and resets addr->gtRegNum to REG_NA.
1551         // Ideally we should set a flag on addr nodes that shouldn't be marked as contained
1552         // (in LowerVirtualStubCall()), but we don't have any GTF_* flags left for that purpose.  As a workaround
1553         // an explicit check is made here.
1554         //
1555         // On x86, direct VSD is done via a relative branch, and in fact it MUST be contained.
1556         MakeSrcContained(node, addr);
1557     }
1558     else if ((addr->OperGet() == GT_LEA) && IsSafeToContainMem(node, addr))
1559     {
1560         MakeSrcContained(node, addr);
1561     }
1562 }
1563
1564 //------------------------------------------------------------------------
1565 // ContainCheckStoreIndir: determine whether the sources of a STOREIND node should be contained.
1566 //
1567 // Arguments:
1568 //    node - pointer to the node
1569 //
1570 void Lowering::ContainCheckStoreIndir(GenTreeIndir* node)
1571 {
1572     // If the source is a containable immediate, make it contained, unless it is
1573     // an int-size or larger store of zero to memory, because we can generate smaller code
1574     // by zeroing a register and then storing it.
1575     GenTree* src = node->gtOp.gtOp2;
1576     if (IsContainableImmed(node, src) &&
1577         (!src->IsIntegralConst(0) || varTypeIsSmall(node) || node->gtGetOp1()->OperGet() == GT_CLS_VAR_ADDR))
1578     {
1579         MakeSrcContained(node, src);
1580     }
1581     ContainCheckIndir(node);
1582 }
1583
1584 //------------------------------------------------------------------------
1585 // ContainCheckMul: determine whether the sources of a MUL node should be contained.
1586 //
1587 // Arguments:
1588 //    node - pointer to the node
1589 //
1590 void Lowering::ContainCheckMul(GenTreeOp* node)
1591 {
1592 #if defined(_TARGET_X86_)
1593     assert(node->OperIs(GT_MUL, GT_MULHI, GT_MUL_LONG));
1594 #else
1595     assert(node->OperIs(GT_MUL, GT_MULHI));
1596 #endif
1597
1598     // Case of float/double mul.
1599     if (varTypeIsFloating(node->TypeGet()))
1600     {
1601         ContainCheckFloatBinary(node);
1602         return;
1603     }
1604
1605     GenTree* op1 = node->gtOp.gtOp1;
1606     GenTree* op2 = node->gtOp.gtOp2;
1607
1608     bool isSafeToContainOp1 = true;
1609     bool isSafeToContainOp2 = true;
1610
1611     bool     isUnsignedMultiply    = ((node->gtFlags & GTF_UNSIGNED) != 0);
1612     bool     requiresOverflowCheck = node->gtOverflowEx();
1613     bool     useLeaEncoding        = false;
1614     GenTree* memOp                 = nullptr;
1615
1616     bool                 hasImpliedFirstOperand = false;
1617     GenTreeIntConCommon* imm                    = nullptr;
1618     GenTree*             other                  = nullptr;
1619
1620     // Multiply should never be using small types
1621     assert(!varTypeIsSmall(node->TypeGet()));
1622
1623     // We do use the widening multiply to implement
1624     // the overflow checking for unsigned multiply
1625     //
1626     if (isUnsignedMultiply && requiresOverflowCheck)
1627     {
1628         hasImpliedFirstOperand = true;
1629     }
1630     else if (node->OperGet() == GT_MULHI)
1631     {
1632         hasImpliedFirstOperand = true;
1633     }
1634 #if defined(_TARGET_X86_)
1635     else if (node->OperGet() == GT_MUL_LONG)
1636     {
1637         hasImpliedFirstOperand = true;
1638     }
1639 #endif
1640     else if (IsContainableImmed(node, op2) || IsContainableImmed(node, op1))
1641     {
1642         if (IsContainableImmed(node, op2))
1643         {
1644             imm   = op2->AsIntConCommon();
1645             other = op1;
1646         }
1647         else
1648         {
1649             imm   = op1->AsIntConCommon();
1650             other = op2;
1651         }
1652
1653         // CQ: We want to rewrite this into a LEA
1654         ssize_t immVal = imm->AsIntConCommon()->IconValue();
1655         if (!requiresOverflowCheck && (immVal == 3 || immVal == 5 || immVal == 9))
1656         {
1657             useLeaEncoding = true;
1658         }
1659
1660         MakeSrcContained(node, imm); // The imm is always contained
1661         if (IsContainableMemoryOp(other))
1662         {
1663             memOp = other; // memOp may be contained below
1664         }
1665     }
1666
1667     // We allow one operand to be a contained memory operand.
1668     // The memory op type must match with the 'node' type.
1669     // This is because during codegen we use 'node' type to derive EmitTypeSize.
1670     // E.g op1 type = byte, op2 type = byte but GT_MUL node type is int.
1671     //
1672     if (memOp == nullptr)
1673     {
1674         if ((op2->TypeGet() == node->TypeGet()) && IsContainableMemoryOp(op2))
1675         {
1676             isSafeToContainOp2 = IsSafeToContainMem(node, op2);
1677             if (isSafeToContainOp2)
1678             {
1679                 memOp = op2;
1680             }
1681         }
1682
1683         if ((memOp == nullptr) && (op1->TypeGet() == node->TypeGet()) && IsContainableMemoryOp(op1))
1684         {
1685             isSafeToContainOp1 = IsSafeToContainMem(node, op1);
1686             if (isSafeToContainOp1)
1687             {
1688                 memOp = op1;
1689             }
1690         }
1691     }
1692     else
1693     {
1694         if ((memOp->TypeGet() != node->TypeGet()))
1695         {
1696             memOp = nullptr;
1697         }
1698         else if (!IsSafeToContainMem(node, memOp))
1699         {
1700             if (memOp == op1)
1701             {
1702                 isSafeToContainOp1 = false;
1703             }
1704             else
1705             {
1706                 isSafeToContainOp2 = false;
1707             }
1708             memOp = nullptr;
1709         }
1710     }
1711     // To generate an LEA we need to force memOp into a register
1712     // so don't allow memOp to be 'contained'
1713     //
1714     if (!useLeaEncoding)
1715     {
1716         if (memOp != nullptr)
1717         {
1718             MakeSrcContained(node, memOp);
1719         }
1720         else
1721         {
1722             // IsSafeToContainMem is expensive so we call it at most once for each operand
1723             // in this method. If we already called IsSafeToContainMem, it must have returned false;
1724             // otherwise, memOp would be set to the corresponding operand (op1 or op2).
1725             if (imm != nullptr)
1726             {
1727                 // Has a contained immediate operand.
1728                 // Only 'other' operand can be marked as reg optional.
1729                 assert(other != nullptr);
1730
1731                 isSafeToContainOp1 = ((other == op1) && isSafeToContainOp1 && IsSafeToContainMem(node, op1));
1732                 isSafeToContainOp2 = ((other == op2) && isSafeToContainOp2 && IsSafeToContainMem(node, op2));
1733             }
1734             else if (hasImpliedFirstOperand)
1735             {
1736                 // Only op2 can be marked as reg optional.
1737                 isSafeToContainOp1 = false;
1738                 isSafeToContainOp2 = isSafeToContainOp2 && IsSafeToContainMem(node, op2);
1739             }
1740             else
1741             {
1742                 // If there are no containable operands, we can make either of op1 or op2
1743                 // as reg optional.
1744                 isSafeToContainOp1 = isSafeToContainOp1 && IsSafeToContainMem(node, op1);
1745                 isSafeToContainOp2 = isSafeToContainOp2 && IsSafeToContainMem(node, op2);
1746             }
1747             SetRegOptionalForBinOp(node, isSafeToContainOp1, isSafeToContainOp2);
1748         }
1749     }
1750 }
1751
1752 //------------------------------------------------------------------------
1753 // ContainCheckDivOrMod: determine which operands of a div/mod should be contained.
1754 //
1755 // Arguments:
1756 //    node - pointer to the node
1757 //
1758 void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
1759 {
1760     assert(node->OperIs(GT_DIV, GT_MOD, GT_UDIV, GT_UMOD));
1761
1762     if (varTypeIsFloating(node->TypeGet()))
1763     {
1764         ContainCheckFloatBinary(node);
1765         return;
1766     }
1767
1768     GenTree* dividend = node->gtGetOp1();
1769     GenTree* divisor  = node->gtGetOp2();
1770
1771     bool divisorCanBeRegOptional = true;
1772 #ifdef _TARGET_X86_
1773     if (dividend->OperGet() == GT_LONG)
1774     {
1775         divisorCanBeRegOptional = false;
1776         MakeSrcContained(node, dividend);
1777     }
1778 #endif
1779
1780     // divisor can be an r/m, but the memory indirection must be of the same size as the divide
1781     if (IsContainableMemoryOp(divisor) && (divisor->TypeGet() == node->TypeGet()))
1782     {
1783         MakeSrcContained(node, divisor);
1784     }
1785     else if (divisorCanBeRegOptional)
1786     {
1787         // If there are no containable operands, we can make an operand reg optional.
1788         // Div instruction allows only divisor to be a memory op.
1789         divisor->SetRegOptional();
1790     }
1791 }
1792
1793 //------------------------------------------------------------------------
1794 // ContainCheckShiftRotate: determine whether the sources of a shift/rotate node should be contained.
1795 //
1796 // Arguments:
1797 //    node - pointer to the node
1798 //
1799 void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
1800 {
1801     assert(node->OperIsShiftOrRotate());
1802 #ifdef _TARGET_X86_
1803     GenTree* source = node->gtOp1;
1804     if (node->OperIsShiftLong())
1805     {
1806         assert(source->OperGet() == GT_LONG);
1807         MakeSrcContained(node, source);
1808     }
1809 #endif // !_TARGET_X86_
1810
1811     GenTree* shiftBy = node->gtOp2;
1812     if (IsContainableImmed(node, shiftBy) && (shiftBy->gtIntConCommon.IconValue() <= 255) &&
1813         (shiftBy->gtIntConCommon.IconValue() >= 0))
1814     {
1815         MakeSrcContained(node, shiftBy);
1816     }
1817 }
1818
1819 //------------------------------------------------------------------------
1820 // ContainCheckStoreLoc: determine whether the source of a STORE_LCL* should be contained.
1821 //
1822 // Arguments:
1823 //    node - pointer to the node
1824 //
1825 void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc)
1826 {
1827     assert(storeLoc->OperIsLocalStore());
1828     GenTree* op1 = storeLoc->gtGetOp1();
1829
1830 #ifdef FEATURE_SIMD
1831     if (varTypeIsSIMD(storeLoc))
1832     {
1833         if (op1->IsCnsIntOrI())
1834         {
1835             // For an InitBlk we want op1 to be contained; otherwise we want it to
1836             // be evaluated into an xmm register.
1837             MakeSrcContained(storeLoc, op1);
1838         }
1839         return;
1840     }
1841 #endif // FEATURE_SIMD
1842
1843     // If the source is a containable immediate, make it contained, unless it is
1844     // an int-size or larger store of zero to memory, because we can generate smaller code
1845     // by zeroing a register and then storing it.
1846     if (IsContainableImmed(storeLoc, op1) && (!op1->IsIntegralConst(0) || varTypeIsSmall(storeLoc)))
1847     {
1848         MakeSrcContained(storeLoc, op1);
1849     }
1850 #ifdef _TARGET_X86_
1851     else if (op1->OperGet() == GT_LONG)
1852     {
1853         MakeSrcContained(storeLoc, op1);
1854     }
1855 #endif // _TARGET_X86_
1856 }
1857
1858 //------------------------------------------------------------------------
1859 // ContainCheckCast: determine whether the source of a CAST node should be contained.
1860 //
1861 // Arguments:
1862 //    node - pointer to the node
1863 //
1864 void Lowering::ContainCheckCast(GenTreeCast* node)
1865 {
1866     GenTree*  castOp     = node->CastOp();
1867     var_types castToType = node->CastToType();
1868     var_types srcType    = castOp->TypeGet();
1869
1870     // force the srcType to unsigned if GT_UNSIGNED flag is set
1871     if (node->gtFlags & GTF_UNSIGNED)
1872     {
1873         srcType = genUnsignedType(srcType);
1874     }
1875
1876     if (!node->gtOverflow() && (varTypeIsFloating(castToType) || varTypeIsFloating(srcType)))
1877     {
1878 #ifdef DEBUG
1879         // If converting to float/double, the operand must be 4 or 8 byte in size.
1880         if (varTypeIsFloating(castToType))
1881         {
1882             unsigned opSize = genTypeSize(srcType);
1883             assert(opSize == 4 || opSize == 8);
1884         }
1885 #endif // DEBUG
1886
1887         // U8 -> R8 conversion requires that the operand be in a register.
1888         if (srcType != TYP_ULONG)
1889         {
1890             if (IsContainableMemoryOp(castOp) || castOp->IsCnsNonZeroFltOrDbl())
1891             {
1892                 MakeSrcContained(node, castOp);
1893             }
1894             else
1895             {
1896                 // Mark castOp as reg optional to indicate codegen
1897                 // can still generate code if it is on stack.
1898                 castOp->SetRegOptional();
1899             }
1900         }
1901     }
1902 #if !defined(_TARGET_64BIT_)
1903     if (varTypeIsLong(srcType))
1904     {
1905         noway_assert(castOp->OperGet() == GT_LONG);
1906         castOp->SetContained();
1907     }
1908 #endif // !defined(_TARGET_64BIT_)
1909 }
1910
1911 //------------------------------------------------------------------------
1912 // ContainCheckCompare: determine whether the sources of a compare node should be contained.
1913 //
1914 // Arguments:
1915 //    node - pointer to the node
1916 //
1917 void Lowering::ContainCheckCompare(GenTreeOp* cmp)
1918 {
1919     assert(cmp->OperIsCompare() || cmp->OperIs(GT_CMP));
1920
1921     GenTree*  op1     = cmp->gtOp.gtOp1;
1922     GenTree*  op2     = cmp->gtOp.gtOp2;
1923     var_types op1Type = op1->TypeGet();
1924     var_types op2Type = op2->TypeGet();
1925
1926     // If either of op1 or op2 is floating point values, then we need to use
1927     // ucomiss or ucomisd to compare, both of which support the following form:
1928     //     ucomis[s|d] xmm, xmm/mem
1929     // That is only the second operand can be a memory op.
1930     //
1931     // Second operand is a memory Op:  Note that depending on comparison operator,
1932     // the operands of ucomis[s|d] need to be reversed.  Therefore, either op1 or
1933     // op2 can be a memory op depending on the comparison operator.
1934     if (varTypeIsFloating(op1Type))
1935     {
1936         // The type of the operands has to be the same and no implicit conversions at this stage.
1937         assert(op1Type == op2Type);
1938
1939         GenTree* otherOp;
1940         if (GenCondition::FromFloatRelop(cmp).PreferSwap())
1941         {
1942             otherOp = op1;
1943         }
1944         else
1945         {
1946             otherOp = op2;
1947         }
1948
1949         assert(otherOp != nullptr);
1950         bool isSafeToContainOtherOp = true;
1951         if (otherOp->IsCnsNonZeroFltOrDbl())
1952         {
1953             MakeSrcContained(cmp, otherOp);
1954         }
1955         else if (IsContainableMemoryOp(otherOp))
1956         {
1957             isSafeToContainOtherOp = IsSafeToContainMem(cmp, otherOp);
1958             if (isSafeToContainOtherOp)
1959             {
1960                 MakeSrcContained(cmp, otherOp);
1961             }
1962         }
1963
1964         if (!otherOp->isContained() && isSafeToContainOtherOp && IsSafeToContainMem(cmp, otherOp))
1965         {
1966             // SSE2 allows only otherOp to be a memory-op. Since otherOp is not
1967             // contained, we can mark it reg-optional.
1968             // IsSafeToContainMem is expensive so we call it at most once for otherOp.
1969             // If we already called IsSafeToContainMem, it must have returned false;
1970             // otherwise, otherOp would be contained.
1971             otherOp->SetRegOptional();
1972         }
1973
1974         return;
1975     }
1976
1977     // TODO-XArch-CQ: factor out cmp optimization in 'genCondSetFlags' to be used here
1978     // or in other backend.
1979
1980     if (CheckImmedAndMakeContained(cmp, op2))
1981     {
1982         // If the types are the same, or if the constant is of the correct size,
1983         // we can treat the MemoryOp as contained.
1984         if (op1Type == op2Type)
1985         {
1986             if (IsContainableMemoryOp(op1))
1987             {
1988                 MakeSrcContained(cmp, op1);
1989             }
1990             else
1991             {
1992                 op1->SetRegOptional();
1993             }
1994         }
1995     }
1996     else if (op1Type == op2Type)
1997     {
1998         // Note that TEST does not have a r,rm encoding like CMP has but we can still
1999         // contain the second operand because the emitter maps both r,rm and rm,r to
2000         // the same instruction code. This avoids the need to special case TEST here.
2001
2002         bool isSafeToContainOp1 = true;
2003         bool isSafeToContainOp2 = true;
2004
2005         if (IsContainableMemoryOp(op2))
2006         {
2007             isSafeToContainOp2 = IsSafeToContainMem(cmp, op2);
2008             if (isSafeToContainOp2)
2009             {
2010                 MakeSrcContained(cmp, op2);
2011             }
2012         }
2013
2014         if (!op2->isContained() && IsContainableMemoryOp(op1))
2015         {
2016             isSafeToContainOp1 = IsSafeToContainMem(cmp, op1);
2017             if (isSafeToContainOp1)
2018             {
2019                 MakeSrcContained(cmp, op1);
2020             }
2021         }
2022
2023         if (!op1->isContained() && !op2->isContained())
2024         {
2025             // One of op1 or op2 could be marked as reg optional
2026             // to indicate that codegen can still generate code
2027             // if one of them is on stack.
2028             GenTree* regOptionalCandidate = op1->IsCnsIntOrI() ? op2 : PreferredRegOptionalOperand(cmp);
2029
2030             // IsSafeToContainMem is expensive so we call it at most once for each operand
2031             // in this method. If we already called IsSafeToContainMem, it must have returned false;
2032             // otherwise, the corresponding operand (op1 or op2) would be contained.
2033             bool setRegOptional = (regOptionalCandidate == op1) ? isSafeToContainOp1 && IsSafeToContainMem(cmp, op1)
2034                                                                 : isSafeToContainOp2 && IsSafeToContainMem(cmp, op2);
2035             if (setRegOptional)
2036             {
2037                 regOptionalCandidate->SetRegOptional();
2038             }
2039         }
2040     }
2041 }
2042
2043 //------------------------------------------------------------------------
2044 // LowerRMWMemOp: Determine if this is a valid RMW mem op, and if so lower it accordingly
2045 //
2046 // Arguments:
2047 //    node       - The indirect store node (GT_STORE_IND) of interest
2048 //
2049 // Return Value:
2050 //    Returns true if 'node' is a valid RMW mem op; false otherwise.
2051 //
2052 bool Lowering::LowerRMWMemOp(GenTreeIndir* storeInd)
2053 {
2054     assert(storeInd->OperGet() == GT_STOREIND);
2055
2056     // SSE2 doesn't support RMW on float values
2057     assert(!varTypeIsFloating(storeInd));
2058
2059     // Terminology:
2060     // indirDst = memory write of an addr mode  (i.e. storeind destination)
2061     // indirSrc = value being written to memory (i.e. storeind source which could a binary/unary op)
2062     // indirCandidate = memory read i.e. a gtInd of an addr mode
2063     // indirOpSource = source operand used in binary/unary op (i.e. source operand of indirSrc node)
2064
2065     GenTree* indirCandidate = nullptr;
2066     GenTree* indirOpSource  = nullptr;
2067
2068     if (!IsRMWMemOpRootedAtStoreInd(storeInd, &indirCandidate, &indirOpSource))
2069     {
2070         JITDUMP("Lower of StoreInd didn't mark the node as self contained for reason: %d\n",
2071                 storeInd->AsStoreInd()->GetRMWStatus());
2072         DISPTREERANGE(BlockRange(), storeInd);
2073         return false;
2074     }
2075
2076     GenTree*   indirDst = storeInd->gtGetOp1();
2077     GenTree*   indirSrc = storeInd->gtGetOp2();
2078     genTreeOps oper     = indirSrc->OperGet();
2079
2080     // At this point we have successfully detected a RMW memory op of one of the following forms
2081     //         storeInd(indirDst, indirSrc(indirCandidate, indirOpSource)) OR
2082     //         storeInd(indirDst, indirSrc(indirOpSource, indirCandidate) in case of commutative operations OR
2083     //         storeInd(indirDst, indirSrc(indirCandidate) in case of unary operations
2084     //
2085     // Here indirSrc = one of the supported binary or unary operation for RMW of memory
2086     //      indirCandidate = a GT_IND node
2087     //      indirCandidateChild = operand of GT_IND indirCandidate
2088     //
2089     // The logic below does the following
2090     //      Make indirOpSource contained.
2091     //      Make indirSrc contained.
2092     //      Make indirCandidate contained.
2093     //      Make indirCandidateChild contained.
2094     //      Make indirDst contained except when it is a GT_LCL_VAR or GT_CNS_INT that doesn't fit within addr
2095     //      base.
2096     //
2097
2098     // We have already done containment analysis on the indirSrc op.
2099     // If any of its operands are marked regOptional, reset that now.
2100     indirSrc->AsOp()->gtOp1->ClearRegOptional();
2101     if (GenTree::OperIsBinary(oper))
2102     {
2103         // On Xarch RMW operations require the source to be an immediate or in a register.
2104         // Therefore, if we have previously marked the indirOpSource as contained while lowering
2105         // the binary node, we need to reset that now.
2106         if (IsContainableMemoryOp(indirOpSource))
2107         {
2108             indirOpSource->ClearContained();
2109         }
2110         indirSrc->AsOp()->gtOp2->ClearRegOptional();
2111         JITDUMP("Lower succesfully detected an assignment of the form: *addrMode BinOp= source\n");
2112     }
2113     else
2114     {
2115         assert(GenTree::OperIsUnary(oper));
2116         JITDUMP("Lower succesfully detected an assignment of the form: *addrMode = UnaryOp(*addrMode)\n");
2117     }
2118     DISPTREERANGE(BlockRange(), storeInd);
2119
2120     indirSrc->SetContained();
2121     indirCandidate->SetContained();
2122
2123     GenTree* indirCandidateChild = indirCandidate->gtGetOp1();
2124     indirCandidateChild->SetContained();
2125
2126     if (indirCandidateChild->OperGet() == GT_LEA)
2127     {
2128         GenTreeAddrMode* addrMode = indirCandidateChild->AsAddrMode();
2129
2130         if (addrMode->HasBase())
2131         {
2132             assert(addrMode->Base()->OperIsLeaf());
2133             addrMode->Base()->SetContained();
2134         }
2135
2136         if (addrMode->HasIndex())
2137         {
2138             assert(addrMode->Index()->OperIsLeaf());
2139             addrMode->Index()->SetContained();
2140         }
2141
2142         indirDst->SetContained();
2143     }
2144     else
2145     {
2146         assert(indirCandidateChild->OperGet() == GT_LCL_VAR || indirCandidateChild->OperGet() == GT_LCL_VAR_ADDR ||
2147                indirCandidateChild->OperGet() == GT_CLS_VAR_ADDR || indirCandidateChild->OperGet() == GT_CNS_INT);
2148
2149         // If it is a GT_LCL_VAR, it still needs the reg to hold the address.
2150         // We would still need a reg for GT_CNS_INT if it doesn't fit within addressing mode base.
2151         // For GT_CLS_VAR_ADDR, we don't need a reg to hold the address, because field address value is known at jit
2152         // time. Also, we don't need a reg for GT_CLS_VAR_ADDR.
2153         if (indirCandidateChild->OperGet() == GT_LCL_VAR_ADDR || indirCandidateChild->OperGet() == GT_CLS_VAR_ADDR)
2154         {
2155             indirDst->SetContained();
2156         }
2157         else if (indirCandidateChild->IsCnsIntOrI() && indirCandidateChild->AsIntConCommon()->FitsInAddrBase(comp))
2158         {
2159             indirDst->SetContained();
2160         }
2161     }
2162     return true;
2163 }
2164
2165 //------------------------------------------------------------------------
2166 // ContainCheckBinary: Determine whether a binary op's operands should be contained.
2167 //
2168 // Arguments:
2169 //    node - the node we care about
2170 //
2171 void Lowering::ContainCheckBinary(GenTreeOp* node)
2172 {
2173     assert(node->OperIsBinary());
2174
2175     if (varTypeIsFloating(node))
2176     {
2177         assert(node->OperIs(GT_ADD, GT_SUB));
2178         ContainCheckFloatBinary(node);
2179         return;
2180     }
2181
2182     GenTree* op1 = node->gtOp1;
2183     GenTree* op2 = node->gtOp2;
2184
2185     // We can directly encode the second operand if it is either a containable constant or a memory-op.
2186     // In case of memory-op, we can encode it directly provided its type matches with 'tree' type.
2187     // This is because during codegen, type of 'tree' is used to determine emit Type size. If the types
2188     // do not match, they get normalized (i.e. sign/zero extended) on load into a register.
2189     bool     directlyEncodable  = false;
2190     bool     binOpInRMW         = false;
2191     GenTree* operand            = nullptr;
2192     bool     isSafeToContainOp1 = true;
2193     bool     isSafeToContainOp2 = true;
2194
2195     if (IsContainableImmed(node, op2))
2196     {
2197         directlyEncodable = true;
2198         operand           = op2;
2199     }
2200     else
2201     {
2202         binOpInRMW = IsBinOpInRMWStoreInd(node);
2203         if (!binOpInRMW)
2204         {
2205             const unsigned operatorSize = genTypeSize(node->TypeGet());
2206             if ((genTypeSize(op2->TypeGet()) == operatorSize) && IsContainableMemoryOp(op2))
2207             {
2208                 isSafeToContainOp2 = IsSafeToContainMem(node, op2);
2209                 if (isSafeToContainOp2)
2210                 {
2211                     directlyEncodable = true;
2212                     operand           = op2;
2213                 }
2214             }
2215
2216             if ((operand == nullptr) && node->OperIsCommutative())
2217             {
2218                 // If it is safe, we can reverse the order of operands of commutative operations for efficient
2219                 // codegen
2220                 if (IsContainableImmed(node, op1))
2221                 {
2222                     directlyEncodable = true;
2223                     operand           = op1;
2224                 }
2225                 else if ((genTypeSize(op1->TypeGet()) == operatorSize) && IsContainableMemoryOp(op1))
2226                 {
2227                     isSafeToContainOp1 = IsSafeToContainMem(node, op1);
2228                     if (isSafeToContainOp1)
2229                     {
2230                         directlyEncodable = true;
2231                         operand           = op1;
2232                     }
2233                 }
2234             }
2235         }
2236     }
2237
2238     if (directlyEncodable)
2239     {
2240         assert(operand != nullptr);
2241         MakeSrcContained(node, operand);
2242     }
2243     else if (!binOpInRMW)
2244     {
2245         // If this binary op neither has contained operands, nor is a
2246         // Read-Modify-Write (RMW) operation, we can mark its operands
2247         // as reg optional.
2248
2249         // IsSafeToContainMem is expensive so we call it at most once for each operand
2250         // in this method. If we already called IsSafeToContainMem, it must have returned false;
2251         // otherwise, directlyEncodable would be true.
2252         isSafeToContainOp1 = isSafeToContainOp1 && IsSafeToContainMem(node, op1);
2253         isSafeToContainOp2 = isSafeToContainOp2 && IsSafeToContainMem(node, op2);
2254
2255         SetRegOptionalForBinOp(node, isSafeToContainOp1, isSafeToContainOp2);
2256     }
2257 }
2258
2259 //------------------------------------------------------------------------
2260 // ContainCheckBoundsChk: determine whether any source of a bounds check node should be contained.
2261 //
2262 // Arguments:
2263 //    node - pointer to the node
2264 //
2265 void Lowering::ContainCheckBoundsChk(GenTreeBoundsChk* node)
2266 {
2267     assert(node->OperIsBoundsCheck());
2268     GenTree* other;
2269     if (CheckImmedAndMakeContained(node, node->gtIndex))
2270     {
2271         other = node->gtArrLen;
2272     }
2273     else if (CheckImmedAndMakeContained(node, node->gtArrLen))
2274     {
2275         other = node->gtIndex;
2276     }
2277     else if (IsContainableMemoryOp(node->gtIndex))
2278     {
2279         other = node->gtIndex;
2280     }
2281     else
2282     {
2283         other = node->gtArrLen;
2284     }
2285
2286     if (node->gtIndex->TypeGet() == node->gtArrLen->TypeGet())
2287     {
2288         if (IsContainableMemoryOp(other))
2289         {
2290             MakeSrcContained(node, other);
2291         }
2292         else
2293         {
2294             // We can mark 'other' as reg optional, since it is not contained.
2295             other->SetRegOptional();
2296         }
2297     }
2298 }
2299
2300 //------------------------------------------------------------------------
2301 // ContainCheckIntrinsic: determine whether the source of an INTRINSIC node should be contained.
2302 //
2303 // Arguments:
2304 //    node - pointer to the node
2305 //
2306 void Lowering::ContainCheckIntrinsic(GenTreeOp* node)
2307 {
2308     assert(node->OperIs(GT_INTRINSIC));
2309
2310     CorInfoIntrinsics intrinsicId = node->gtIntrinsic.gtIntrinsicId;
2311
2312     if (intrinsicId == CORINFO_INTRINSIC_Sqrt || intrinsicId == CORINFO_INTRINSIC_Round ||
2313         intrinsicId == CORINFO_INTRINSIC_Ceiling || intrinsicId == CORINFO_INTRINSIC_Floor)
2314     {
2315         GenTree* op1 = node->gtGetOp1();
2316         if (IsContainableMemoryOp(op1) || op1->IsCnsNonZeroFltOrDbl())
2317         {
2318             MakeSrcContained(node, op1);
2319         }
2320         else
2321         {
2322             // Mark the operand as reg optional since codegen can still
2323             // generate code if op1 is on stack.
2324             op1->SetRegOptional();
2325         }
2326     }
2327 }
2328
2329 #ifdef FEATURE_SIMD
2330 //----------------------------------------------------------------------------------------------
2331 // ContainCheckSIMD: Perform containment analysis for a SIMD intrinsic node.
2332 //
2333 //  Arguments:
2334 //     simdNode - The SIMD intrinsic node.
2335 //
2336 void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode)
2337 {
2338     switch (simdNode->gtSIMDIntrinsicID)
2339     {
2340         GenTree* op1;
2341         GenTree* op2;
2342
2343         case SIMDIntrinsicInit:
2344         {
2345             op1 = simdNode->gtOp.gtOp1;
2346 #ifndef _TARGET_64BIT_
2347             if (op1->OperGet() == GT_LONG)
2348             {
2349                 MakeSrcContained(simdNode, op1);
2350                 GenTree* op1lo = op1->gtGetOp1();
2351                 GenTree* op1hi = op1->gtGetOp2();
2352
2353                 if ((op1lo->IsIntegralConst(0) && op1hi->IsIntegralConst(0)) ||
2354                     (op1lo->IsIntegralConst(-1) && op1hi->IsIntegralConst(-1)))
2355                 {
2356                     MakeSrcContained(op1, op1lo);
2357                     MakeSrcContained(op1, op1hi);
2358                 }
2359             }
2360             else
2361 #endif // !_TARGET_64BIT_
2362                 if (op1->IsFPZero() || op1->IsIntegralConst(0) ||
2363                     (varTypeIsIntegral(simdNode->gtSIMDBaseType) && op1->IsIntegralConst(-1)))
2364             {
2365                 MakeSrcContained(simdNode, op1);
2366             }
2367             else if ((comp->getSIMDSupportLevel() == SIMD_AVX2_Supported) &&
2368                      ((simdNode->gtSIMDSize == 16) || (simdNode->gtSIMDSize == 32)))
2369             {
2370                 // Either op1 is a float or dbl constant or an addr
2371                 if (op1->IsCnsFltOrDbl() || op1->OperIsLocalAddr())
2372                 {
2373                     MakeSrcContained(simdNode, op1);
2374                 }
2375             }
2376         }
2377         break;
2378
2379         case SIMDIntrinsicInitArray:
2380             // We have an array and an index, which may be contained.
2381             CheckImmedAndMakeContained(simdNode, simdNode->gtGetOp2());
2382             break;
2383
2384         case SIMDIntrinsicOpEquality:
2385         case SIMDIntrinsicOpInEquality:
2386             // On SSE4/AVX, we can generate optimal code for (in)equality
2387             // against zero using ptest. We can safely do this optimization
2388             // for integral vectors but not for floating-point for the reason
2389             // that we have +0.0 and -0.0 and +0.0 == -0.0
2390             op2 = simdNode->gtGetOp2();
2391             if ((comp->getSIMDSupportLevel() >= SIMD_SSE4_Supported) && op2->IsIntegralConstVector(0))
2392             {
2393                 MakeSrcContained(simdNode, op2);
2394             }
2395             break;
2396
2397         case SIMDIntrinsicGetItem:
2398         {
2399             // This implements get_Item method. The sources are:
2400             //  - the source SIMD struct
2401             //  - index (which element to get)
2402             // The result is baseType of SIMD struct.
2403             op1 = simdNode->gtOp.gtOp1;
2404             op2 = simdNode->gtOp.gtOp2;
2405
2406             if (op1->OperGet() == GT_IND)
2407             {
2408                 assert((op1->gtFlags & GTF_IND_REQ_ADDR_IN_REG) != 0);
2409                 op1->AsIndir()->Addr()->ClearContained();
2410             }
2411             // If the index is a constant, mark it as contained.
2412             CheckImmedAndMakeContained(simdNode, op2);
2413
2414             if (IsContainableMemoryOp(op1))
2415             {
2416                 MakeSrcContained(simdNode, op1);
2417                 if (op1->OperGet() == GT_IND)
2418                 {
2419                     op1->AsIndir()->Addr()->ClearContained();
2420                 }
2421             }
2422         }
2423         break;
2424
2425         case SIMDIntrinsicShuffleSSE2:
2426             // Second operand is an integer constant and marked as contained.
2427             assert(simdNode->gtOp.gtOp2->IsCnsIntOrI());
2428             MakeSrcContained(simdNode, simdNode->gtOp.gtOp2);
2429             break;
2430
2431         default:
2432             break;
2433     }
2434 }
2435 #endif // FEATURE_SIMD
2436
2437 #ifdef FEATURE_HW_INTRINSICS
2438 //----------------------------------------------------------------------------------------------
2439 // IsContainableHWIntrinsicOp: Return true if 'node' is a containable HWIntrinsic op.
2440 //
2441 //  Arguments:
2442 //     containingNode - The hardware intrinsic node which contains 'node'
2443 //     node - The node to check
2444 //     [Out] supportsRegOptional - On return, this will be true if 'containingNode' supports regOptional operands;
2445 //     otherwise, false.
2446 //
2447 // Return Value:
2448 //    true if 'node' is a containable hardware intrinsic node; otherwise, false.
2449 //
2450 bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node, bool* supportsRegOptional)
2451 {
2452     NamedIntrinsic      containingIntrinsicId = containingNode->gtHWIntrinsicId;
2453     HWIntrinsicCategory category              = HWIntrinsicInfo::lookupCategory(containingIntrinsicId);
2454
2455     // We shouldn't have called in here if containingNode doesn't support containment
2456     assert(HWIntrinsicInfo::SupportsContainment(containingIntrinsicId));
2457
2458     // containingNode supports nodes that read from an aligned memory address
2459     //
2460     // This will generally be an explicit LoadAligned instruction and is generally
2461     // false for machines with VEX support. This is because there is currently no way
2462     // to guarantee that the address read from will always be aligned and we could silently
2463     // change the behavior of the program in the case where an Access Violation would have
2464     // otherwise occurred.
2465     bool supportsAlignedSIMDLoads = false;
2466
2467     // containingNode supports nodes that read from general memory
2468     //
2469     // We currently have to assume all "general" loads are unaligned. As such, this is
2470     // generally used to determine if we can mark the node as `regOptional` in the case
2471     // where `node` is not containable. However, this can also be used to determine whether
2472     // we can mark other types of reads as contained (such as when directly reading a local).
2473     bool supportsGeneralLoads = false;
2474
2475     // containingNode supports nodes that read from a scalar memory address
2476     //
2477     // This will generally be an explicit LoadScalar instruction but is also used to determine
2478     // whether we can read an address of type T (we don't support this when the load would
2479     // read more than sizeof(T) bytes).
2480     bool supportsSIMDScalarLoads = false;
2481
2482     // containingNode supports nodes that read from an unaligned memory address
2483     //
2484     // This will generally be an explicit Load instruction and is generally false for machines
2485     // without VEX support. This is because older hardware required that the SIMD operand always
2486     // be aligned to the 'natural alignment' of the type.
2487     bool supportsUnalignedSIMDLoads = false;
2488
2489     switch (category)
2490     {
2491         case HW_Category_MemoryLoad:
2492             supportsGeneralLoads = (!node->OperIsHWIntrinsic());
2493             break;
2494
2495         case HW_Category_SimpleSIMD:
2496         {
2497             // These intrinsics only expect 16 or 32-byte nodes for containment
2498             assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
2499             assert(supportsSIMDScalarLoads == false);
2500
2501             supportsAlignedSIMDLoads =
2502                 !comp->canUseVexEncoding() && (containingIntrinsicId != NI_SSE2_ConvertToVector128Double);
2503             supportsUnalignedSIMDLoads = !supportsAlignedSIMDLoads;
2504             supportsGeneralLoads       = supportsUnalignedSIMDLoads;
2505
2506             break;
2507         }
2508
2509         case HW_Category_IMM:
2510         {
2511             switch (containingIntrinsicId)
2512             {
2513                 case NI_SSE_Shuffle:
2514                 case NI_SSE2_CompareLessThan:
2515                 case NI_SSE2_ShiftLeftLogical:
2516                 case NI_SSE2_ShiftRightArithmetic:
2517                 case NI_SSE2_ShiftRightLogical:
2518                 case NI_SSE2_Shuffle:
2519                 case NI_SSE2_ShuffleHigh:
2520                 case NI_SSE2_ShuffleLow:
2521                 case NI_SSSE3_AlignRight:
2522                 case NI_SSE41_Blend:
2523                 case NI_SSE41_DotProduct:
2524                 case NI_SSE41_MultipleSumAbsoluteDifferences:
2525                 case NI_AES_KeygenAssist:
2526                 case NI_PCLMULQDQ_CarrylessMultiply:
2527                 case NI_AVX_Blend:
2528                 case NI_AVX_Compare:
2529                 case NI_AVX_DotProduct:
2530                 case NI_AVX_InsertVector128:
2531                 case NI_AVX_Permute:
2532                 case NI_AVX_Permute2x128:
2533                 case NI_AVX2_Blend:
2534                 case NI_AVX2_InsertVector128:
2535                 case NI_AVX2_MultipleSumAbsoluteDifferences:
2536                 case NI_AVX2_Permute2x128:
2537                 case NI_AVX2_Permute4x64:
2538                 case NI_AVX2_ShiftLeftLogical:
2539                 case NI_AVX2_ShiftRightArithmetic:
2540                 case NI_AVX2_ShiftRightLogical:
2541                 case NI_AVX2_ShuffleHigh:
2542                 case NI_AVX2_ShuffleLow:
2543                 {
2544                     // These intrinsics only expect 16 or 32-byte nodes for containment
2545                     assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
2546                     assert(supportsSIMDScalarLoads == false);
2547
2548                     supportsAlignedSIMDLoads   = !comp->canUseVexEncoding();
2549                     supportsUnalignedSIMDLoads = !supportsAlignedSIMDLoads;
2550                     supportsGeneralLoads       = supportsUnalignedSIMDLoads;
2551
2552                     break;
2553                 }
2554
2555                 case NI_SSE2_Insert:
2556                 case NI_SSE41_Insert:
2557                 case NI_SSE41_X64_Insert:
2558                 {
2559                     if (containingNode->gtSIMDBaseType == TYP_FLOAT)
2560                     {
2561                         assert(containingIntrinsicId == NI_SSE41_Insert);
2562                         assert(genTypeSize(node->TypeGet()) == 16);
2563
2564                         // Sse41.Insert(V128<float>, V128<float>, byte) is a bit special
2565                         // in that it has different behavior depending on whether the
2566                         // second operand is coming from a register or memory. When coming
2567                         // from a register, all 4 elements of the vector can be used and it
2568                         // is effectively a regular `SimpleSIMD` operation; but when loading
2569                         // from memory, it only works with the lowest element and is effectively
2570                         // a `SIMDScalar`.
2571
2572                         assert(supportsAlignedSIMDLoads == false);
2573                         assert(supportsUnalignedSIMDLoads == false);
2574                         assert(supportsGeneralLoads == false);
2575                         assert(supportsSIMDScalarLoads == false);
2576
2577                         GenTree* op1 = containingNode->gtGetOp1();
2578                         GenTree* op2 = nullptr;
2579                         GenTree* op3 = nullptr;
2580
2581                         assert(op1->OperIsList());
2582                         assert(containingNode->gtGetOp2() == nullptr);
2583
2584                         GenTreeArgList* argList = op1->AsArgList();
2585
2586                         op1     = argList->Current();
2587                         argList = argList->Rest();
2588
2589                         op2     = argList->Current();
2590                         argList = argList->Rest();
2591
2592                         assert(node == op2);
2593
2594                         op3 = argList->Current();
2595
2596                         // The upper two bits of the immediate value are ignored if
2597                         // op2 comes from memory. In order to support using the upper
2598                         // bits, we need to disable containment support if op3 is not
2599                         // constant or if the constant is greater than 0x3F (which means
2600                         // at least one of the upper two bits is set).
2601
2602                         if (op3->IsCnsIntOrI())
2603                         {
2604                             ssize_t ival = op3->AsIntCon()->IconValue();
2605                             assert((ival >= 0) && (ival <= 255));
2606
2607                             supportsSIMDScalarLoads = (ival <= 0x3F);
2608                             supportsGeneralLoads    = supportsSIMDScalarLoads;
2609                         }
2610                         break;
2611                     }
2612
2613                     // We should only get here for integral nodes.
2614                     assert(varTypeIsIntegral(node->TypeGet()));
2615
2616                     assert(supportsAlignedSIMDLoads == false);
2617                     assert(supportsUnalignedSIMDLoads == false);
2618                     assert(supportsSIMDScalarLoads == false);
2619
2620                     const unsigned expectedSize = genTypeSize(containingNode->gtSIMDBaseType);
2621                     const unsigned operandSize  = genTypeSize(node->TypeGet());
2622
2623                     supportsGeneralLoads = (operandSize >= expectedSize);
2624                     break;
2625                 }
2626
2627                 case NI_AVX_CompareScalar:
2628                 {
2629                     // These intrinsics only expect 16 or 32-byte nodes for containment
2630                     assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
2631
2632                     assert(supportsAlignedSIMDLoads == false);
2633                     assert(supportsUnalignedSIMDLoads == false);
2634
2635                     supportsSIMDScalarLoads = true;
2636                     supportsGeneralLoads    = supportsSIMDScalarLoads;
2637                     break;
2638                 }
2639
2640                 default:
2641                 {
2642                     assert(supportsAlignedSIMDLoads == false);
2643                     assert(supportsGeneralLoads == false);
2644                     assert(supportsSIMDScalarLoads == false);
2645                     assert(supportsUnalignedSIMDLoads == false);
2646                     break;
2647                 }
2648             }
2649             break;
2650         }
2651
2652         case HW_Category_SIMDScalar:
2653         {
2654             assert(supportsAlignedSIMDLoads == false);
2655             assert(supportsUnalignedSIMDLoads == false);
2656
2657             switch (containingIntrinsicId)
2658             {
2659                 case NI_Base_Vector128_CreateScalarUnsafe:
2660                 case NI_Base_Vector256_CreateScalarUnsafe:
2661                 {
2662                     assert(supportsSIMDScalarLoads == false);
2663
2664                     const unsigned expectedSize = genTypeSize(genActualType(containingNode->gtSIMDBaseType));
2665                     const unsigned operandSize  = genTypeSize(node->TypeGet());
2666
2667                     supportsGeneralLoads = (operandSize == expectedSize);
2668                     break;
2669                 }
2670
2671                 case NI_AVX2_BroadcastScalarToVector128:
2672                 case NI_AVX2_BroadcastScalarToVector256:
2673                 {
2674                     // The memory form of this already takes a pointer, and cannot be further contained.
2675                     // The containable form is the one that takes a SIMD value, that may be in memory.
2676                     supportsGeneralLoads = (node->TypeGet() == TYP_SIMD16);
2677                     break;
2678                 }
2679
2680                 case NI_SSE_ConvertScalarToVector128Single:
2681                 case NI_SSE2_ConvertScalarToVector128Double:
2682                 case NI_SSE2_ConvertScalarToVector128Int32:
2683                 case NI_SSE2_ConvertScalarToVector128UInt32:
2684                 case NI_SSE_X64_ConvertScalarToVector128Single:
2685                 case NI_SSE2_X64_ConvertScalarToVector128Double:
2686                 case NI_SSE2_X64_ConvertScalarToVector128Int64:
2687                 case NI_SSE2_X64_ConvertScalarToVector128UInt64:
2688                 {
2689                     if (!varTypeIsIntegral(node->TypeGet()))
2690                     {
2691                         // The floating-point overload doesn't require any special semantics
2692                         assert(containingIntrinsicId == NI_SSE2_ConvertScalarToVector128Double);
2693                         supportsSIMDScalarLoads = true;
2694                         supportsGeneralLoads    = supportsSIMDScalarLoads;
2695                         break;
2696                     }
2697
2698                     assert(supportsSIMDScalarLoads == false);
2699
2700                     const unsigned expectedSize = genTypeSize(genActualType(containingNode->gtSIMDBaseType));
2701                     const unsigned operandSize  = genTypeSize(node->TypeGet());
2702
2703                     supportsGeneralLoads = (operandSize == expectedSize);
2704                     break;
2705                 }
2706
2707                 default:
2708                 {
2709                     // These intrinsics only expect 16 or 32-byte nodes for containment
2710                     assert((genTypeSize(node->TypeGet()) == 16) || (genTypeSize(node->TypeGet()) == 32));
2711
2712                     supportsSIMDScalarLoads = true;
2713                     supportsGeneralLoads    = supportsSIMDScalarLoads;
2714                     break;
2715                 }
2716             }
2717             break;
2718         }
2719
2720         case HW_Category_Scalar:
2721         {
2722             // We should only get here for integral nodes.
2723             assert(varTypeIsIntegral(node->TypeGet()));
2724
2725             assert(supportsAlignedSIMDLoads == false);
2726             assert(supportsUnalignedSIMDLoads == false);
2727             assert(supportsSIMDScalarLoads == false);
2728
2729             unsigned       expectedSize = genTypeSize(containingNode->TypeGet());
2730             const unsigned operandSize  = genTypeSize(node->TypeGet());
2731
2732             // CRC32 codegen depends on its second oprand's type.
2733             // Currently, we are using SIMDBaseType to store the op2Type info.
2734             if (containingIntrinsicId == NI_SSE42_Crc32)
2735             {
2736                 var_types op2Type = containingNode->gtSIMDBaseType;
2737                 expectedSize      = genTypeSize(op2Type);
2738             }
2739
2740             supportsGeneralLoads = (operandSize >= expectedSize);
2741             break;
2742         }
2743
2744         default:
2745         {
2746             assert(supportsAlignedSIMDLoads == false);
2747             assert(supportsGeneralLoads == false);
2748             assert(supportsSIMDScalarLoads == false);
2749             assert(supportsUnalignedSIMDLoads == false);
2750             break;
2751         }
2752     }
2753
2754     noway_assert(supportsRegOptional != nullptr);
2755     *supportsRegOptional = supportsGeneralLoads;
2756
2757     if (!node->OperIsHWIntrinsic())
2758     {
2759         return supportsGeneralLoads && IsContainableMemoryOp(node);
2760     }
2761
2762     // TODO-XArch: Update this to be table driven, if possible.
2763
2764     NamedIntrinsic intrinsicId = node->AsHWIntrinsic()->gtHWIntrinsicId;
2765
2766     switch (intrinsicId)
2767     {
2768         case NI_SSE_LoadAlignedVector128:
2769         case NI_SSE2_LoadAlignedVector128:
2770         case NI_AVX_LoadAlignedVector256:
2771         {
2772             return supportsAlignedSIMDLoads;
2773         }
2774
2775         case NI_SSE_LoadScalarVector128:
2776         case NI_SSE2_LoadScalarVector128:
2777         {
2778             return supportsSIMDScalarLoads;
2779         }
2780
2781         // VEX encoding supports unaligned memory ops, so we can fold them
2782         case NI_SSE_LoadVector128:
2783         case NI_SSE2_LoadVector128:
2784         case NI_AVX_LoadVector256:
2785         {
2786             return supportsUnalignedSIMDLoads;
2787         }
2788
2789         default:
2790         {
2791             assert(!node->isContainableHWIntrinsic());
2792             return false;
2793         }
2794     }
2795 }
2796
2797 //----------------------------------------------------------------------------------------------
2798 // ContainCheckHWIntrinsicAddr: Perform containment analysis for an address operand of a hardware
2799 //                              intrinsic node.
2800 //
2801 //  Arguments:
2802 //     node  - The hardware intrinsic node
2803 //     pAddr - The "parent" pointer to the address operand, so that we can update the operand
2804 //             of the parent as needed.
2805 //
2806 void Lowering::ContainCheckHWIntrinsicAddr(GenTreeHWIntrinsic* node, GenTree** pAddr)
2807 {
2808     assert(((*pAddr)->TypeGet() == TYP_I_IMPL) || ((*pAddr)->TypeGet() == TYP_BYREF));
2809     TryCreateAddrMode(LIR::Use(BlockRange(), pAddr, node), true);
2810     GenTree* addr = *pAddr;
2811     if ((addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_VAR_ADDR) ||
2812          (addr->IsCnsIntOrI() && addr->AsIntConCommon()->FitsInAddrBase(comp)) || (addr->OperGet() == GT_LEA)) &&
2813         IsSafeToContainMem(node, addr))
2814     {
2815         MakeSrcContained(node, addr);
2816     }
2817 }
2818
2819 //----------------------------------------------------------------------------------------------
2820 // ContainCheckHWIntrinsic: Perform containment analysis for a hardware intrinsic node.
2821 //
2822 //  Arguments:
2823 //     node - The hardware intrinsic node.
2824 //
2825 void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node)
2826 {
2827     NamedIntrinsic      intrinsicId = node->gtHWIntrinsicId;
2828     HWIntrinsicCategory category    = HWIntrinsicInfo::lookupCategory(intrinsicId);
2829     int                 numArgs     = HWIntrinsicInfo::lookupNumArgs(node);
2830     var_types           baseType    = node->gtSIMDBaseType;
2831
2832     GenTree* op1 = node->gtGetOp1();
2833     GenTree* op2 = node->gtGetOp2();
2834     GenTree* op3 = nullptr;
2835
2836     if (!HWIntrinsicInfo::SupportsContainment(intrinsicId))
2837     {
2838         // AVX2 gather are not containable and always have constant IMM argument
2839         if (HWIntrinsicInfo::isAVX2GatherIntrinsic(intrinsicId))
2840         {
2841             GenTree* lastOp = HWIntrinsicInfo::lookupLastOp(node);
2842             assert(lastOp != nullptr);
2843             MakeSrcContained(node, lastOp);
2844         }
2845         // Exit early if containment isn't supported
2846         return;
2847     }
2848
2849     // TODO-XArch-CQ: Non-VEX encoded instructions can have both ops contained
2850
2851     const bool isCommutative = HWIntrinsicInfo::IsCommutative(intrinsicId);
2852
2853     if (numArgs == 1)
2854     {
2855         // One argument intrinsics cannot be commutative
2856         assert(!isCommutative);
2857
2858         assert(!op1->OperIsList());
2859         assert(op2 == nullptr);
2860
2861         switch (category)
2862         {
2863             case HW_Category_MemoryLoad:
2864             {
2865                 GenTree** pAddr = &node->gtOp1;
2866                 ContainCheckHWIntrinsicAddr(node, pAddr);
2867                 break;
2868             }
2869             case HW_Category_SimpleSIMD:
2870             case HW_Category_SIMDScalar:
2871             case HW_Category_Scalar:
2872             {
2873                 switch (intrinsicId)
2874                 {
2875                     case NI_SSE_ReciprocalScalar:
2876                     case NI_SSE_ReciprocalSqrtScalar:
2877                     case NI_SSE_SqrtScalar:
2878                     case NI_SSE2_SqrtScalar:
2879                     case NI_SSE41_CeilingScalar:
2880                     case NI_SSE41_FloorScalar:
2881                     case NI_SSE41_RoundCurrentDirectionScalar:
2882                     case NI_SSE41_RoundToNearestIntegerScalar:
2883                     case NI_SSE41_RoundToNegativeInfinityScalar:
2884                     case NI_SSE41_RoundToPositiveInfinityScalar:
2885                     case NI_SSE41_RoundToZeroScalar:
2886                     {
2887                         // These intrinsics have both 1 and 2-operand overloads.
2888                         //
2889                         // The 1-operand overload basically does `intrinsic(op1, op1)`
2890                         //
2891                         // Because of this, the operand must be loaded into a register
2892                         // and cannot be contained.
2893                         return;
2894                     }
2895
2896                     case NI_SSE2_ConvertToInt32:
2897                     case NI_SSE2_X64_ConvertToInt64:
2898                     case NI_SSE2_ConvertToUInt32:
2899                     case NI_SSE2_X64_ConvertToUInt64:
2900                     case NI_AVX2_ConvertToInt32:
2901                     case NI_AVX2_ConvertToUInt32:
2902                     {
2903                         if (varTypeIsIntegral(baseType))
2904                         {
2905                             // These intrinsics are "ins reg/mem, xmm" and don't
2906                             // currently support containment.
2907                             return;
2908                         }
2909
2910                         break;
2911                     }
2912
2913                     default:
2914                     {
2915                         break;
2916                     }
2917                 }
2918
2919                 bool supportsRegOptional = false;
2920
2921                 if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
2922                 {
2923                     MakeSrcContained(node, op1);
2924                 }
2925                 else if (supportsRegOptional)
2926                 {
2927                     op1->SetRegOptional();
2928                 }
2929                 break;
2930             }
2931
2932             default:
2933             {
2934                 unreached();
2935                 break;
2936             }
2937         }
2938     }
2939     else
2940     {
2941         if (numArgs == 2)
2942         {
2943             assert(!op1->OperIsList());
2944             assert(op2 != nullptr);
2945             assert(!op2->OperIsList());
2946
2947             switch (category)
2948             {
2949                 case HW_Category_MemoryLoad:
2950                 {
2951                     GenTree** pAddr = nullptr;
2952                     if ((intrinsicId == NI_AVX_MaskLoad) || (intrinsicId == NI_AVX2_MaskLoad))
2953                     {
2954                         pAddr = &node->gtOp.gtOp1;
2955                     }
2956                     else
2957                     {
2958                         pAddr = &node->gtOp.gtOp2;
2959                     }
2960                     ContainCheckHWIntrinsicAddr(node, pAddr);
2961                     break;
2962                 }
2963                 case HW_Category_MemoryStore:
2964                 {
2965                     GenTree** pAddr = &node->gtOp1;
2966                     ContainCheckHWIntrinsicAddr(node, pAddr);
2967                     break;
2968                 }
2969                 case HW_Category_SimpleSIMD:
2970                 case HW_Category_SIMDScalar:
2971                 case HW_Category_Scalar:
2972                 {
2973                     if (HWIntrinsicInfo::GeneratesMultipleIns(intrinsicId))
2974                     {
2975                         switch (intrinsicId)
2976                         {
2977                             case NI_SSE_CompareLessThanOrderedScalar:
2978                             case NI_SSE_CompareLessThanUnorderedScalar:
2979                             case NI_SSE_CompareLessThanOrEqualOrderedScalar:
2980                             case NI_SSE_CompareLessThanOrEqualUnorderedScalar:
2981                             case NI_SSE2_CompareLessThanOrderedScalar:
2982                             case NI_SSE2_CompareLessThanUnorderedScalar:
2983                             case NI_SSE2_CompareLessThanOrEqualOrderedScalar:
2984                             case NI_SSE2_CompareLessThanOrEqualUnorderedScalar:
2985                             {
2986                                 // We need to swap the operands for CompareLessThanOrEqual
2987                                 node->gtOp1 = op2;
2988                                 node->gtOp2 = op1;
2989                                 op2         = op1;
2990                                 break;
2991                             }
2992
2993                             default:
2994                             {
2995                                 // TODO-XArch-CQ: The Compare*OrderedScalar and Compare*UnorderedScalar methods
2996                                 //                are commutative if you also inverse the intrinsic.
2997                                 break;
2998                             }
2999                         }
3000                     }
3001
3002                     bool supportsRegOptional = false;
3003
3004                     if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3005                     {
3006                         MakeSrcContained(node, op2);
3007                     }
3008                     else if ((isCommutative || (intrinsicId == NI_BMI2_MultiplyNoFlags) ||
3009                               (intrinsicId == NI_BMI2_X64_MultiplyNoFlags)) &&
3010                              IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3011                     {
3012                         MakeSrcContained(node, op1);
3013
3014                         // Swap the operands here to make the containment checks in codegen significantly simpler
3015                         node->gtOp1 = op2;
3016                         node->gtOp2 = op1;
3017                     }
3018                     else if (supportsRegOptional)
3019                     {
3020                         op2->SetRegOptional();
3021
3022                         // TODO-XArch-CQ: For commutative nodes, either operand can be reg-optional.
3023                         //                https://github.com/dotnet/coreclr/issues/6361
3024                     }
3025                     break;
3026                 }
3027
3028                 case HW_Category_IMM:
3029                 {
3030                     // We don't currently have any IMM intrinsics which are also commutative
3031                     assert(!isCommutative);
3032                     bool supportsRegOptional = false;
3033
3034                     switch (intrinsicId)
3035                     {
3036                         case NI_SSE2_ShiftLeftLogical:
3037                         case NI_SSE2_ShiftRightArithmetic:
3038                         case NI_SSE2_ShiftRightLogical:
3039                         case NI_AVX2_ShiftLeftLogical:
3040                         case NI_AVX2_ShiftRightArithmetic:
3041                         case NI_AVX2_ShiftRightLogical:
3042                         {
3043                             // These intrinsics can have op2 be imm or reg/mem
3044
3045                             if (!HWIntrinsicInfo::isImmOp(intrinsicId, op2))
3046                             {
3047                                 if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3048                                 {
3049                                     MakeSrcContained(node, op2);
3050                                 }
3051                                 else if (supportsRegOptional)
3052                                 {
3053                                     op2->SetRegOptional();
3054                                 }
3055                             }
3056                             break;
3057                         }
3058
3059                         case NI_SSE2_Shuffle:
3060                         case NI_SSE2_ShuffleHigh:
3061                         case NI_SSE2_ShuffleLow:
3062                         case NI_AVX2_Permute4x64:
3063                         {
3064                             // These intrinsics have op2 as an imm and op1 as a reg/mem
3065
3066                             if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3067                             {
3068                                 MakeSrcContained(node, op1);
3069                             }
3070                             else if (supportsRegOptional)
3071                             {
3072                                 op1->SetRegOptional();
3073                             }
3074                             break;
3075                         }
3076
3077                         case NI_AVX_Permute:
3078                         {
3079                             // These intrinsics can have op2 be imm or reg/mem
3080                             // They also can have op1 be reg/mem and op2 be imm
3081
3082                             if (HWIntrinsicInfo::isImmOp(intrinsicId, op2))
3083                             {
3084                                 if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3085                                 {
3086                                     MakeSrcContained(node, op1);
3087                                 }
3088                                 else if (supportsRegOptional)
3089                                 {
3090                                     op1->SetRegOptional();
3091                                 }
3092                             }
3093                             else if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3094                             {
3095                                 MakeSrcContained(node, op2);
3096                             }
3097                             else if (supportsRegOptional)
3098                             {
3099                                 op2->SetRegOptional();
3100                             }
3101                             break;
3102                         }
3103
3104                         case NI_AES_KeygenAssist:
3105                         {
3106                             if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3107                             {
3108                                 MakeSrcContained(node, op1);
3109                             }
3110                             else if (supportsRegOptional)
3111                             {
3112                                 op1->SetRegOptional();
3113                             }
3114                             break;
3115                         }
3116
3117                         default:
3118                         {
3119                             break;
3120                         }
3121                     }
3122
3123                     break;
3124                 }
3125
3126                 case HW_Category_Special:
3127                 {
3128                     if (intrinsicId == NI_SSE2_CompareLessThan)
3129                     {
3130                         bool supportsRegOptional = false;
3131
3132                         if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3133                         {
3134                             MakeSrcContained(node, op2);
3135                         }
3136                         else if (supportsRegOptional)
3137                         {
3138                             op2->SetRegOptional();
3139                         }
3140                     }
3141                     else
3142                     {
3143                         unreached();
3144                     }
3145                     break;
3146                 }
3147
3148                 default:
3149                 {
3150                     unreached();
3151                     break;
3152                 }
3153             }
3154         }
3155         else if (numArgs == 3)
3156         {
3157             // three argument intrinsics should not be marked commutative
3158             assert(!isCommutative);
3159
3160             assert(op1->OperIsList());
3161             assert(op2 == nullptr);
3162
3163             GenTreeArgList* argList         = op1->AsArgList();
3164             GenTreeArgList* originalArgList = argList;
3165
3166             op1     = argList->Current();
3167             argList = argList->Rest();
3168
3169             op2     = argList->Current();
3170             argList = argList->Rest();
3171
3172             op3 = argList->Current();
3173             assert(argList->Rest() == nullptr);
3174
3175             switch (category)
3176             {
3177                 case HW_Category_MemoryStore:
3178                 {
3179                     GenTree** pAddr = &node->gtOp.gtOp1->gtOp.gtOp1;
3180                     ContainCheckHWIntrinsicAddr(node, pAddr);
3181                     break;
3182                 }
3183                 case HW_Category_SimpleSIMD:
3184                 case HW_Category_SIMDScalar:
3185                 case HW_Category_Scalar:
3186                 {
3187                     if ((intrinsicId >= NI_FMA_MultiplyAdd) && (intrinsicId <= NI_FMA_MultiplySubtractNegatedScalar))
3188                     {
3189                         bool supportsRegOptional = false;
3190
3191                         if (IsContainableHWIntrinsicOp(node, op3, &supportsRegOptional))
3192                         {
3193                             // 213 form: op1 = (op2 * op1) + [op3]
3194                             MakeSrcContained(node, op3);
3195                         }
3196                         else if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3197                         {
3198                             // 132 form: op1 = (op1 * op3) + [op2]
3199                             MakeSrcContained(node, op2);
3200                         }
3201                         else if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3202                         {
3203                             // Intrinsics with CopyUpperBits semantics cannot have op1 be contained
3204
3205                             if (!HWIntrinsicInfo::CopiesUpperBits(intrinsicId))
3206                             {
3207                                 // 231 form: op3 = (op2 * op3) + [op1]
3208                                 MakeSrcContained(node, op1);
3209                             }
3210                         }
3211                         else
3212                         {
3213                             assert(supportsRegOptional);
3214
3215                             // TODO-XArch-CQ: Technically any one of the three operands can
3216                             //                be reg-optional. With a limitation on op1 where
3217                             //                it can only be so if CopyUpperBits is off.
3218                             //                https://github.com/dotnet/coreclr/issues/6361
3219
3220                             // 213 form: op1 = (op2 * op1) + op3
3221                             op3->SetRegOptional();
3222                         }
3223                     }
3224                     else
3225                     {
3226                         bool supportsRegOptional = false;
3227
3228                         switch (intrinsicId)
3229                         {
3230                             case NI_SSE41_BlendVariable:
3231                             case NI_AVX_BlendVariable:
3232                             case NI_AVX2_BlendVariable:
3233                             {
3234                                 if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3235                                 {
3236                                     MakeSrcContained(node, op2);
3237                                 }
3238                                 else if (supportsRegOptional)
3239                                 {
3240                                     op2->SetRegOptional();
3241                                 }
3242                                 break;
3243                             }
3244
3245                             case NI_BMI2_MultiplyNoFlags:
3246                             case NI_BMI2_X64_MultiplyNoFlags:
3247                             {
3248                                 if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3249                                 {
3250                                     MakeSrcContained(node, op2);
3251                                 }
3252                                 else if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional))
3253                                 {
3254                                     MakeSrcContained(node, op1);
3255                                     // MultiplyNoFlags is a Commutative operation, so swap the first two operands here
3256                                     // to make the containment checks in codegen significantly simpler
3257                                     *(originalArgList->pCurrent())         = op2;
3258                                     *(originalArgList->Rest()->pCurrent()) = op1;
3259                                 }
3260                                 else if (supportsRegOptional)
3261                                 {
3262                                     op2->SetRegOptional();
3263                                 }
3264                                 break;
3265                             }
3266
3267                             default:
3268                             {
3269                                 unreached();
3270                                 break;
3271                             }
3272                         }
3273                     }
3274                 }
3275
3276                 case HW_Category_IMM:
3277                 {
3278                     bool supportsRegOptional = false;
3279
3280                     switch (intrinsicId)
3281                     {
3282                         case NI_SSE_Shuffle:
3283                         case NI_SSE2_Insert:
3284                         case NI_SSE2_Shuffle:
3285                         case NI_SSSE3_AlignRight:
3286                         case NI_SSE41_Blend:
3287                         case NI_SSE41_DotProduct:
3288                         case NI_SSE41_Insert:
3289                         case NI_SSE41_X64_Insert:
3290                         case NI_SSE41_MultipleSumAbsoluteDifferences:
3291                         case NI_AVX_Blend:
3292                         case NI_AVX_Compare:
3293                         case NI_AVX_CompareScalar:
3294                         case NI_AVX_DotProduct:
3295                         case NI_AVX_Permute2x128:
3296                         case NI_AVX_Shuffle:
3297                         case NI_AVX2_Blend:
3298                         case NI_AVX2_MultipleSumAbsoluteDifferences:
3299                         case NI_AVX2_Permute2x128:
3300                         case NI_PCLMULQDQ_CarrylessMultiply:
3301                         {
3302                             if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional))
3303                             {
3304                                 MakeSrcContained(node, op2);
3305                             }
3306                             else if (supportsRegOptional)
3307                             {
3308                                 op2->SetRegOptional();
3309                             }
3310                             break;
3311                         }
3312
3313                         default:
3314                         {
3315                             break;
3316                         }
3317                     }
3318
3319                     break;
3320                 }
3321
3322                 default:
3323                 {
3324                     unreached();
3325                     break;
3326                 }
3327             }
3328         }
3329         else
3330         {
3331             unreached();
3332         }
3333
3334         if (HWIntrinsicInfo::lookupCategory(intrinsicId) == HW_Category_IMM)
3335         {
3336             GenTree* lastOp = HWIntrinsicInfo::lookupLastOp(node);
3337             assert(lastOp != nullptr);
3338
3339             if (HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && lastOp->IsCnsIntOrI())
3340             {
3341                 MakeSrcContained(node, lastOp);
3342             }
3343         }
3344     }
3345 }
3346 #endif // FEATURE_HW_INTRINSICS
3347
3348 //------------------------------------------------------------------------
3349 // ContainCheckFloatBinary: determine whether the sources of a floating point binary node should be contained.
3350 //
3351 // Arguments:
3352 //    node - pointer to the node
3353 //
3354 void Lowering::ContainCheckFloatBinary(GenTreeOp* node)
3355 {
3356     assert(node->OperIs(GT_ADD, GT_SUB, GT_MUL, GT_DIV) && varTypeIsFloating(node));
3357
3358     // overflow operations aren't supported on float/double types.
3359     assert(!node->gtOverflowEx());
3360
3361     GenTree* op1 = node->gtGetOp1();
3362     GenTree* op2 = node->gtGetOp2();
3363
3364     // No implicit conversions at this stage as the expectation is that
3365     // everything is made explicit by adding casts.
3366     assert(op1->TypeGet() == op2->TypeGet());
3367
3368     bool isSafeToContainOp1 = true;
3369     bool isSafeToContainOp2 = true;
3370
3371     if (op2->IsCnsNonZeroFltOrDbl())
3372     {
3373         MakeSrcContained(node, op2);
3374     }
3375     else if (IsContainableMemoryOp(op2))
3376     {
3377         isSafeToContainOp2 = IsSafeToContainMem(node, op2);
3378         if (isSafeToContainOp2)
3379         {
3380             MakeSrcContained(node, op2);
3381         }
3382     }
3383
3384     if (!op2->isContained() && node->OperIsCommutative())
3385     {
3386         // Though we have GT_ADD(op1=memOp, op2=non-memOp, we try to reorder the operands
3387         // as long as it is safe so that the following efficient code sequence is generated:
3388         //      addss/sd targetReg, memOp    (if op1Reg == targetReg) OR
3389         //      movaps targetReg, op2Reg; addss/sd targetReg, [memOp]
3390         //
3391         // Instead of
3392         //      movss op1Reg, [memOp]; addss/sd targetReg, Op2Reg  (if op1Reg == targetReg) OR
3393         //      movss op1Reg, [memOp]; movaps targetReg, op1Reg, addss/sd targetReg, Op2Reg
3394
3395         if (op1->IsCnsNonZeroFltOrDbl())
3396         {
3397             MakeSrcContained(node, op1);
3398         }
3399         else if (IsContainableMemoryOp(op1))
3400         {
3401             isSafeToContainOp1 = IsSafeToContainMem(node, op1);
3402             if (isSafeToContainOp1)
3403             {
3404                 MakeSrcContained(node, op1);
3405             }
3406         }
3407     }
3408
3409     if (!op1->isContained() && !op2->isContained())
3410     {
3411         // If there are no containable operands, we can make an operand reg optional.
3412         // IsSafeToContainMem is expensive so we call it at most once for each operand
3413         // in this method. If we already called IsSafeToContainMem, it must have returned false;
3414         // otherwise, the corresponding operand (op1 or op2) would be contained.
3415         isSafeToContainOp1 = isSafeToContainOp1 && IsSafeToContainMem(node, op1);
3416         isSafeToContainOp2 = isSafeToContainOp2 && IsSafeToContainMem(node, op2);
3417         SetRegOptionalForBinOp(node, isSafeToContainOp1, isSafeToContainOp2);
3418     }
3419 }
3420
3421 #endif // _TARGET_XARCH_