e09e96baec0914e90ea48b413c5871f9ba389a22
[platform/upstream/coreclr.git] / src / jit / morph.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                          Morph                                            XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 #include "jitpch.h"
15 #ifdef _MSC_VER
16 #pragma hdrstop
17 #endif
18
19 #include "allocacheck.h"     // for alloca
20
21 /*****************************************************************************/
22
23 // Split a tree at the given point
24 // -- Introduces a new temporary variable
25 // -- evaluates *splitPoint into the new temp, in a new statement inserted before 'stmt'
26 // -- substitutes the temporary for '*splitPoint' in 'stmt'
27 // '*splitpoint' must be a node in 'stmt', which is within 'blk', and 'splitpoint' is a pointer
28 // to the link to that node, contained in its parent node.
29 GenTree* Compiler::fgMorphSplitTree(GenTree** splitPoint, // where to split
30                                     GenTree* stmt,        // top level statement housing this tree
31                                     BasicBlock* blk)      // block we are in
32 {
33     GenTree* newTree;
34     GenTree* temp;
35
36     if ((*splitPoint)->OperIsAssignment())
37     {
38         // it's already being assigned so don't introduce a new one
39         newTree = *splitPoint;
40         temp = (*splitPoint)->gtGetOp1();
41     }
42     else
43     {
44         unsigned lclNum = lvaGrabTemp(true DEBUGARG("split tree"));
45         newTree = gtNewTempAssign(lclNum, *splitPoint);
46         temp = gtNewLclvNode(lclNum, (*splitPoint)->TypeGet());
47     }
48
49     GenTreePtr asg  = gtNewStmt(newTree);
50
51     *splitPoint = temp;
52
53     fgInsertStmtBefore(blk, stmt, asg);
54
55     return asg;
56 }
57
58 // state carried over the tree walk, to be used in making
59 // a splitting decision.
60 struct SplitData
61 {
62     // number of calls seen
63     size_t count;
64
65     // callback to determine if we should split here
66     Compiler::fgSplitPredicate* pred;
67
68     // root stmt of tree being processed
69     GenTree* root;
70 };
71
72
73 #ifdef _TARGET_ARM_
74 // Returns true if we should split the tree above this node.
75 // For ARM FP, handling multiple calls per tree via a local and
76 // greedy register allocator could result in a lot of shuffling.
77 // So let the global register allocator handle these cases.
78 bool shouldSplitARM(GenTree* tree, GenTree* parent, Compiler::fgWalkData* data)
79 {
80     if (tree->IsCall()
81         && varTypeIsFloating(tree)
82         && parent
83         && !parent->OperIsAssignment())
84     {
85         // increment call count
86         SplitData* tmpState = (SplitData*) data->pCallbackData;
87         tmpState->count++;
88
89         return tmpState->count > 1;
90     }
91     else
92     {
93         return false;
94     }
95 }
96 #endif // _TARGET_ARM_
97
98 // Callback for the tree walker, called once per node.
99 // Determines if we want to split, performs the split, and then processes the rest of the tree
100 Compiler::fgWalkResult Compiler::fgSplitHelper(GenTree** ppTree, fgWalkData* data)
101 {
102     GenTree* tree = *ppTree;
103     Compiler* comp = data->compiler;
104
105     SplitData* tmpState = (SplitData*) data->pCallbackData;
106
107     fgSplitPredicate* pred = tmpState->pred;
108
109     if (pred(tree, data->parent, data)) // does this look like somewhere we want to split?
110     {
111         //printf("tmpstate2 = %d %p r:%p tmp:%p tree:%p\n", tmpState->count, tmpState->pred, tmpState->root, tmpState, tree);
112         GenTree* result = comp->fgMorphSplitTree(ppTree, tmpState->root, comp->compCurBB);
113
114         GenTree* oldStatement = comp->compCurStmt;
115         comp->compCurStmt = result;
116
117         // because we are doing this in pre-order we also have to process
118         // the subtree that we have just split off
119         comp->fgSplitProcessOneTree(result, pred);
120
121         // restore it
122         comp->compCurStmt = oldStatement;
123
124         return Compiler::WALK_SKIP_SUBTREES;
125     }
126     //else       printf("tmpstate3 = %d %p r:%p tmp:%p tree:%p\n", tmpState->count, tmpState->pred, tmpState->root, tmpState, tree);
127
128     return Compiler::WALK_CONTINUE;
129 }
130
131 void Compiler::fgSplitProcessOneTree(GenTree* tree, fgSplitPredicate pred)
132 {
133     SplitData tmpState = {0};
134     tmpState.pred = pred;
135     tmpState.root = tree;
136
137     fgWalkTreePre(&(tree->gtStmt.gtStmtExpr),
138                   fgSplitHelper,
139                   (void*) &tmpState);
140 }
141
142 // Split expression trees at points which in the case of ARM this is done.
143 void Compiler::fgSplitMethodTrees(void)
144 {
145 #ifndef _TARGET_ARM_
146     return;
147 #else // _TARGET_ARM_
148     for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
149     {
150         compCurBB = block;
151         for (GenTree* tree = block->bbTreeList; tree; tree = tree->gtNext)
152         {
153             assert(tree != tree->gtNext);
154             fgSplitProcessOneTree(tree, shouldSplitARM);
155         }
156     }
157 #endif // _TARGET_ARM_
158 }
159
160
161 // Convert the given node into a call to the specified helper passing
162 //  the given argument list.
163 // Tries to fold constants and also adds an edge for overflow exception
164 // returns the morphed tree
165 GenTreePtr Compiler::fgMorphCastIntoHelper(GenTreePtr tree,
166                                            int        helper,
167                                            GenTreePtr oper)
168 {
169     GenTree *result;
170
171     /* If the operand is a constant, we'll try to fold it */
172     if  (oper->OperIsConst())
173     {
174         GenTreePtr oldTree = tree;
175
176         tree = gtFoldExprConst(tree);    // This may not fold the constant (NaN ...)
177
178         if (tree != oldTree)
179             return fgMorphTree(tree);
180         else if (tree->OperKind() & GTK_CONST)
181             return fgMorphConst(tree);
182
183         // assert that oper is unchanged and that it is still a GT_CAST node
184         noway_assert(tree->gtCast.CastOp() == oper);
185         noway_assert(tree->gtOper == GT_CAST);
186     }
187     result = fgMorphIntoHelperCall(tree, helper, gtNewArgList(oper));
188     assert(result == tree);
189     return result;
190 }
191
192
193 /*****************************************************************************
194  *
195  *  Convert the given node into a call to the specified helper passing
196  *  the given argument list.
197  */
198
199 GenTreePtr          Compiler::fgMorphIntoHelperCall(GenTreePtr      tree,
200                                                     int             helper,
201                                                     GenTreeArgList* args)
202 {
203     tree->ChangeOper(GT_CALL);
204
205     tree->gtFlags              |= GTF_CALL;
206     tree->gtCall.gtCallType     = CT_HELPER;
207     tree->gtCall.gtCallMethHnd  = eeFindHelper(helper);
208     tree->gtCall.gtCallArgs     = args;
209     tree->gtCall.gtCallObjp     = NULL;
210     tree->gtCall.gtCallLateArgs = NULL;
211     tree->gtCall.fgArgInfo      = NULL;
212     tree->gtCall.gtRetClsHnd    = NULL;
213     tree->gtCall.gtCallRegUsedMask = RBM_NONE;
214     tree->gtCall.gtCallMoreFlags   = 0;
215     tree->gtCall.gtInlineCandidateInfo = NULL;
216     tree->gtCall.gtControlExpr = NULL;
217
218 #ifdef FEATURE_READYTORUN_COMPILER
219     tree->gtCall.gtEntryPoint.addr = nullptr;
220 #endif
221
222     /* Perform the morphing */
223
224     tree = fgMorphArgs(tree->AsCall());
225
226     return tree;
227 }
228
229 /*****************************************************************************
230  * This node should not be referenced by anyone now. Set its values to garbage
231  * to catch extra references
232  */
233
234 inline
235 void                DEBUG_DESTROY_NODE(GenTreePtr tree)
236 {
237 #ifdef DEBUG
238     // printf("DEBUG_DESTROY_NODE for [0x%08x]\n", tree);
239
240     // Save gtOper in case we want to find out what this node was
241     tree->gtOperSave    = tree->gtOper;
242
243     tree->gtType        = TYP_UNDEF;
244     tree->gtFlags      |= 0xFFFFFFFF & ~GTF_NODE_MASK;
245     if (tree->OperIsSimple())
246     {
247         tree->gtOp.gtOp1    =
248         tree->gtOp.gtOp2    = NULL;
249     }
250     // Must do this last, because the "gtOp" check above will fail otherwise.
251     // Don't call SetOper, because GT_COUNT is not a valid value
252     tree->gtOper        = GT_COUNT;
253 #endif
254 }
255
256
257 /*****************************************************************************
258  *
259  *  Determine if a relop must be morphed to a qmark to manifest a boolean value.
260  *  This is done when code generation can't create straight-line code to do it.
261  */
262 bool                Compiler::fgMorphRelopToQmark(GenTreePtr tree)
263 {
264 #ifndef LEGACY_BACKEND
265     return false;
266 #else // LEGACY_BACKEND
267     return (genActualType(tree->TypeGet()) == TYP_LONG) ||
268            varTypeIsFloating(tree->TypeGet());
269 #endif // LEGACY_BACKEND
270 }
271
272
273 /*****************************************************************************
274  *
275  *  Morph a cast node (we perform some very simple transformations here).
276  */
277
278 #ifdef _PREFAST_
279 #pragma warning(push)
280 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
281 #endif
282 GenTreePtr          Compiler::fgMorphCast(GenTreePtr tree)
283 {
284     noway_assert(tree->gtOper == GT_CAST);
285     noway_assert(genTypeSize(TYP_I_IMPL) == sizeof(void*));
286
287     /* The first sub-operand is the thing being cast */
288
289     GenTreePtr      oper    = tree->gtCast.CastOp();
290     var_types       srcType = genActualType(oper->TypeGet());
291     unsigned        srcSize;
292
293     var_types       dstType = tree->CastToType();
294     unsigned        dstSize = genTypeSize(dstType);
295
296     // See if the cast has to be done in two steps.  R -> I
297     if (varTypeIsFloating(srcType) && varTypeIsIntegral(dstType))
298     {
299         // Only x86 must go through TYP_DOUBLE to get to all
300         // integral types everybody else can get straight there
301         // except for when using helpers
302         if (srcType == TYP_FLOAT
303 #if !FEATURE_STACK_FP_X87
304
305 #if defined(_TARGET_ARM64_)
306             // Amd64: src = float, dst is overflow conversion.
307             // This goes through helper and hence src needs to be converted to double.
308             &&  tree->gtOverflow()
309 #elif defined(_TARGET_AMD64_)
310             // Amd64: src = float, dst = uint64 or overflow conversion.
311             // This goes through helper and hence src needs to be converted to double.
312             && (tree->gtOverflow() || (dstType == TYP_ULONG))
313 #elif  defined(_TARGET_ARM_)
314             // Arm: src = float, dst = int64/uint64 or overflow conversion.
315             && (tree->gtOverflow() || varTypeIsLong(dstType))
316 #endif
317
318 #endif // FEATURE_STACK_FP_X87
319             )
320         {
321             oper = gtNewCastNode(TYP_DOUBLE, oper, TYP_DOUBLE);
322         }
323
324         // do we need to do it in two steps R -> I, '-> smallType
325 #if defined(_TARGET_ARM64_) || defined(_TARGET_AMD64_)
326         if (dstSize < genTypeSize(TYP_INT))
327         {
328             oper = gtNewCastNodeL(TYP_INT, oper, TYP_INT);
329             oper->gtFlags |= (tree->gtFlags & (GTF_UNSIGNED|GTF_OVERFLOW|GTF_EXCEPT));
330             tree->gtFlags &= ~GTF_UNSIGNED;
331         }
332 #else
333         if (dstSize < sizeof(void*))
334         {
335             oper = gtNewCastNodeL(TYP_I_IMPL, oper, TYP_I_IMPL);
336             oper->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW|GTF_EXCEPT));
337         }
338 #endif
339         else
340         {
341             /* Note that if we need to use a helper call then we can not morph oper */
342             if (!tree->gtOverflow())
343             {
344 #ifdef _TARGET_ARM64_    // On ARM64 All non-overflow checking conversions can be optimized
345                 goto OPTIMIZECAST;
346 #else
347                 switch (dstType)
348                 {
349                 case TYP_INT:
350 #ifdef _TARGET_X86_     // there is no rounding convert to integer instruction on ARM or x64 so skip this
351                     if ((oper->gtOper == GT_INTRINSIC) &&
352                         (oper->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round))
353                     {
354                         /* optimization: conv.i4(round.d(d)) -> round.i(d) */
355                         oper->gtType = dstType;
356                         return fgMorphTree(oper);
357                     }
358                     // if SSE2 is not enabled, we need the helper
359                     else if (!opts.compCanUseSSE2)
360                     {
361                         return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2INT, oper);
362                     }
363                     else
364 #endif // _TARGET_X86_
365                     {
366                         goto OPTIMIZECAST;
367                     }
368 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
369                 case TYP_UINT:  goto OPTIMIZECAST;
370 #else // _TARGET_ARM_
371                 case TYP_UINT:  return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2UINT, oper);
372 #endif // _TARGET_ARM_
373
374 #ifdef _TARGET_AMD64_
375                 // SSE2 has instructions to convert a float/double directly to a long
376                 case TYP_LONG:  goto OPTIMIZECAST;
377 #else
378                 case TYP_LONG:  return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2LNG, oper);
379 #endif //_TARGET_AMD64_
380                 case TYP_ULONG: return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2ULNG, oper);
381                 default: break;
382                 }
383 #endif // _TARGET_ARM64_
384             }
385             else
386             {
387                 switch (dstType)
388                 {
389                 case TYP_INT:   return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2INT_OVF, oper);
390                 case TYP_UINT:  return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2UINT_OVF, oper);
391                 case TYP_LONG:  return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2LNG_OVF, oper);
392                 case TYP_ULONG: return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2ULNG_OVF, oper);
393                 default: break;
394                 }
395             }
396             noway_assert(!"Unexpected dstType");
397         }
398     }
399 #ifndef _TARGET_64BIT_
400     // The code generation phase (for x86 & ARM32) does not handle casts
401     // directly from [u]long to anything other than [u]int. Insert an
402     // intermediate cast to native int.
403     else if (varTypeIsLong(srcType) && varTypeIsSmall(dstType))
404     {
405         oper = gtNewCastNode(TYP_I_IMPL, oper, TYP_I_IMPL);
406         oper->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW|GTF_EXCEPT|GTF_UNSIGNED));
407         tree->gtFlags &= ~GTF_UNSIGNED;
408     }
409 #endif //!_TARGET_64BIT_
410
411 #ifdef _TARGET_ARM_
412     else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && (oper->gtOper == GT_CAST) && !varTypeIsLong(oper->gtCast.CastOp()))
413     {
414         // optimization: conv.r4(conv.r8(?)) -> conv.r4(d)
415         // except when the ultimate source is a long because there is no long-to-float helper, so it must be 2 step.
416         // This happens semi-frequently because there is no IL 'conv.r4.un'
417         oper->gtType = TYP_FLOAT;
418         oper->CastToType() = TYP_FLOAT;
419         return fgMorphTree(oper);
420     }
421     // converts long/ulong --> float/double casts into helper calls.
422     else if (varTypeIsFloating(dstType) && varTypeIsLong(srcType))
423     {
424         if (dstType == TYP_FLOAT)
425         {
426             // there is only a double helper, so we
427             // - change the dsttype to double
428             // - insert a cast from double to float
429             // - recurse into the resulting tree
430             tree->CastToType() = TYP_DOUBLE;
431             tree->gtType = TYP_DOUBLE;
432
433             tree = gtNewCastNode(TYP_FLOAT, tree, TYP_FLOAT);
434
435             return fgMorphTree(tree);
436         }
437         if (tree->gtFlags & GTF_UNSIGNED)
438             return fgMorphCastIntoHelper(tree, CORINFO_HELP_ULNG2DBL, oper);
439         return fgMorphCastIntoHelper(tree, CORINFO_HELP_LNG2DBL, oper);
440     }
441 #endif //_TARGET_ARM_
442
443 #ifdef _TARGET_AMD64_
444     // Do we have to do two step U4/8 -> R4/8 ?
445     // Codegen supports the following conversion as one-step operation
446     // a) Long -> R4/R8
447     // b) U8 -> R8
448     //
449     // The following conversions are performed as two-step operations using above.
450     // U4 -> R4/8 = U4-> Long -> R4/8
451     // U8 -> R4   = U8 -> R8 -> R4
452     else if ((tree->gtFlags & GTF_UNSIGNED) && varTypeIsFloating(dstType))
453     {
454         srcType = genUnsignedType(srcType);
455
456         if (srcType == TYP_ULONG)
457         {
458             if (dstType == TYP_FLOAT)
459             {
460                 // Codegen can handle U8 -> R8 conversion.
461                 // U8 -> R4 =  U8 -> R8 -> R4
462                 // - change the dsttype to double
463                 // - insert a cast from double to float
464                 // - recurse into the resulting tree
465                 tree->CastToType() = TYP_DOUBLE;
466                 tree->gtType = TYP_DOUBLE;
467                 tree = gtNewCastNode(TYP_FLOAT, tree, TYP_FLOAT);
468                 return fgMorphTree(tree);
469             }
470         }
471         else if (srcType == TYP_UINT)
472         {
473             oper = gtNewCastNode(TYP_LONG, oper, TYP_LONG);
474             oper->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW|GTF_EXCEPT|GTF_UNSIGNED));
475             tree->gtFlags &= ~GTF_UNSIGNED;
476         }
477     }
478 #endif // _TARGET_AMD64_
479
480 #ifdef _TARGET_X86_
481     // Do we have to do two step U4/8 -> R4/8 ?
482     else if ((tree->gtFlags & GTF_UNSIGNED) && varTypeIsFloating(dstType))
483     {
484         srcType = genUnsignedType(srcType);
485
486         if (srcType == TYP_ULONG)
487         {
488             return fgMorphCastIntoHelper(tree, CORINFO_HELP_ULNG2DBL, oper);
489         }
490         else if (srcType == TYP_UINT)
491         {
492             oper = gtNewCastNode(TYP_LONG, oper, TYP_LONG);
493             oper->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW|GTF_EXCEPT|GTF_UNSIGNED));
494             tree->gtFlags &= ~GTF_UNSIGNED;
495         }
496     }
497 #endif //_TARGET_XARCH_
498     else if (varTypeIsGC(srcType) != varTypeIsGC(dstType))
499     {
500         // We are casting away GC information.  we would like to just
501         // change the type to int, however this gives the emitter fits because
502         // it believes the variable is a GC variable at the begining of the
503         // instruction group, but is not turned non-gc by the code generator
504         // we fix this by copying the GC pointer to a non-gc pointer temp.
505         noway_assert(!varTypeIsGC(dstType) && "How can we have a cast to a GCRef here?");
506
507         // We generate an assignment to an int and then do the cast from an int. With this we avoid
508         // the gc problem and we allow casts to bytes, longs,  etc...
509         unsigned lclNum = lvaGrabTemp(true DEBUGARG("Cast away GC"));
510         oper->gtType = TYP_I_IMPL;
511         GenTreePtr asg = gtNewTempAssign(lclNum, oper);
512         oper->gtType = srcType;
513
514         // do the real cast
515         GenTreePtr cast = gtNewCastNode(tree->TypeGet(), gtNewLclvNode(lclNum, TYP_I_IMPL), dstType);
516
517         // Generate the comma tree
518         oper = gtNewOperNode(GT_COMMA, tree->TypeGet(), asg, cast);
519
520         return fgMorphTree(oper);
521     }
522
523     // Look for narrowing casts ([u]long -> [u]int) and try to push them
524     // down into the operand before morphing it.
525     //
526     // It doesn't matter if this is cast is from ulong or long (i.e. if
527     // GTF_UNSIGNED is set) because the transformation is only applied to
528     // overflow-insensitive narrowing casts, which always silently truncate.
529     //
530     // Note that casts from [u]long to small integer types are handled above.
531     if ((srcType == TYP_LONG) &&
532         ((dstType == TYP_INT) || (dstType == TYP_UINT)))
533     {
534         // As a special case, look for overflow-sensitive casts of an AND
535         // expression, and see if the second operand is a small constant. Since
536         // the result of an AND is bound by its smaller operand, it may be
537         // possible to prove that the cast won't overflow, which will in turn
538         // allow the cast's operand to be transformed.
539         if (tree->gtOverflow() && (oper->OperGet() == GT_AND))
540         {
541             GenTreePtr andOp2 = oper->gtOp.gtOp2;
542
543             // Special case to the special case: AND with a casted int.
544             if ((andOp2->OperGet() == GT_CAST) &&
545                 (andOp2->gtCast.CastOp()->OperGet() == GT_CNS_INT))
546             {
547                 // gtFoldExprConst will deal with whether the cast is signed or
548                 // unsigned, or overflow-sensitive.
549                 andOp2 = oper->gtOp.gtOp2 = gtFoldExprConst(andOp2);
550             }
551
552             // Look for a constant less than 2^{32} for a cast to uint, or less
553             // than 2^{31} for a cast to int.
554             int maxWidth = (dstType == TYP_UINT) ? 32 : 31;
555
556             if ((andOp2->OperGet() == GT_CNS_NATIVELONG) &&
557                 ((andOp2->gtIntConCommon.LngValue() >> maxWidth) == 0))
558             {
559                 // This cast can't overflow.
560                 tree->gtFlags &= ~(GTF_OVERFLOW | GTF_EXCEPT);
561             }
562         }
563
564         // Only apply this transformation during global morph,
565         // when neither the cast node nor the oper node may throw an exception
566         // based on the upper 32 bits.
567         //
568         if (fgGlobalMorph                  &&
569             !tree->gtOverflow()            &&
570             !oper->gtOverflowEx())
571         {
572             // For these operations the lower 32 bits of the result only depends 
573             // upon the lower 32 bits of the operands
574             //
575             if ( (oper->OperGet() == GT_ADD) ||
576                  (oper->OperGet() == GT_MUL) ||
577                  (oper->OperGet() == GT_AND) ||
578                  (oper->OperGet() == GT_OR)  ||
579                  (oper->OperGet() == GT_XOR)    )
580             {
581                 DEBUG_DESTROY_NODE(tree);
582
583                 // Insert narrowing casts for op1 and op2
584                 oper->gtOp.gtOp1 = gtNewCastNode(TYP_INT, oper->gtOp.gtOp1, dstType);
585                 oper->gtOp.gtOp2 = gtNewCastNode(TYP_INT, oper->gtOp.gtOp2, dstType);
586
587                 // Clear the GT_MUL_64RSLT if it is set
588                 if  (oper->gtOper == GT_MUL && (oper->gtFlags & GTF_MUL_64RSLT))
589                     oper->gtFlags &= ~GTF_MUL_64RSLT;
590
591                 // The operation now produces a 32-bit result.
592                 oper->gtType = TYP_INT;
593
594                 // Remorph the new tree as the casts that we added may be folded away.
595                 return fgMorphTree(oper);
596             }
597         }
598     }
599
600 OPTIMIZECAST:
601     noway_assert(tree->gtOper == GT_CAST);
602
603     /* Morph the operand */
604     tree->gtCast.CastOp() = oper = fgMorphTree(oper);
605
606     /* Reset the call flag */
607     tree->gtFlags &= ~GTF_CALL;
608
609     /* unless we have an overflow cast, reset the except flag */
610     if (!tree->gtOverflow())
611         tree->gtFlags &= ~GTF_EXCEPT;
612
613     /* Just in case new side effects were introduced */
614     tree->gtFlags |= (oper->gtFlags & GTF_ALL_EFFECT);
615
616     srcType = oper->TypeGet();
617
618     /* if GTF_UNSIGNED is set then force srcType to an unsigned type */
619     if (tree->gtFlags & GTF_UNSIGNED)
620         srcType = genUnsignedType(srcType);
621
622     srcSize = genTypeSize(srcType);
623
624     if (!gtIsActiveCSE_Candidate(tree))     // tree cannot be a CSE candidate
625     {
626         /* See if we can discard the cast */
627         if (varTypeIsIntegral(srcType) && varTypeIsIntegral(dstType))
628         {
629             if (srcType == dstType) // Certainly if they are identical it is pointless
630                 goto REMOVE_CAST;
631
632             if (oper->OperGet() == GT_LCL_VAR && varTypeIsSmall(dstType))
633             {
634                 unsigned    varNum = oper->gtLclVarCommon.gtLclNum;
635                 LclVarDsc * varDsc = &lvaTable[varNum];
636                 if (varDsc->TypeGet() == dstType && varDsc->lvNormalizeOnStore())
637                     goto REMOVE_CAST;
638             }
639
640             bool  unsignedSrc = varTypeIsUnsigned(srcType);
641             bool  unsignedDst = varTypeIsUnsigned(dstType);
642             bool  signsDiffer = (unsignedSrc != unsignedDst);
643
644             // For same sized casts with
645             //    the same signs or non-overflow cast we discard them as well
646             if (srcSize == dstSize)
647             {
648                 /* This should have been handled above */
649                 noway_assert(varTypeIsGC(srcType) == varTypeIsGC(dstType));
650
651                 if (!signsDiffer)
652                     goto REMOVE_CAST;
653
654                 if (!tree->gtOverflow())
655                 {
656                     /* For small type casts, when necessary we force
657                        the src operand to the dstType and allow the
658                        implied load from memory to perform the casting */
659                     if (varTypeIsSmall(srcType))
660                     {
661                         switch (oper->gtOper)
662                         {
663                         case GT_IND:
664                         case GT_CLS_VAR:
665                         case GT_LCL_FLD:
666                         case GT_ARR_ELEM:
667                             oper->gtType = dstType;
668                             goto REMOVE_CAST;
669                         default: break;
670                         }
671                     }
672                     else
673                         goto REMOVE_CAST;
674                 }
675             }
676
677             if (srcSize < dstSize)  // widening cast
678             {
679                 // Keep any long casts
680                 if (dstSize == sizeof(int))
681                 {
682                     // Only keep signed to unsigned widening cast with overflow check
683                     if (!tree->gtOverflow() || !unsignedDst || unsignedSrc)
684                         goto REMOVE_CAST;
685                 }
686
687                 // Casts from signed->unsigned can never overflow while widening
688
689                 if (unsignedSrc || !unsignedDst)
690                     tree->gtFlags &= ~GTF_OVERFLOW;
691             }
692             else
693             {
694                 // Try to narrow the operand of the cast and discard the cast
695                 // Note: Do not narrow a cast that is marked as a CSE
696                 // And do not narrow if the oper is marked as a CSE either
697                 //
698                 if  (!tree->gtOverflow()                  &&
699                      !gtIsActiveCSE_Candidate(oper)       &&
700                      (opts.compFlags & CLFLG_TREETRANS)   &&
701                      optNarrowTree(oper, srcType, dstType, tree->gtVNPair, false))
702                 {
703                     optNarrowTree(oper, srcType, dstType,  tree->gtVNPair, true);
704                     
705                     /* If oper is changed into a cast to TYP_INT, or to a GT_NOP, we may need to discard it */
706                     if (oper->gtOper == GT_CAST && oper->CastToType() == genActualType(oper->CastFromType()))
707                     {
708                         oper = oper->gtCast.CastOp();
709                     }
710                     goto REMOVE_CAST;
711                 }
712             }
713         }
714         
715         switch (oper->gtOper)
716         {
717             /* If the operand is a constant, we'll fold it */
718         case GT_CNS_INT:
719         case GT_CNS_LNG:
720         case GT_CNS_DBL:
721         case GT_CNS_STR:
722             {
723                 GenTreePtr oldTree = tree;
724
725                 tree = gtFoldExprConst(tree);    // This may not fold the constant (NaN ...)
726
727                 // Did we get a comma throw as a result of gtFoldExprConst?
728                 if ((oldTree != tree) && (oldTree->gtOper != GT_COMMA))
729                 {
730                     noway_assert(fgIsCommaThrow(tree));
731                     tree->gtOp.gtOp1 = fgMorphTree(tree->gtOp.gtOp1);
732                     fgMorphTreeDone(tree);
733                     return tree;
734                 }
735                 else if (tree->gtOper != GT_CAST)
736                     return tree;
737
738                 noway_assert(tree->gtCast.CastOp() == oper); // unchanged
739             }
740             break;
741
742         case GT_CAST:
743             /* Check for two consecutive casts into the same dstType */
744             if (!tree->gtOverflow())
745             {
746                 var_types dstType2 = oper->CastToType();
747                 if (dstType == dstType2)
748                     goto REMOVE_CAST;
749             }
750             break;
751
752             /* If op1 is a mod node, mark it with the GTF_MOD_INT_RESULT flag
753                so that the code generator will know not to convert the result
754                of the idiv to a regpair */
755         case GT_MOD:
756             if (dstType == TYP_INT)
757                 tree->gtOp.gtOp1->gtFlags |= GTF_MOD_INT_RESULT;
758
759                 break;
760         case GT_UMOD:
761             if (dstType == TYP_UINT)
762                 tree->gtOp.gtOp1->gtFlags |= GTF_MOD_INT_RESULT;
763                 break;
764
765         case GT_COMMA:
766             // Check for cast of a GT_COMMA with a throw overflow
767             // Bug 110829: Since this optimization will bash the types 
768             // neither oper or commaOp2 can be CSE candidates
769             if (fgIsCommaThrow(oper)  &&
770                 !gtIsActiveCSE_Candidate(oper))   // oper can not be a CSE candidate
771             {
772                 GenTreePtr commaOp2 = oper->gtOp.gtOp2;
773
774                 if (!gtIsActiveCSE_Candidate(commaOp2))   // commaOp2 can not be a CSE candidate
775                 {
776                    // need type of oper to be same as tree
777                    if (tree->gtType == TYP_LONG)
778                    {
779                       commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
780                       commaOp2->gtIntConCommon.SetLngValue(0);
781                       /* Change the types of oper and commaOp2 to TYP_LONG */
782                       oper->gtType = commaOp2->gtType = TYP_LONG;
783                    }
784                    else if (varTypeIsFloating(tree->gtType))
785                    {
786                       commaOp2->ChangeOperConst(GT_CNS_DBL);
787                       commaOp2->gtDblCon.gtDconVal = 0.0;
788                       // Change the types of oper and commaOp2
789                       // X87 promotes everything to TYP_DOUBLE
790                       // But other's are a little more precise
791                       const var_types newTyp
792 #if FEATURE_X87_DOUBLES
793                                              = TYP_DOUBLE;
794 #else // FEATURE_X87_DOUBLES
795                                              = tree->gtType;
796 #endif // FEATURE_X87_DOUBLES
797                       oper->gtType = commaOp2->gtType = newTyp;
798                    }
799                    else
800                    {
801                       commaOp2->ChangeOperConst(GT_CNS_INT);
802                       commaOp2->gtIntCon.gtIconVal = 0;
803                       /* Change the types of oper and commaOp2 to TYP_INT */
804                       oper->gtType = commaOp2->gtType = TYP_INT;
805                    }
806                 }
807
808                 if (vnStore != nullptr)
809                 {
810                    fgValueNumberTreeConst(commaOp2);
811                 }
812
813                 /* Return the GT_COMMA node as the new tree */
814                 return oper;
815             }
816             break;
817
818         default:
819             break;
820         } /* end switch (oper->gtOper) */
821     }
822
823     if (tree->gtOverflow())
824         fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
825
826     return tree;
827
828 REMOVE_CAST:
829
830     /* Here we've eliminated the cast, so just return it's operand */
831     assert(!gtIsActiveCSE_Candidate(tree));     // tree cannot be a CSE candidate
832
833     DEBUG_DESTROY_NODE(tree);
834     return oper;
835 }
836 #ifdef _PREFAST_
837 #pragma warning(pop)
838 #endif
839
840 /*****************************************************************************
841  *
842  *  Perform an unwrap operation on a Proxy object
843  */
844
845 GenTreePtr          Compiler::fgUnwrapProxy(GenTreePtr objRef)
846 {
847     assert(info.compIsContextful  &&
848            info.compUnwrapContextful &&
849            impIsThis(objRef));
850
851     CORINFO_EE_INFO * pInfo   = eeGetEEInfo();
852     GenTreePtr        addTree;
853
854     // Perform the unwrap:
855     //
856     //   This requires two extra indirections.
857     //   We mark these indirections as 'invariant' and
858     //   the CSE logic will hoist them when appropriate.
859     //
860     //  Note that each dereference is a GC pointer
861
862     addTree = gtNewOperNode(GT_ADD, TYP_I_IMPL,
863                             objRef,
864                             gtNewIconNode(pInfo->offsetOfTransparentProxyRP, TYP_I_IMPL));
865
866     objRef           = gtNewOperNode(GT_IND, TYP_REF, addTree);
867     objRef->gtFlags |= GTF_IND_INVARIANT;
868
869     addTree = gtNewOperNode(GT_ADD, TYP_I_IMPL,
870                             objRef,
871                             gtNewIconNode(pInfo->offsetOfRealProxyServer, TYP_I_IMPL));
872
873     objRef           = gtNewOperNode(GT_IND, TYP_REF, addTree);
874     objRef->gtFlags |= GTF_IND_INVARIANT;
875
876     // objRef now hold the 'real this' reference (i.e. the unwrapped proxy)
877     return objRef;
878 }
879
880 /*****************************************************************************
881  *
882  *  Morph an argument list; compute the pointer argument count in the process.
883  *
884  *  NOTE: This function can be called from any place in the JIT to perform re-morphing
885  *  due to graph altering modifications such as copy / constant propagation
886  */
887
888 unsigned UpdateGT_LISTFlags(GenTreePtr tree)
889 {
890     assert(tree->gtOper == GT_LIST);
891
892     unsigned flags = 0;
893     if (tree->gtOp.gtOp2)
894     {
895         flags |= UpdateGT_LISTFlags(tree->gtOp.gtOp2);
896     }
897
898     flags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
899
900     tree->gtFlags &= ~GTF_ALL_EFFECT;
901     tree->gtFlags |= flags;
902
903     return tree->gtFlags;
904 }
905
906 #ifdef DEBUG
907 void fgArgTabEntry::Dump()
908 {
909     if (regNum == REG_STK)
910     {
911         printf("fgArgTabEntry[arg%d, stk%02x, slots=%d", argNum, slotNum, numSlots);
912     }
913     else
914     {
915 #ifdef _TARGET_ARM64_
916         if (emitter::isFloatReg(regNum))
917         {
918             printf("fgArgTabEntry[arg%d, d%d, regs=%d", argNum, regNum-REG_FP_FIRST, numRegs);
919         }
920         else   // integer register
921         {
922             printf("fgArgTabEntry[arg%d, x%d, regs=%d", argNum, regNum-REG_INT_FIRST, numRegs);
923         }
924 #else
925         printf("fgArgTabEntry[arg%02d, r%d, regs=%d", argNum, regNum, numRegs);
926 #endif
927     }
928     if (needTmp)
929     {
930         printf(", tmpNum=V%02d", tmpNum);
931     }
932     if (isHfaRegArg)
933     {
934         printf(", isHfa");
935     }
936     printf("]\n");
937 }
938 #endif
939
940 fgArgInfo::fgArgInfo(Compiler *  comp,  GenTreePtr  call, unsigned numArgs)
941 {
942     compiler     = comp;
943     callTree     = call;    assert(call->IsCall());
944     argCount     = 0;       // filled in arg count, starts at zero
945     nextSlotNum  = INIT_ARG_STACK_SLOT;
946     stkLevel     = 0;
947     argTableSize = numArgs; // the allocated table size
948     argsComplete = false;
949     argsSorted   = false;
950
951     if (argTableSize == 0)
952         argTable = NULL;
953     else
954         argTable = new(compiler, CMK_fgArgInfoPtrArr) fgArgTabEntryPtr[argTableSize];
955  }
956
957 /*****************************************************************************
958  *
959  *  fgArgInfo Copy Constructor
960  *
961  *  This method needs to act like a copy constructor for fgArgInfo.
962  *  The newCall needs to have its fgArgInfo initialized such that
963  *  we have newCall that is an exact copy of the oldCall.
964  *  We have to take care since the argument information
965  *  in the argTable contains pointers that must point to the
966  *  new arguments and not the old arguments.
967  */
968 fgArgInfo::fgArgInfo(GenTreePtr  newCall, GenTreePtr  oldCall)
969 {
970     assert(oldCall->IsCall());
971     assert(newCall->IsCall());
972
973     fgArgInfoPtr oldArgInfo = oldCall->gtCall.fgArgInfo;
974
975     compiler     = oldArgInfo->compiler;;
976     callTree     = newCall;  assert(newCall->IsCall());
977     argCount     = 0;       // filled in arg count, starts at zero
978     nextSlotNum  = INIT_ARG_STACK_SLOT;
979     stkLevel     = oldArgInfo->stkLevel;
980     argTableSize = oldArgInfo->argTableSize;
981     argsComplete = false;
982     argTable     = NULL;
983     if (argTableSize > 0)
984     {
985         argTable = new(compiler, CMK_fgArgInfoPtrArr) fgArgTabEntryPtr[argTableSize];
986         for (unsigned inx=0; inx<argTableSize; inx++)
987         {
988             argTable[inx] = NULL;
989         }
990     }
991
992     assert(oldArgInfo->argsComplete);
993
994     // We create local, artificial GenTreeArgLists that includes the gtCallObjp, if that exists, as first argument,
995     // so we can iterate over these argument lists more uniformly.
996     // Need to provide a temporary non-null first arguments to these constructors: if we use them, we'll replace them
997     GenTreeArgList* newArgs;
998     GenTreeArgList newArgObjp(newCall, newCall->gtCall.gtCallArgs);
999     GenTreeArgList* oldArgs;
1000     GenTreeArgList oldArgObjp(oldCall, oldCall->gtCall.gtCallArgs);
1001
1002     if (newCall->gtCall.gtCallObjp == NULL)
1003     {
1004         assert(oldCall->gtCall.gtCallObjp == NULL);
1005         newArgs = newCall->gtCall.gtCallArgs;
1006         oldArgs = oldCall->gtCall.gtCallArgs;
1007     }
1008     else
1009     {
1010         assert(oldCall->gtCall.gtCallObjp != NULL);
1011         newArgObjp.Current() = newCall->gtCall.gtCallArgs;
1012         newArgs = &newArgObjp;
1013         oldArgObjp.Current() = oldCall->gtCall.gtCallObjp;
1014         oldArgs = &oldArgObjp;
1015     }
1016
1017     GenTreePtr          newCurr;
1018     GenTreePtr          oldCurr;
1019     GenTreeArgList*     newParent   = NULL;
1020     GenTreeArgList*     oldParent   = NULL;
1021     fgArgTabEntryPtr *  oldArgTable = oldArgInfo->argTable;
1022     bool                scanRegArgs = false;
1023
1024     while (newArgs)
1025     {
1026         /* Get hold of the next argument values for the oldCall and newCall */
1027
1028         newCurr = newArgs->Current();
1029         oldCurr = oldArgs->Current();
1030         if (newArgs != &newArgObjp)
1031         {
1032             newParent = newArgs;
1033             oldParent = oldArgs;
1034         }
1035         else
1036         {
1037             assert(newParent == NULL && oldParent == NULL);
1038         }
1039         newArgs = newArgs->Rest();
1040         oldArgs = oldArgs->Rest();
1041
1042         fgArgTabEntryPtr oldArgTabEntry = NULL;
1043         fgArgTabEntryPtr newArgTabEntry = NULL;
1044
1045         for (unsigned inx=0; inx<argTableSize; inx++)
1046         {
1047             oldArgTabEntry = oldArgTable[inx];
1048
1049             if (oldArgTabEntry->parent == oldParent)
1050             {
1051                 assert((oldParent == NULL) == (newParent == NULL));
1052
1053                 // We have found the matching "parent" field in oldArgTabEntry
1054
1055                 newArgTabEntry = new (compiler, CMK_fgArgInfo) fgArgTabEntry;
1056
1057                 // First block copy all fields
1058                 //
1059                 *newArgTabEntry = *oldArgTabEntry;
1060
1061                 // Then update all GenTreePtr fields in the newArgTabEntry
1062                 //
1063                 newArgTabEntry->parent = newParent;
1064
1065                 // The node field is likely to have been updated
1066                 //  to point at a node in the gtCallLateArgs list
1067                 //
1068                 if (oldArgTabEntry->node == oldCurr)
1069                 {
1070                     // node is not pointing into the gtCallLateArgs list
1071                     newArgTabEntry->node = newCurr;
1072                 }
1073                 else
1074                 {
1075                     // node must be pointing into the gtCallLateArgs list
1076                     //
1077                     // We will fix this pointer up in the next loop
1078                     //
1079                     newArgTabEntry->node = NULL;  // For now we assign a NULL to this field
1080
1081                     scanRegArgs = true;
1082                 }
1083
1084                 // Now initialize the proper element in the argTable array
1085                 //
1086                 argTable[inx] = newArgTabEntry;
1087                 break;
1088             }
1089         }
1090         // We should have found the matching oldArgTabEntry and created the newArgTabEntry
1091         //
1092         assert(newArgTabEntry != NULL);
1093     }
1094
1095     if (scanRegArgs)
1096     {
1097         newArgs = newCall->gtCall.gtCallLateArgs;
1098         oldArgs = oldCall->gtCall.gtCallLateArgs;
1099
1100         while (newArgs)
1101         {
1102             /* Get hold of the next argument values for the oldCall and newCall */
1103
1104             assert(newArgs->IsList());
1105
1106             newCurr = newArgs->Current();
1107             newArgs = newArgs->Rest();
1108
1109             assert(oldArgs->IsList());
1110
1111             oldCurr = oldArgs->Current();
1112             oldArgs = oldArgs->Rest();
1113
1114             fgArgTabEntryPtr oldArgTabEntry = NULL;
1115             fgArgTabEntryPtr newArgTabEntry = NULL;
1116
1117             for (unsigned inx=0; inx<argTableSize; inx++)
1118             {
1119                 oldArgTabEntry = oldArgTable[inx];
1120
1121                 if (oldArgTabEntry->node == oldCurr)
1122                 {
1123                     // We have found the matching "node" field in oldArgTabEntry
1124
1125                     newArgTabEntry = argTable[inx];
1126                     assert(newArgTabEntry != NULL);
1127
1128                     // update the "node" GenTreePtr fields in the newArgTabEntry
1129                     //
1130                     assert(newArgTabEntry->node == NULL);  // We previously assigned NULL to this field
1131
1132                     newArgTabEntry->node = newCurr;
1133                     break;
1134                 }
1135             }
1136         }
1137     }
1138
1139     argCount     = oldArgInfo->argCount;
1140     nextSlotNum  = oldArgInfo->nextSlotNum;
1141     argsComplete = true;
1142     argsSorted   = true;
1143 }
1144
1145 void fgArgInfo::AddArg(fgArgTabEntryPtr curArgTabEntry)
1146 {
1147     assert(argCount < argTableSize);
1148     argTable[argCount] = curArgTabEntry;
1149     argCount++;
1150 }
1151
1152 fgArgTabEntryPtr fgArgInfo::AddRegArg(unsigned    argNum,
1153                                       GenTreePtr  node,
1154                                       GenTreePtr  parent,
1155                                       regNumber   regNum,
1156                                       unsigned    numRegs,
1157                                       unsigned    alignment)
1158 {
1159     fgArgTabEntryPtr curArgTabEntry = new(compiler, CMK_fgArgInfo) fgArgTabEntry;
1160
1161     curArgTabEntry->argNum =            argNum;
1162     curArgTabEntry->node =              node;
1163     curArgTabEntry->parent =            parent;
1164     curArgTabEntry->regNum =            regNum;
1165     curArgTabEntry->slotNum =           0;
1166     curArgTabEntry->numRegs =           numRegs;
1167     curArgTabEntry->numSlots =          0;
1168     curArgTabEntry->alignment =         alignment;
1169     curArgTabEntry->lateArgInx =        (unsigned)-1;
1170     curArgTabEntry->tmpNum =            (unsigned)-1;
1171     curArgTabEntry->isSplit =           false;
1172     curArgTabEntry->isTmp =             false;
1173     curArgTabEntry->needTmp =           false;
1174     curArgTabEntry->needPlace =         false;
1175     curArgTabEntry->processed =         false;
1176     curArgTabEntry->isHfaRegArg =       false;
1177     curArgTabEntry->isBackFilled =      false;
1178     curArgTabEntry->isNonStandard =     false;
1179
1180     AddArg(curArgTabEntry);
1181     return curArgTabEntry;
1182 }
1183
1184 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1185 fgArgTabEntryPtr fgArgInfo::AddRegArg(unsigned          argNum,
1186                                       GenTreePtr        node,
1187                                       GenTreePtr        parent,
1188                                       regNumber         regNum,
1189                                       unsigned          numRegs,
1190                                       unsigned          alignment,
1191                                       const bool        isStruct,
1192                                       const regNumber   otherRegNum,
1193                                       const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr)
1194 {
1195     fgArgTabEntryPtr curArgTabEntry = AddRegArg(argNum, node, parent, regNum, numRegs, alignment);
1196     assert(curArgTabEntry != nullptr);
1197
1198     // The node of the ArgTabEntry could change after remorphing - it could be rewritten to a cpyblk or a
1199     // PlaceHolder node (in case of needed late argument, for example.)
1200     // This requires using of an extra flag. At creation time the state is right, so
1201     // and this assert enforces that.
1202     assert((varTypeIsStruct(node) && isStruct) || (!varTypeIsStruct(node) && !isStruct));
1203     curArgTabEntry->otherRegNum = otherRegNum;                       // Second reg for the struct
1204     curArgTabEntry->isStruct = isStruct;                             // is this a struct arg
1205
1206     if (isStruct && structDescPtr != nullptr)
1207     {
1208         curArgTabEntry->structDesc.CopyFrom(*structDescPtr);
1209     }
1210
1211     return curArgTabEntry;
1212 }
1213 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1214
1215 fgArgTabEntryPtr fgArgInfo::AddStkArg(unsigned    argNum,
1216                                       GenTreePtr  node,
1217                                       GenTreePtr  parent,
1218                                       unsigned    numSlots,
1219                                       unsigned    alignment
1220                                       FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool isStruct))
1221 {
1222     fgArgTabEntryPtr curArgTabEntry = new(compiler, CMK_fgArgInfo) fgArgTabEntry;
1223
1224     nextSlotNum = (unsigned)roundUp(nextSlotNum, alignment);
1225
1226 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1227     // The node of the ArgTabEntry could change after remorphing - it could be rewritten to a cpyblk or a
1228     // PlaceHolder node (in case of needed late argument, for example.)
1229     // This reqires using of an extra flag. At creation time the state is right, so
1230     // and this assert enforces that.
1231     assert((varTypeIsStruct(node) && isStruct) || (!varTypeIsStruct(node) && !isStruct));
1232     curArgTabEntry->isStruct = isStruct;                             // is this a struct arg
1233 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1234
1235     curArgTabEntry->argNum        = argNum;
1236     curArgTabEntry->node          = node;
1237     curArgTabEntry->parent        = parent;
1238     curArgTabEntry->regNum        = REG_STK;
1239     curArgTabEntry->slotNum       = nextSlotNum;
1240     curArgTabEntry->numRegs       = 0;
1241     curArgTabEntry->numSlots      = numSlots;
1242     curArgTabEntry->alignment     = alignment;
1243     curArgTabEntry->lateArgInx    = (unsigned) -1;
1244     curArgTabEntry->tmpNum        = (unsigned) -1;
1245     curArgTabEntry->isSplit       = false;
1246     curArgTabEntry->isTmp         = false;
1247     curArgTabEntry->needTmp       = false;
1248     curArgTabEntry->needPlace     = false;
1249     curArgTabEntry->processed     = false;
1250     curArgTabEntry->isHfaRegArg   = false;
1251     curArgTabEntry->isBackFilled  = false;
1252     curArgTabEntry->isNonStandard = false;
1253
1254     AddArg(curArgTabEntry);
1255
1256     nextSlotNum += numSlots;
1257     return curArgTabEntry;
1258 }
1259
1260 void fgArgInfo::RemorphReset()
1261 {
1262     nextSlotNum = INIT_ARG_STACK_SLOT;
1263 }
1264
1265 fgArgTabEntry* fgArgInfo::RemorphRegArg(unsigned    argNum,
1266                                         GenTreePtr  node,
1267                                         GenTreePtr  parent,
1268                                         regNumber   regNum,
1269                                         unsigned    numRegs,
1270                                         unsigned    alignment)
1271 {
1272     fgArgTabEntryPtr  curArgTabEntry = NULL;
1273     unsigned          regArgInx      = 0;
1274     unsigned          inx;
1275
1276     for (inx=0; inx < argCount; inx++)
1277     {
1278         curArgTabEntry = argTable[inx];
1279         if (curArgTabEntry->argNum == argNum)
1280             break;
1281
1282         bool isRegArg;
1283         GenTreePtr argx;
1284         if (curArgTabEntry->parent != NULL)
1285         {
1286             assert(curArgTabEntry->parent->IsList());
1287             argx     = curArgTabEntry->parent->Current();
1288             isRegArg = (argx->gtFlags & GTF_LATE_ARG) != 0;
1289         }
1290         else
1291         {
1292             argx     = curArgTabEntry->node;
1293             isRegArg = true;
1294         }
1295
1296         if (isRegArg)
1297         {
1298             regArgInx++;
1299         }
1300     }
1301     // if this was a nonstandard arg the table is definitive
1302     if (curArgTabEntry->isNonStandard)
1303         regNum = curArgTabEntry->regNum;
1304
1305     assert(curArgTabEntry->argNum    == argNum);
1306     assert(curArgTabEntry->regNum    == regNum);
1307     assert(curArgTabEntry->alignment == alignment);
1308     assert(curArgTabEntry->parent    == parent);
1309
1310     if (curArgTabEntry->node != node)
1311     {
1312         GenTreePtr  argx     = NULL;
1313         unsigned    regIndex = 0;
1314
1315         /* process the register argument list */
1316         for (GenTreeArgList* list = callTree->gtCall.gtCallLateArgs; list; (regIndex++, list = list->Rest()))
1317         {
1318             argx = list->Current();
1319             assert(!argx->IsArgPlaceHolderNode());  // No place holders nodes are in gtCallLateArgs;
1320             if (regIndex == regArgInx)
1321                 break;
1322         }
1323         assert(regIndex == regArgInx);
1324         assert(regArgInx == curArgTabEntry->lateArgInx);
1325
1326         if (curArgTabEntry->node != argx)
1327         {
1328             curArgTabEntry->node = argx;
1329         }
1330     }
1331     return curArgTabEntry;
1332 }
1333
1334 void fgArgInfo::RemorphStkArg(unsigned    argNum,
1335                               GenTreePtr  node,
1336                               GenTreePtr  parent,
1337                               unsigned    numSlots,
1338                               unsigned    alignment)
1339 {
1340     fgArgTabEntryPtr  curArgTabEntry = NULL;
1341     bool              isRegArg       = false;
1342     unsigned          regArgInx      = 0;
1343     GenTreePtr        argx;
1344     unsigned          inx;
1345
1346     for (inx=0; inx < argCount; inx++)
1347     {
1348         curArgTabEntry = argTable[inx];
1349
1350         if (curArgTabEntry->parent != NULL)
1351         {
1352             assert(curArgTabEntry->parent->IsList());
1353             argx     = curArgTabEntry->parent->Current();
1354             isRegArg = (argx->gtFlags & GTF_LATE_ARG) != 0;
1355         }
1356         else
1357         {
1358             argx     = curArgTabEntry->node;
1359             isRegArg = true;
1360         }
1361
1362         if (curArgTabEntry->argNum == argNum)
1363             break;
1364
1365         if (isRegArg)
1366             regArgInx++;
1367     }
1368
1369     nextSlotNum = (unsigned) roundUp(nextSlotNum, alignment);
1370
1371     assert(curArgTabEntry->argNum    == argNum);
1372     assert(curArgTabEntry->slotNum   == nextSlotNum);
1373     assert(curArgTabEntry->numSlots  == numSlots);
1374     assert(curArgTabEntry->alignment == alignment);
1375     assert(curArgTabEntry->parent    == parent);
1376     assert(parent->IsList());
1377
1378 #if FEATURE_FIXED_OUT_ARGS
1379     if (curArgTabEntry->node != node)
1380     {
1381         if (isRegArg)
1382         {
1383             GenTreePtr  argx     = NULL;
1384             unsigned    regIndex = 0;
1385
1386             /* process the register argument list */
1387             for (GenTreeArgList * list = callTree->gtCall.gtCallLateArgs; list; list = list->Rest(), regIndex++)
1388             {
1389                 argx = list->Current();
1390                 assert(!argx->IsArgPlaceHolderNode());  // No place holders nodes are in gtCallLateArgs;
1391                 if (regIndex == regArgInx)
1392                     break;
1393             }
1394             assert(regIndex == regArgInx);
1395             assert(regArgInx == curArgTabEntry->lateArgInx);
1396
1397             if (curArgTabEntry->node != argx)
1398             {
1399                 curArgTabEntry->node = argx;
1400             }
1401         }
1402         else
1403         {
1404             assert(parent->Current() == node);
1405             curArgTabEntry->node = node;
1406         }
1407     }
1408 #else
1409     curArgTabEntry->node = node;
1410 #endif
1411
1412     nextSlotNum += numSlots;
1413 }
1414
1415 void fgArgInfo::SplitArg(unsigned  argNum,
1416                          unsigned  numRegs,
1417                          unsigned  numSlots)
1418 {
1419     fgArgTabEntryPtr  curArgTabEntry = NULL;
1420     assert(argNum < argCount);
1421     for (unsigned inx=0; inx < argCount; inx++)
1422     {
1423         curArgTabEntry = argTable[inx];
1424         if (curArgTabEntry->argNum == argNum)
1425             break;
1426     }
1427
1428     assert(numRegs  > 0);
1429     assert(numSlots > 0);
1430
1431     curArgTabEntry->isSplit  = true;
1432     curArgTabEntry->numRegs  = numRegs;
1433     curArgTabEntry->numSlots = numSlots;
1434
1435     nextSlotNum += numSlots;
1436 }
1437
1438 void fgArgInfo::EvalToTmp(unsigned    argNum,
1439                           unsigned    tmpNum,
1440                           GenTreePtr  newNode)
1441 {
1442     fgArgTabEntryPtr  curArgTabEntry = NULL;
1443     assert(argNum < argCount);
1444     for (unsigned inx=0; inx < argCount; inx++)
1445     {
1446         curArgTabEntry = argTable[inx];
1447         if (curArgTabEntry->argNum == argNum)
1448             break;
1449     }
1450     assert(curArgTabEntry->parent->Current() == newNode);
1451
1452     curArgTabEntry->node    = newNode;
1453     curArgTabEntry->tmpNum  = tmpNum;
1454     curArgTabEntry->isTmp   = true;
1455 }
1456
1457 void fgArgInfo::ArgsComplete()
1458 {
1459     bool hasStackArgs    = false;
1460     bool hasStructRegArg = false;
1461
1462     for (unsigned curInx = 0; curInx < argCount; curInx++)
1463     {
1464         fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1465         assert(curArgTabEntry != NULL);
1466         GenTreePtr       argx           = curArgTabEntry->node;
1467
1468 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1469         // If this is a struct, mark it for needing a tempVar.
1470         // In the copyblk and store this should have minimal perf impact since 
1471         // the local vars where we copy/store to already exist and the logic for temp 
1472         // var will not create a new one if it creates a tempVar from another tempVar.
1473         // (Debugging through the code, there was no new copy of data created, neither a new tempVar.)
1474         // The need for this arise from Lower::LowerArg. 
1475         // In case of copyblk and store operation, the NewPutArg method will 
1476         // not be invoked and the struct will not be loaded to be passed in
1477         // registers or by value on the stack.
1478         if (varTypeIsStruct(argx) FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY( || curArgTabEntry->isStruct))
1479         {
1480             curArgTabEntry->needTmp = true;
1481         }
1482 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1483
1484         if (curArgTabEntry->regNum == REG_STK)
1485         {
1486             hasStackArgs = true;
1487 #if !FEATURE_FIXED_OUT_ARGS
1488             // On x86 we use push instructions to pass arguments:
1489             //   The non-register arguments are evaluated and pushed in order
1490             //   and they are never evaluated into temps
1491             //
1492             continue;
1493 #endif
1494         }
1495         else // we have a register argument, next we look for a struct type.
1496         {
1497             if (varTypeIsStruct(argx)
1498                 FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY( || curArgTabEntry->isStruct))
1499             {
1500                 hasStructRegArg = true;
1501             }
1502         }
1503
1504         /* If the argument tree contains an assignment (GTF_ASG) then the argument and
1505            and every earlier argument (except constants) must be evaluated into temps
1506            since there may be other arguments that follow and they may use the value being assigned.
1507
1508            EXAMPLE: ArgTab is "a, a=5, a"
1509                     -> when we see the second arg "a=5"
1510                        we know the first two arguments "a, a=5" have to be evaluated into temps
1511
1512            For the case of an assignment, we only know that there exist some assignment someplace
1513            in the tree.  We don't know what is being assigned so we are very conservative here
1514            and assume that any local variable could have been assigned.
1515          */
1516
1517         if (argx->gtFlags & GTF_ASG)
1518         {
1519             // If this is not the only argument, or it's a copyblk, or it already evaluates the expression to
1520             // a tmp, then we need a temp in the late arg list.
1521             if ((argCount > 1) || argx->OperIsCopyBlkOp()
1522 #ifdef FEATURE_FIXED_OUT_ARGS
1523                 || curArgTabEntry->isTmp   // I protect this by "FEATURE_FIXED_OUT_ARGS" to preserve the property
1524                                            // that we only have late non-register args when that feature is on.
1525 #endif // FEATURE_FIXED_OUT_ARGS
1526                 )
1527             {
1528                 curArgTabEntry->needTmp = true;
1529             }
1530
1531             // For all previous arguments, unless they are a simple constant
1532             //  we require that they be evaluated into temps
1533             for (unsigned prevInx = 0; prevInx < curInx; prevInx++)
1534             {
1535                 fgArgTabEntryPtr prevArgTabEntry  = argTable[prevInx];
1536                 assert(prevArgTabEntry->argNum < curArgTabEntry->argNum);
1537
1538                 assert(prevArgTabEntry->node);
1539                 if (prevArgTabEntry->node->gtOper != GT_CNS_INT)
1540                 {
1541                     prevArgTabEntry->needTmp = true;
1542                 }
1543             }
1544         }
1545
1546 #if FEATURE_FIXED_OUT_ARGS
1547         // Like calls, if this argument has a tree that will do an inline throw,
1548         // a call to a jit helper, then we need to treat it like a call (but only
1549         // if there are/were any stack args).
1550         // This means unnesting, sorting, etc.  Technically this is overly
1551         // conservative, but I want to avoid as much special-case debug-only code
1552         // as possible, so leveraging the GTF_CALL flag is the easiest.
1553         if (!(argx->gtFlags & GTF_CALL) &&
1554             (argx->gtFlags & GTF_EXCEPT) &&
1555             (argCount > 1) &&
1556             compiler->opts.compDbgCode &&
1557             (compiler->fgWalkTreePre(&argx, Compiler::fgChkThrowCB) == Compiler::WALK_ABORT))
1558         {
1559             for (unsigned otherInx = 0; otherInx < argCount; otherInx++)
1560             {
1561                 if (otherInx == curInx)
1562                     continue;
1563
1564                 if (argTable[otherInx]->regNum == REG_STK)
1565                 {
1566                     argx->gtFlags |= GTF_CALL;
1567                     break;
1568                 }
1569             }
1570         }
1571 #endif // FEATURE_FIXED_OUT_ARGS
1572
1573         /* If it contains a call (GTF_CALL) then itself and everything before the call
1574            with a GLOB_EFFECT must eval to temp (this is because everything with SIDE_EFFECT
1575            has to be kept in the right order since we will move the call to the first position)
1576
1577            For calls we don't have to be quite as conservative as we are with an assignment
1578            since the call won't be modifying any non-address taken LclVars.
1579          */
1580
1581         if (argx->gtFlags & GTF_CALL)
1582         {
1583             if (argCount > 1)       // If this is not the only argument
1584             {
1585                 curArgTabEntry->needTmp = true;
1586             }
1587             else if (varTypeIsFloating(argx->TypeGet()) && (argx->OperGet() == GT_CALL))
1588             {
1589                 // Spill all arguments that are floating point calls
1590                 curArgTabEntry->needTmp = true;
1591             }
1592
1593             // All previous arguments may need to be evaluated into temps
1594             for (unsigned prevInx = 0; prevInx < curInx; prevInx++)
1595             {
1596                 fgArgTabEntryPtr prevArgTabEntry  = argTable[prevInx];
1597                 assert(prevArgTabEntry->argNum < curArgTabEntry->argNum);
1598                 assert(prevArgTabEntry->node);
1599
1600                 // For all previous arguments, if they have any GTF_ALL_EFFECT
1601                 //  we require that they be evaluated into a temp
1602                 if ((prevArgTabEntry->node->gtFlags & GTF_ALL_EFFECT) != 0)
1603                 {
1604                     prevArgTabEntry->needTmp = true;
1605                 }
1606 #if FEATURE_FIXED_OUT_ARGS
1607                 // Or, if they are stored into the FIXED_OUT_ARG area
1608                 // we require that they be moved to the gtCallLateArgs
1609                 // and replaced with a placeholder node
1610                 else if (prevArgTabEntry->regNum == REG_STK)
1611                 {
1612                     prevArgTabEntry->needPlace = true;
1613                 }
1614 #endif
1615             }
1616         }
1617
1618 #ifndef LEGACY_BACKEND
1619         // For RyuJIT backend we will expand a Multireg arg into a GT_LIST 
1620         // with multiple indirections, so here we consider spilling it into a tmp LclVar.
1621         //
1622         // Note that Arm32 is a LEGACY_BACKEND and it defines FEATURE_MULTIREG_ARGS
1623         // so we skip this for ARM32 until it is ported to use RyuJIT backend
1624         //
1625 #if FEATURE_MULTIREG_ARGS
1626         if ((argx->TypeGet() == TYP_STRUCT) &&
1627             (curArgTabEntry->numRegs > 1)   && 
1628             (curArgTabEntry->needTmp == false))
1629         {           
1630             if ((argx->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) != 0)
1631             {
1632                 // Spill multireg struct arguments that have Assignments or Calls embedded in them
1633                 curArgTabEntry->needTmp = true;
1634             }
1635             else
1636             {
1637                 // We call gtPrepareCost to measure the cost of evaluating this tree
1638                 compiler->gtPrepareCost(argx);
1639
1640                 if (argx->gtCostEx > (6 * IND_COST_EX))
1641                 {
1642                     // Spill multireg struct arguments that are expensive to evaluate twice
1643                     curArgTabEntry->needTmp = true;
1644                 }
1645                 else if (argx->OperGet() == GT_OBJ)
1646                 {
1647                     GenTreeObj*           argObj     = argx->AsObj();
1648                     CORINFO_CLASS_HANDLE  objClass   = argObj->gtClass;
1649                     unsigned              structSize = compiler->info.compCompHnd->getClassSize(objClass);
1650                     switch (structSize)
1651                     {
1652                     case 11:
1653                     case 13:
1654                     case 14:
1655                     case 15:
1656                         // Spill any GT_OBJ multireg structs that are difficult to extract
1657                         //
1658                         // When we have a GT_OBJ of a struct with the above sizes we would need
1659                         // to use 3 or 4 load instructions to load the exact size of this struct.
1660                         // Instead we spill the GT_OBJ into a new GT_LCL_VAR temp and this sequence
1661                         // will use a GT_CPBLK to copy the exact size into the GT_LCL_VAR temp.
1662                         // Then we can just load all 16 bytes of the GT_LCL_VAR temp when passing
1663                         // the argument.
1664                         //
1665                         curArgTabEntry->needTmp = true;
1666                         break;
1667
1668                     default:
1669                         break;
1670                     }
1671                 }
1672             }
1673         }
1674 #endif // FEATURE_MULTIREG_ARGS
1675 #endif // LEGACY_BACKEND
1676     }
1677
1678
1679     // We only care because we can't spill structs and qmarks involve a lot of spilling, but
1680     // if we don't have qmarks, then it doesn't matter.
1681     // So check for Qmark's globally once here, instead of inside the loop.
1682     //
1683     const bool hasStructRegArgWeCareAbout = (hasStructRegArg && compiler->compQmarkUsed);
1684
1685 #if FEATURE_FIXED_OUT_ARGS
1686
1687     // For Arm/x64 we only care because we can't reorder a register
1688     // argument that uses GT_LCLHEAP.  This is an optimization to
1689     // save a check inside the below loop.
1690     //
1691     const bool hasStackArgsWeCareAbout = (hasStackArgs && compiler->compLocallocUsed);
1692
1693 #else
1694
1695     const bool hasStackArgsWeCareAbout = hasStackArgs;
1696
1697 #endif // FEATURE_FIXED_OUT_ARGS
1698
1699     // If we have any stack args we have to force the evaluation
1700     // of any arguments passed in registers that might throw an exception
1701     //
1702     // Technically we only a required to handle the following two cases:
1703     //     a GT_IND with GTF_IND_RNGCHK (only on x86) or
1704     //     a GT_LCLHEAP node that allocates stuff on the stack
1705     //
1706     if (hasStackArgsWeCareAbout || hasStructRegArgWeCareAbout)
1707     {
1708         for (unsigned curInx = 0; curInx < argCount; curInx++)
1709         {
1710             fgArgTabEntryPtr curArgTabEntry  = argTable[curInx];        assert(curArgTabEntry != NULL);
1711             GenTreePtr       argx            = curArgTabEntry->node;
1712
1713             // Examine the register args that are currently not marked needTmp
1714             //
1715             if (!curArgTabEntry->needTmp && (curArgTabEntry->regNum != REG_STK))
1716             {
1717                 if (hasStackArgsWeCareAbout)
1718                 {
1719 #if !FEATURE_FIXED_OUT_ARGS
1720                     // On x86 we previously recorded a stack depth of zero when
1721                     // morphing the register arguments of any GT_IND with a GTF_IND_RNGCHK flag
1722                     // Thus we can not reorder the argument after any stack based argument
1723                     // (Note that GT_LCLHEAP sets the GTF_EXCEPT flag so we don't need to
1724                     // check for it explicitly
1725                     //
1726                     if (argx->gtFlags & GTF_EXCEPT)
1727                     {
1728                         curArgTabEntry->needTmp = true;
1729                         continue;
1730                     }
1731 #else
1732                     // For Arm/X64 we can't reorder a register argument that uses a GT_LCLHEAP
1733                     //
1734                     if (argx->gtFlags & GTF_EXCEPT)
1735                     {
1736                         assert(compiler->compLocallocUsed);
1737
1738                         // Returns WALK_ABORT if a GT_LCLHEAP node is encountered in the argx tree
1739                         //
1740                         if (compiler->fgWalkTreePre(&argx, Compiler::fgChkLocAllocCB) == Compiler::WALK_ABORT)
1741                         {
1742                             curArgTabEntry->needTmp = true;
1743                             continue;
1744                         }
1745                     }
1746 #endif
1747                 }
1748                 if (hasStructRegArgWeCareAbout)
1749                 {
1750                     // Returns true if a GT_QMARK node is encountered in the argx tree
1751                     //
1752                     if (compiler->fgWalkTreePre(&argx, Compiler::fgChkQmarkCB) == Compiler::WALK_ABORT)
1753                     {
1754                         curArgTabEntry->needTmp = true;
1755                         continue;
1756                     }
1757                 }
1758             }
1759         }
1760     }
1761
1762     argsComplete = true;
1763 }
1764
1765 void fgArgInfo::SortArgs()
1766 {
1767     assert(argsComplete == true);
1768
1769     /* Shuffle the arguments around before we build the gtCallLateArgs list.
1770        The idea is to move all "simple" arguments like constants and local vars
1771        to the end of the table, and move the complex arguments towards the beginning
1772        of the table. This will help prevent registers from being spilled by
1773        allowing us to evaluate the more complex arguments before the simpler arguments.
1774        The argTable ends up looking like:
1775            +------------------------------------+  <--- argTable[argCount - 1]
1776            |          constants                 |
1777            +------------------------------------+
1778            |    local var / local field         |
1779            +------------------------------------+
1780            | remaining arguments sorted by cost |
1781            +------------------------------------+
1782            | temps (argTable[].needTmp = true)  |
1783            +------------------------------------+
1784            |  args with calls (GTF_CALL)        |
1785            +------------------------------------+  <--- argTable[0]
1786      */
1787
1788 #ifdef DEBUG
1789     if (compiler->verbose)
1790     {
1791         printf("\nSorting the arguments:\n");
1792     }
1793 #endif
1794
1795     /* Set the beginning and end for the new argument table */
1796     unsigned curInx;
1797     int      regCount      = 0;
1798     unsigned begTab        = 0;
1799     unsigned endTab        = argCount - 1;
1800     unsigned argsRemaining = argCount;
1801
1802     // First take care of arguments that are constants.
1803     // [We use a backward iterator pattern]
1804     //
1805     curInx = argCount;
1806     do {
1807         curInx--;
1808
1809         fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1810
1811         if (curArgTabEntry->regNum != REG_STK)
1812             regCount++;
1813
1814         // Skip any already processed args
1815         //
1816         if (!curArgTabEntry->processed)
1817         {
1818             GenTreePtr   argx = curArgTabEntry->node;
1819
1820             // put constants at the end of the table
1821             //
1822             if (argx->gtOper == GT_CNS_INT)
1823             {
1824                 noway_assert(curInx <= endTab);
1825
1826                 curArgTabEntry->processed = true;
1827
1828                 // place curArgTabEntry at the endTab position by performing a swap
1829                 //
1830                 if (curInx != endTab)
1831                 {
1832                     argTable[curInx] = argTable[endTab];
1833                     argTable[endTab] = curArgTabEntry;
1834                 }
1835
1836                 endTab--;
1837                 argsRemaining--;
1838             }
1839         }
1840     }  while (curInx > 0);
1841
1842     if (argsRemaining > 0)
1843     {
1844         // Next take care of arguments that are calls.
1845         // [We use a forward iterator pattern]
1846         //
1847         for (curInx = begTab; curInx <= endTab; curInx++)
1848         {
1849             fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1850
1851             // Skip any already processed args
1852             //
1853             if (!curArgTabEntry->processed)
1854             {
1855                 GenTreePtr   argx = curArgTabEntry->node;
1856
1857                 // put calls at the beginning of the table
1858                 //
1859                 if (argx->gtFlags & GTF_CALL)
1860                 {
1861                     curArgTabEntry->processed = true;
1862
1863                     // place curArgTabEntry at the begTab position by performing a swap
1864                     //
1865                     if (curInx != begTab)
1866                     {
1867                         argTable[curInx] = argTable[begTab];
1868                         argTable[begTab] = curArgTabEntry;
1869                     }
1870
1871                     begTab++;
1872                     argsRemaining--;
1873                 }
1874             }
1875         }
1876     }
1877
1878     if (argsRemaining > 0)
1879     {
1880         // Next take care arguments that are temps.
1881         // These temps come before the arguments that are
1882         // ordinary local vars or local fields
1883         // since this will give them a better chance to become
1884         // enregistered into their actual argument register.
1885         // [We use a forward iterator pattern]
1886         //
1887         for (curInx = begTab; curInx <= endTab; curInx++)
1888         {
1889             fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1890
1891             // Skip any already processed args
1892             //
1893             if (!curArgTabEntry->processed)
1894             {
1895                 if (curArgTabEntry->needTmp)
1896                 {
1897                     curArgTabEntry->processed = true;
1898
1899                     // place curArgTabEntry at the begTab position by performing a swap
1900                     //
1901                     if (curInx != begTab)
1902                     {
1903                         argTable[curInx] = argTable[begTab];
1904                         argTable[begTab] = curArgTabEntry;
1905                     }
1906
1907                     begTab++;
1908                     argsRemaining--;
1909                 }
1910             }
1911         }
1912     }
1913
1914     if (argsRemaining > 0)
1915     {
1916         // Next take care of local var and local field arguments.
1917         // These are moved towards the end of the argument evaluation.
1918         // [We use a backward iterator pattern]
1919         //
1920         curInx = endTab + 1;
1921         do {
1922             curInx--;
1923
1924             fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1925
1926             // Skip any already processed args
1927             //
1928             if (!curArgTabEntry->processed)
1929             {
1930                 GenTreePtr   argx = curArgTabEntry->node;
1931
1932                 if ((argx->gtOper == GT_LCL_VAR) || (argx->gtOper == GT_LCL_FLD))
1933                 {
1934                     noway_assert(curInx <= endTab);
1935
1936                     curArgTabEntry->processed = true;
1937
1938                     // place curArgTabEntry at the endTab position by performing a swap
1939                     //
1940                     if (curInx != endTab)
1941                     {
1942                         argTable[curInx] = argTable[endTab];
1943                         argTable[endTab] = curArgTabEntry;
1944                     }
1945
1946                     endTab--;
1947                     argsRemaining--;
1948                 }
1949             }
1950         } while (curInx > begTab);
1951     }
1952
1953     // Finally, take care of all the remaining arguments.
1954     // Note that we fill in one arg at a time using a while loop.
1955     bool costsPrepared = false; // Only prepare tree costs once, the first time through this loop
1956     while (argsRemaining > 0)
1957     {
1958         /* Find the most expensive arg remaining and evaluate it next */
1959
1960         fgArgTabEntryPtr expensiveArgTabEntry = NULL;
1961         unsigned         expensiveArg         = UINT_MAX;
1962         unsigned         expensiveArgCost     = 0;
1963
1964         // [We use a forward iterator pattern]
1965         //
1966         for (curInx = begTab; curInx <= endTab; curInx++)
1967         {
1968             fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
1969
1970             // Skip any already processed args
1971             //
1972             if (!curArgTabEntry->processed)
1973             {
1974                 GenTreePtr  argx = curArgTabEntry->node;
1975
1976                 // We should have already handled these kinds of args
1977                 assert (argx->gtOper != GT_LCL_VAR);
1978                 assert (argx->gtOper != GT_LCL_FLD);
1979                 assert (argx->gtOper != GT_CNS_INT);
1980
1981                 // This arg should either have no persistent side effects or be the last one in our table
1982                 // assert(((argx->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) == 0) || (curInx == (argCount-1)));
1983
1984                 if (argsRemaining == 1)
1985                 {
1986                     // This is the last arg to place
1987                     expensiveArg         = curInx;
1988                     expensiveArgTabEntry = curArgTabEntry;
1989                     assert(begTab == endTab);
1990                     break;
1991                 }
1992                 else
1993                 {
1994                     if (!costsPrepared)
1995                     {
1996                         /* We call gtPrepareCost to measure the cost of evaluating this tree */
1997                         compiler->gtPrepareCost(argx);
1998                     }
1999
2000                     if (argx->gtCostEx > expensiveArgCost)
2001                     {
2002                         // Remember this arg as the most expensive one that we have yet seen
2003                         expensiveArgCost     = argx->gtCostEx;
2004                         expensiveArg         = curInx;
2005                         expensiveArgTabEntry = curArgTabEntry;
2006                     }
2007                 }
2008             }
2009         }
2010
2011         noway_assert(expensiveArg != UINT_MAX);
2012
2013         // put the most expensive arg towards the beginning of the table
2014
2015         expensiveArgTabEntry->processed = true;
2016
2017         // place expensiveArgTabEntry at the begTab position by performing a swap
2018         //
2019         if (expensiveArg != begTab)
2020         {
2021             argTable[expensiveArg] = argTable[begTab];
2022             argTable[begTab]       = expensiveArgTabEntry;
2023         }
2024
2025         begTab++;
2026         argsRemaining--;
2027
2028         costsPrepared = true; // If we have more expensive arguments, don't re-evaluate the tree cost on the next loop
2029     }
2030
2031     // The table should now be completely filled and thus begTab should now be adjacent to endTab
2032     // and regArgsRemaining should be zero
2033     assert(begTab == (endTab + 1));
2034     assert(argsRemaining == 0);
2035
2036 #if !FEATURE_FIXED_OUT_ARGS
2037     // Finally build the regArgList
2038     //
2039     callTree->gtCall.regArgList = NULL;
2040     callTree->gtCall.regArgListCount = regCount;
2041
2042     unsigned regInx = 0;
2043     for (curInx = 0; curInx < argCount; curInx++)
2044     {
2045         fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
2046
2047         if (curArgTabEntry->regNum != REG_STK)
2048         {
2049             // Encode the argument register in the register mask
2050             //
2051             callTree->gtCall.regArgList[regInx] = curArgTabEntry->regNum;
2052             regInx++;
2053         }
2054     }
2055 #endif // !FEATURE_FIXED_OUT_ARGS
2056
2057     argsSorted = true;
2058 }
2059
2060 //------------------------------------------------------------------------------
2061 // fgMakeTmpArgNode : This function creates a tmp var only if needed.
2062 //                    We need this to be done in order to enforce ordering
2063 //                    of the evaluation of arguments.
2064 //
2065 // Arguments:
2066 //    tmpVarNum  - the var num which we clone into the newly created temp var.
2067 //
2068 // Return Value:
2069 //    the newly created temp var tree. 
2070
2071 GenTreePtr    Compiler::fgMakeTmpArgNode(unsigned tmpVarNum
2072                                          FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool passedInRegisters))
2073 {
2074     LclVarDsc *  varDsc = &lvaTable[tmpVarNum];
2075     assert(varDsc->lvIsTemp);
2076     var_types  type = varDsc->TypeGet();
2077
2078     // Create a copy of the temp to go into the late argument list
2079     GenTreePtr arg = gtNewLclvNode(tmpVarNum, type);
2080     GenTreePtr addrNode = nullptr;
2081
2082     if (varTypeIsStruct(type))
2083     {
2084
2085 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2086
2087 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2088
2089         arg->gtFlags |= GTF_DONT_CSE;
2090
2091         // If it is passed in registers, don't get the address of the var. Make it a
2092         // field instead. It will be loaded in registers with putarg_reg tree in lower.
2093         if (passedInRegisters)
2094         {
2095             arg->ChangeOper(GT_LCL_FLD);
2096             arg->gtType = type;
2097         }
2098         else
2099         {
2100             arg = gtNewOperNode(GT_ADDR, type, arg);
2101             addrNode = arg;
2102         }
2103
2104 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING 
2105
2106         unsigned structSize = lvaLclExactSize(tmpVarNum);
2107
2108         switch (structSize)
2109         {
2110         case 1: type = TYP_BYTE;  break;
2111         case 2: type = TYP_SHORT; break;
2112 #if defined (_TARGET_AMD64_)
2113         case 4: type = TYP_INT;   break;
2114 #elif defined(_TARGET_ARM64_)
2115         case 3:
2116         case 4: type = TYP_INT;   break;
2117         case 5: 
2118         case 6:
2119         case 7: type = TYP_I_IMPL; break;
2120 #endif // defined (_TARGET_ARM64_)
2121         case 8: 
2122             switch (*lvaGetGcLayout(tmpVarNum))
2123             {
2124             case TYPE_GC_NONE:
2125                 type = TYP_I_IMPL;
2126                 break;
2127             case TYPE_GC_REF:
2128                 type = TYP_REF;
2129                 break;
2130             case TYPE_GC_BYREF:
2131                 type = TYP_BYREF;
2132                 break;
2133             default:
2134                 unreached();
2135             }
2136             break;
2137         default:
2138             break;
2139         }
2140
2141         // If we didn't change the type of the struct, it means
2142         // its structure doesn't support to be passed directly through a
2143         // register, so we need to pass a pointer to the destination where
2144         // where we copied the struct to.
2145         if (type == varDsc->TypeGet())
2146         {
2147 #if FEATURE_MULTIREG_ARGS
2148 #ifdef _TARGET_ARM64_
2149             assert(varTypeIsStruct(type));
2150             if (varDsc->lvIsMultiregStruct())
2151             {
2152                 // ToDo-ARM64: Consider using:  arg->ChangeOper(GT_LCL_FLD);
2153                 // as that is how FEATURE_UNIX_AMD64_STRUCT_PASSING works.
2154                 // Create a GT_OBJ for the argument 
2155                 // This will be passed by value in two registers
2156                 arg = gtNewOperNode(GT_ADDR, TYP_BYREF, arg);
2157                 addrNode = arg;
2158
2159                 // Create an Obj of the temp to use it as a call argument.
2160                 arg = gtNewObjNode(lvaGetStruct(tmpVarNum), arg);
2161             }
2162             else
2163 #endif // _TARGET_ARM64_
2164 #endif // FEATURE_MULTIREG_ARGS
2165             {
2166                 arg = gtNewOperNode(GT_ADDR, TYP_I_IMPL, arg);
2167                 addrNode = arg;
2168             }
2169         }
2170         else // type was changed from a struct to a scalar type
2171         {
2172             arg->ChangeOper(GT_LCL_FLD);
2173             arg->gtType = type;
2174         }
2175 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
2176
2177 #else // not (_TARGET_AMD64_ or _TARGET_ARM64_)
2178
2179         // other targets, we pass the struct by value 
2180         assert(varTypeIsStruct(type));
2181
2182         arg = gtNewOperNode(GT_ADDR, TYP_BYREF, arg);
2183         addrNode = arg;
2184
2185         // Get a new Obj node temp to use it as a call argument
2186         arg = gtNewObjNode(lvaGetStruct(tmpVarNum), arg);
2187         arg->gtFlags |= GTF_EXCEPT;
2188
2189 #endif  // not (_TARGET_AMD64_ or _TARGET_ARM64_)
2190
2191     } // (varTypeIsStruct(type))
2192
2193     if (addrNode != nullptr)
2194     {
2195         assert(addrNode->gtOper == GT_ADDR);
2196
2197         // This will prevent this LclVar from being optimized away
2198         lvaSetVarAddrExposed(tmpVarNum); 
2199
2200         // the child of a GT_ADDR is required to have this flag set
2201         addrNode->gtOp.gtOp1->gtFlags |= GTF_DONT_CSE;
2202     }
2203
2204     return arg;
2205 }
2206
2207 void fgArgInfo::EvalArgsToTemps()
2208 {
2209     assert(argsSorted == true);
2210
2211     unsigned regArgInx = 0;
2212     // Now go through the argument table and perform the necessary evaluation into temps
2213     GenTreeArgList* tmpRegArgNext = NULL;
2214     for (unsigned curInx = 0; curInx < argCount; curInx++)
2215     {
2216         fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
2217
2218         GenTreePtr  argx     = curArgTabEntry->node;
2219         GenTreePtr  setupArg = NULL;
2220         GenTreePtr  defArg;
2221
2222 #if !FEATURE_FIXED_OUT_ARGS
2223         // Only ever set for FEATURE_FIXED_OUT_ARGS
2224         assert(curArgTabEntry->needPlace == false);
2225
2226         // On x86 and other archs that use push instructions to pass arguments:
2227         //   Only the register arguments need to be replaced with placeholder nodes.
2228         //   Stacked arguments are evaluated and pushed (or stored into the stack) in order.
2229         //
2230         if (curArgTabEntry->regNum == REG_STK) 
2231             continue;
2232 #endif
2233
2234         if (curArgTabEntry->needTmp)
2235         {
2236             unsigned tmpVarNum;
2237
2238             if (curArgTabEntry->isTmp == true)
2239             {
2240                 // Create a copy of the temp to go into the late argument list
2241                 tmpVarNum = curArgTabEntry->tmpNum;
2242                 defArg = compiler->fgMakeTmpArgNode(
2243                     tmpVarNum
2244                     FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(argTable[curInx]->structDesc.passedInRegisters));
2245
2246                 // mark the original node as a late argument
2247                 argx->gtFlags |= GTF_LATE_ARG;
2248             }
2249             else
2250             {
2251                 // Create a temp assignment for the argument
2252                 //  Put the temp in the gtCallLateArgs list
2253 #ifdef DEBUG
2254                 if (compiler->verbose)
2255                 {
2256                     printf("Argument with 'side effect'...\n");
2257                     compiler->gtDispTree(argx);
2258                 }
2259 #endif
2260
2261 #if defined(_TARGET_AMD64_) && !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2262                 noway_assert(argx->gtType != TYP_STRUCT);
2263 #endif
2264
2265                 tmpVarNum = compiler->lvaGrabTemp(true DEBUGARG("argument with side effect"));
2266                 if (argx->gtOper == GT_MKREFANY)
2267                 {
2268                     // For GT_MKREFANY, typically the actual struct copying does
2269                     // not have any side-effects and can be delayed. So instead
2270                     // of using a temp for the whole struct, we can just use a temp
2271                     // for operand that that has a side-effect
2272                     GenTreePtr operand;
2273                     if ((argx->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT) == 0)
2274                     {
2275                         operand = argx->gtOp.gtOp1;
2276
2277                         // In the early argument evaluation, place an assignment to the temp
2278                         // from the source operand of the mkrefany
2279                         setupArg = compiler->gtNewTempAssign(tmpVarNum, operand);
2280
2281                         // Replace the operand for the mkrefany with the new temp.
2282                         argx->gtOp.gtOp1 = compiler->gtNewLclvNode(tmpVarNum, operand->TypeGet());
2283                     }
2284                     else if ((argx->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT) == 0)
2285                     {
2286                         operand = argx->gtOp.gtOp2;
2287
2288                         // In the early argument evaluation, place an assignment to the temp
2289                         // from the source operand of the mkrefany
2290                         setupArg = compiler->gtNewTempAssign(tmpVarNum, operand);
2291
2292                         // Replace the operand for the mkrefany with the new temp.
2293                         argx->gtOp.gtOp2 = compiler->gtNewLclvNode(tmpVarNum, operand->TypeGet());
2294                     }
2295                 }
2296
2297                 if (setupArg != NULL)
2298                 {
2299                     // Now keep the mkrefany for the late argument list
2300                     defArg = argx;
2301
2302                     // Clear the side-effect flags because now both op1 and op2 have no side-effects
2303                     defArg->gtFlags &= ~GTF_ALL_EFFECT;
2304                 }
2305                 else
2306                 {
2307                     setupArg = compiler->gtNewTempAssign(tmpVarNum, argx);
2308
2309 #ifndef LEGACY_BACKEND
2310                     if (compiler->fgOrder == Compiler::FGOrderLinear)
2311                     {
2312                         // We'll reference this temporary variable just once
2313                         // when we perform the function call after
2314                         // setting up this argument.
2315                         LclVarDsc* varDsc = compiler->lvaTable + tmpVarNum;
2316                         varDsc->lvRefCnt = 1;
2317                     }
2318 #endif // !LEGACY_BACKEND
2319
2320                     if (setupArg->OperIsCopyBlkOp())
2321                         setupArg = compiler->fgMorphCopyBlock(setupArg);
2322
2323                     /* Create a copy of the temp to go to the late argument list */
2324                     defArg = compiler->gtNewLclvNode(tmpVarNum, genActualType(argx->gtType));
2325
2326                     curArgTabEntry->isTmp   = true;
2327                     curArgTabEntry->tmpNum  = tmpVarNum;
2328
2329 #ifdef _TARGET_ARM_
2330                     // Previously we might have thought the local was promoted, and thus the 'COPYBLK'
2331                     // might have left holes in the used registers (see
2332                     // fgAddSkippedRegsInPromotedStructArg).
2333                     // Too bad we're not that smart for these intermediate temps...
2334                     if (isValidIntArgReg(curArgTabEntry->regNum) && (curArgTabEntry->numRegs > 1))
2335                     {
2336                         regNumber argReg = curArgTabEntry->regNum;
2337                         regMaskTP allUsedRegs = genRegMask(curArgTabEntry->regNum);
2338                         for (unsigned i = 1; i < curArgTabEntry->numRegs; i++)
2339                         {
2340                             argReg = genRegArgNext(argReg);
2341                             allUsedRegs |= genRegMask(argReg);
2342                         }
2343                         callTree->gtCall.gtCallRegUsedMask |= allUsedRegs;
2344                     }
2345 #endif // _TARGET_ARM_
2346                 }
2347
2348                 /* mark the assignment as a late argument */
2349                 setupArg->gtFlags |= GTF_LATE_ARG;
2350
2351 #ifdef DEBUG
2352                 if (compiler->verbose)
2353                 {
2354                     printf("\n  Evaluate to a temp:\n");
2355                     compiler->gtDispTree(setupArg);
2356                 }
2357 #endif
2358             }
2359         }
2360         else // curArgTabEntry->needTmp == false
2361         {
2362             //   On x86 -
2363             //      Only register args are replaced with placeholder nodes
2364             //      and the stack based arguments are evaluated and pushed in order.
2365             //
2366             //   On Arm/x64 - When needTmp is false and needPlace is false,
2367             //      the non-register arguments are evaluated and stored in order.
2368             //      When needPlace is true we have a nested call that comes after
2369             //      this argument so we have to replace it in the gtCallArgs list
2370             //      (the initial argument evaluation list) with a placeholder.
2371             //
2372             if ((curArgTabEntry->regNum == REG_STK) && (curArgTabEntry->needPlace == false))
2373                 continue;
2374
2375             /* No temp needed - move the whole node to the gtCallLateArgs list */
2376
2377             /* The argument is deferred and put in the late argument list */
2378
2379             defArg = argx;
2380
2381             // Create a placeholder node to put in its place in gtCallLateArgs.
2382
2383             // For a struct type we also need to record the class handle of the arg.
2384             CORINFO_CLASS_HANDLE clsHnd = NO_CLASS_HANDLE;
2385
2386 #if defined(_TARGET_AMD64_) && !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2387
2388             // All structs are either passed (and retyped) as integral types, OR they
2389             // are passed by reference.
2390             noway_assert(argx->gtType != TYP_STRUCT);
2391
2392 #else // !defined(_TARGET_AMD64_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2393
2394             if (varTypeIsStruct(defArg))
2395             {
2396                 // Need a temp to walk any GT_COMMA nodes when searching for the clsHnd
2397                 GenTreePtr  defArgTmp = defArg;
2398
2399                 // The GT_OBJ may be be a child of a GT_COMMA.
2400                 while (defArgTmp->gtOper == GT_COMMA)
2401                 {
2402                     defArgTmp = defArgTmp->gtOp.gtOp2;
2403                 }
2404                 assert(varTypeIsStruct(defArgTmp));
2405
2406                 // We handle two opcodes: GT_MKREFANY and GT_OBJ.
2407                 if (defArgTmp->gtOper == GT_MKREFANY)
2408                 {
2409                     clsHnd = compiler->impGetRefAnyClass();
2410                 }
2411                 else if (defArgTmp->gtOper == GT_OBJ)
2412                 {
2413                     clsHnd = defArgTmp->AsObj()->gtClass;
2414                 }
2415                 else
2416                 {
2417                     BADCODE("Unhandled struct argument tree in fgMorphArgs");
2418                 }
2419         }
2420
2421 #endif // !(defined(_TARGET_AMD64_) && !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING))
2422
2423             setupArg = compiler->gtNewArgPlaceHolderNode(defArg->gtType, clsHnd);
2424
2425             /* mark the placeholder node as a late argument */
2426             setupArg->gtFlags |= GTF_LATE_ARG;
2427
2428 #ifdef DEBUG
2429             if (compiler->verbose)
2430             {
2431                 if (curArgTabEntry->regNum == REG_STK)
2432                 {
2433                     printf("Deferred stack argument :\n");
2434                 }
2435                 else
2436                 {
2437                     printf("Deferred argument ('%s'):\n", getRegName(curArgTabEntry->regNum));
2438                 }
2439
2440                 compiler->gtDispTree(argx);
2441                 printf("Replaced with placeholder node:\n");
2442                 compiler->gtDispTree(setupArg);
2443             }
2444 #endif
2445         }
2446
2447         if (setupArg != NULL)
2448         {
2449             if (curArgTabEntry->parent)
2450             {
2451                 GenTreePtr  parent = curArgTabEntry->parent;
2452                 /* a normal argument from the list */
2453                 noway_assert(parent->IsList());
2454                 noway_assert(parent->gtOp.gtOp1 == argx);
2455
2456                 parent->gtOp.gtOp1 = setupArg;
2457             }
2458             else
2459             {
2460                 /* must be the gtCallObjp */
2461                 noway_assert(callTree->gtCall.gtCallObjp == argx);
2462
2463                 callTree->gtCall.gtCallObjp = setupArg;
2464             }
2465         }
2466
2467         /* deferred arg goes into the late argument list */
2468
2469         if (tmpRegArgNext == NULL)
2470         {
2471             tmpRegArgNext = compiler->gtNewArgList(defArg);
2472             callTree->gtCall.gtCallLateArgs = tmpRegArgNext;
2473         }
2474         else
2475         {
2476             noway_assert(tmpRegArgNext->IsList());
2477             noway_assert(tmpRegArgNext->Current());
2478             tmpRegArgNext->gtOp.gtOp2 = compiler->gtNewArgList(defArg);
2479             tmpRegArgNext = tmpRegArgNext->Rest();
2480         }
2481
2482         curArgTabEntry->node       = defArg;
2483         curArgTabEntry->lateArgInx = regArgInx++;
2484     }
2485
2486 #ifdef DEBUG
2487     if (compiler->verbose)
2488     {
2489         printf("\nShuffled argument table:    ");
2490         for (unsigned curInx = 0; curInx < argCount; curInx++)
2491         {
2492             fgArgTabEntryPtr curArgTabEntry = argTable[curInx];
2493
2494             if (curArgTabEntry->regNum != REG_STK)
2495             {
2496                 printf("%s ", getRegName( curArgTabEntry->regNum ));
2497             }
2498         }
2499         printf("\n");
2500     }
2501 #endif
2502 }
2503
2504 void fgArgInfo::RecordStkLevel(unsigned stkLvl)
2505 {
2506     assert(!IsUninitialized(stkLvl));
2507     this->stkLevel = stkLvl;
2508 }
2509
2510 unsigned fgArgInfo::RetrieveStkLevel()
2511 {
2512     assert(!IsUninitialized(stkLevel));
2513     return stkLevel;
2514 }
2515
2516 // Return a conservative estimate of the stack size in bytes.
2517 // It will be used only on the intercepted-for-host code path to copy the arguments.
2518 int Compiler::fgEstimateCallStackSize(GenTreeCall* call)
2519 {
2520
2521     int numArgs = 0;
2522     for (GenTreeArgList* args = call->gtCallArgs; args; args = args->Rest())
2523     {
2524         numArgs++;
2525     }
2526
2527     int numStkArgs;
2528     if (numArgs > MAX_REG_ARG)
2529         numStkArgs = numArgs - MAX_REG_ARG;
2530     else
2531         numStkArgs = 0;
2532
2533     return numStkArgs * REGSIZE_BYTES;
2534 }
2535
2536 //------------------------------------------------------------------------------
2537 // fgMakeMultiUse : If the node is a local, clone it and increase the ref count
2538 //                  otherwise insert a comma form temp
2539 //
2540 // Arguments:
2541 //    ppTree  - a pointer to the child node we will be replacing with the comma expression that
2542 //              evaluates ppTree to a temp and returns the result
2543 //
2544 // Return Value:
2545 //    A fresh GT_LCL_VAR node referencing the temp which has not been used 
2546 //
2547 // Assumption:
2548 //    The result tree MUST be added to the tree structure since the ref counts are
2549 //    already incremented.
2550
2551 GenTree* Compiler::fgMakeMultiUse(GenTree** pOp)
2552 {
2553     GenTree* tree = *pOp;
2554     if (tree->IsLocal())
2555     {
2556         auto result = gtClone(tree);
2557         if (lvaLocalVarRefCounted)
2558         {
2559             lvaTable[tree->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
2560         }
2561         return result;
2562     }
2563     else
2564     {
2565         GenTree* result =  fgInsertCommaFormTemp(pOp);
2566
2567         // At this point, *pOp is GT_COMMA(GT_ASG(V01, *pOp), V01) and result = V01
2568         // Therefore, the ref count has to be incremented 3 times for *pOp and result, if result will
2569         // be added by the caller.
2570         if (lvaLocalVarRefCounted)
2571         {
2572             lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
2573             lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
2574             lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
2575         }
2576
2577         return result;
2578     }
2579 }
2580
2581
2582 //------------------------------------------------------------------------------
2583 // fgInsertCommaFormTemp: Create a new temporary variable to hold the result of *ppTree,
2584 //                        and replace *ppTree with comma(asg(newLcl, *ppTree), newLcl)
2585 //
2586 // Arguments:
2587 //    ppTree     - a pointer to the child node we will be replacing with the comma expression that
2588 //                 evaluates ppTree to a temp and returns the result
2589 //
2590 //    structType - value type handle if the temp created is of TYP_STRUCT.
2591 //
2592 // Return Value:
2593 //    A fresh GT_LCL_VAR node referencing the temp which has not been used 
2594 //
2595
2596 GenTree*   Compiler::fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType /*= nullptr*/)
2597 {
2598     GenTree* subTree = *ppTree;
2599
2600     unsigned lclNum = lvaGrabTemp(true DEBUGARG("fgInsertCommaFormTemp is creating a new local variable"));
2601    
2602     if (varTypeIsStruct(subTree))
2603     {
2604         assert(structType != nullptr);
2605         lvaSetStruct(lclNum, structType, false);
2606     }
2607
2608     // If subTree->TypeGet() == TYP_STRUCT, gtNewTempAssign() will create a GT_COPYBLK tree.
2609     // The type of GT_COPYBLK is TYP_VOID.  Therefore, we should use subTree->TypeGet() for
2610     // setting type of lcl vars created.
2611     GenTree* asg = gtNewTempAssign(lclNum, subTree);
2612
2613     GenTree* load = new (this, GT_LCL_VAR) GenTreeLclVar(subTree->TypeGet(), lclNum, BAD_IL_OFFSET);
2614     
2615     GenTree* comma = gtNewOperNode(GT_COMMA, subTree->TypeGet(), asg, load);
2616
2617     *ppTree = comma;
2618
2619     return new (this, GT_LCL_VAR) GenTreeLclVar(subTree->TypeGet(), lclNum, BAD_IL_OFFSET);
2620 }
2621
2622
2623 //------------------------------------------------------------------------
2624 // fgMorphArgs: Walk and transform (morph) the arguments of a call
2625 //
2626 // Arguments:
2627 //    callNode - the call for which we are doing the argument morphing
2628 //
2629 // Return Value:
2630 //    Like most morph methods, this method returns the morphed node,
2631 //    though in this case there are currently no scenarios where the
2632 //    node itself is re-created.
2633 //
2634 // Notes:
2635 //    This method is even less idempotent than most morph methods.
2636 //    That is, it makes changes that should not be redone. It uses the existence
2637 //    of gtCallLateArgs (the late arguments list) to determine if it has
2638 //    already done that work.
2639 //
2640 //    The first time it is called (i.e. during global morphing), this method
2641 //    computes the "late arguments". This is when it determines which arguments
2642 //    need to be evaluated to temps prior to the main argument setup, and which
2643 //    can be directly evaluated into the argument location. It also creates a
2644 //    second argument list (gtCallLateArgs) that does the final placement of the
2645 //    arguments, e.g. into registers or onto the stack.
2646 //
2647 //    The "non-late arguments", aka the gtCallArgs, are doing the in-order
2648 //    evaluation of the arguments that might have side-effects, such as embedded
2649 //    assignments, calls or possible throws. In these cases, it and earlier
2650 //    arguments must be evaluated to temps.
2651 //
2652 //    On targets with a fixed outgoing argument area (FEATURE_FIXED_OUT_ARGS),
2653 //    if we have any nested calls, we need to defer the copying of the argument
2654 //    into the fixed argument area until after the call. If the argument did not
2655 //    otherwise need to be computed into a temp, it is moved to gtCallLateArgs and
2656 //    replaced in the "early" arg list (gtCallArgs) with a placeholder node.
2657
2658 #ifdef _PREFAST_
2659 #pragma warning(push)
2660 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
2661 #endif
2662 GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
2663 {
2664     GenTreeCall* call = callNode->AsCall();
2665
2666     GenTreePtr      args;
2667     GenTreePtr      argx;
2668
2669     unsigned        flagsSummary  = 0;
2670     unsigned        genPtrArgCntSav = fgPtrArgCntCur;
2671
2672     unsigned        argIndex      = 0;
2673
2674     unsigned        intArgRegNum  = 0;
2675     unsigned        fltArgRegNum  = 0;
2676
2677     regMaskTP       argSkippedRegMask    = RBM_NONE;
2678
2679 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
2680     regMaskTP       fltArgSkippedRegMask = RBM_NONE;
2681 #endif
2682
2683 #if defined(_TARGET_X86_)
2684     unsigned        maxRegArgs    = MAX_REG_ARG;  // X86: non-const, must be calculated
2685 #else
2686     const unsigned  maxRegArgs    = MAX_REG_ARG;  // other arch: fixed constant number 
2687 #endif 
2688
2689     unsigned        argSlots          = 0;
2690     unsigned        nonRegPassedStructSlots = 0;
2691     bool            lateArgsComputed  = (call->gtCallLateArgs != nullptr);
2692     bool            callHasRetBuffArg = call->HasRetBufArg();
2693
2694 #ifndef _TARGET_X86_    // i.e. _TARGET_AMD64_ or _TARGET_ARM_
2695     bool            callIsVararg      = call->IsVarargs();
2696 #endif
2697
2698     bool hasNonStandardArg = false;
2699 #ifndef LEGACY_BACKEND
2700     // data structure for keeping track of non-standard args we insert
2701     // (args that have a special meaning and are not passed following the normal
2702     // calling convention or even in the normal arg regs.
2703     struct NonStandardArg
2704     {
2705         regNumber reg;
2706         GenTree*  node;
2707     };
2708
2709     ArrayStack<NonStandardArg> nonStandardArgs(this, 2);
2710 #endif // !LEGACY_BACKEND
2711
2712     // Process the late arguments (which were determined by a previous caller).
2713     // Do this before resetting fgPtrArgCntCur as fgMorphTree(call->gtCallLateArgs)
2714     // may need to refer to it.
2715     if  (lateArgsComputed)
2716     {
2717         // We need to reMorph the gtCallLateArgs early since that is what triggers
2718         // the expression folding and we need to have the final folded gtCallLateArgs
2719         // available when we call RemorphRegArg so that we correctly update the fgArgInfo
2720         // with the folded tree that represents the final optimized argument nodes.
2721         //
2722         // However if a range-check needs to be generated for any of these late
2723         // arguments we also need to "know" what the stack depth will be when we generate
2724         // code to branch to the throw range check failure block as that is part of the
2725         // GC information contract for that block.
2726         //
2727         // Since the late arguments are evaluated last we have pushed all of the
2728         // other arguments on the stack before we evaluate these late arguments,
2729         // so we record the stack depth on the first morph call when lateArgsComputed
2730         // was false (via RecordStkLevel) and then retrieve that value here (via RetrieveStkLevel)
2731         //
2732         unsigned callStkLevel = call->fgArgInfo->RetrieveStkLevel();
2733         fgPtrArgCntCur += callStkLevel;
2734         call->gtCallLateArgs = fgMorphTree(call->gtCallLateArgs)->AsArgList();
2735         flagsSummary |= call->gtCallLateArgs->gtFlags;
2736         fgPtrArgCntCur -= callStkLevel;
2737         assert(call->fgArgInfo != nullptr);
2738         call->fgArgInfo->RemorphReset();
2739     }
2740     else
2741     {
2742         // First we need to count the args
2743         unsigned numArgs = 0;
2744         if (call->gtCallObjp)
2745             numArgs++;
2746         for (args = call->gtCallArgs; (args != nullptr); args = args->gtOp.gtOp2)
2747         {
2748             numArgs++;
2749         }
2750
2751
2752         // insert nonstandard args (outside the calling convention)
2753
2754 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_X86_)
2755         // TODO-X86-CQ: Currently RyuJIT/x86 passes args on the stack, so this is not needed.
2756         // If/when we change that, the following code needs to be changed to correctly support the (TBD) managed calling
2757         // convention for x86/SSE.
2758         if (!lateArgsComputed)
2759         {
2760             if (call->IsUnmanaged() && !opts.ShouldUsePInvokeHelpers())
2761             {
2762                 assert(!call->gtCallCookie);
2763                 // Add a conservative estimate of the stack size in a special parameter (r11) at the call site.
2764                 // It will be used only on the intercepted-for-host code path to copy the arguments.             
2765
2766                 GenTree* cns = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, fgEstimateCallStackSize(call));
2767                 call->gtCallArgs = gtNewListNode(cns, call->gtCallArgs);
2768                 NonStandardArg nsa = {REG_PINVOKE_COOKIE_PARAM, cns};
2769                 numArgs++;
2770
2771                 nonStandardArgs.Push(nsa);
2772             }
2773             else if (call->IsVirtualStub() &&
2774                      (call->gtCallType == CT_INDIRECT) &&
2775                      !call->IsTailCallViaHelper())
2776             {
2777                 // indirect VSD stubs need the base of the indirection cell to be 
2778                 // passed in addition.  At this point that is the value in gtCallAddr.
2779                 // The actual call target will be derived from gtCallAddr in call 
2780                 // lowering.
2781
2782                 // If it is a VSD call getting dispatched via tail call helper,
2783                 // fgMorphTailCall() would materialize stub addr as an additional
2784                 // parameter added to the original arg list and hence no need to 
2785                 // add as a non-standard arg.
2786                 
2787                 GenTree* arg = call->gtCallAddr;
2788                 if (arg->OperIsLocal())
2789                 {
2790                     arg = gtClone(arg, true);
2791                 }
2792                 else
2793                 {
2794                     call->gtCallAddr = fgInsertCommaFormTemp(&arg);
2795                     call->gtFlags |= GTF_ASG;
2796                 }
2797                 noway_assert(arg != nullptr);
2798             
2799                 // And push the stub address onto the list of arguments
2800                 call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
2801                 numArgs++;
2802
2803                 NonStandardArg nsa = {REG_VIRTUAL_STUB_PARAM, arg};
2804             
2805                 nonStandardArgs.Push(nsa);
2806             }
2807             else if (call->gtCallType == CT_INDIRECT && call->gtCallCookie)
2808             {
2809                 assert(!call->IsUnmanaged());
2810
2811                 // put cookie into R11
2812                 GenTree* arg = call->gtCallCookie;
2813                 noway_assert(arg != nullptr);
2814                 call->gtCallCookie = nullptr;
2815
2816                 call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
2817                 numArgs++;
2818
2819                 NonStandardArg nsa = {REG_PINVOKE_COOKIE_PARAM, arg};
2820             
2821                 nonStandardArgs.Push(nsa);
2822
2823                 // put destination into R10
2824                 arg = gtClone(call->gtCallAddr, true);
2825                 call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
2826                 numArgs++;
2827
2828                 NonStandardArg nsa2 = {REG_PINVOKE_TARGET_PARAM, arg};
2829                 nonStandardArgs.Push(nsa2);
2830
2831                 // finally change this call to a helper call
2832                 call->gtCallType = CT_HELPER;
2833                 call->gtCallMethHnd  = eeFindHelper(CORINFO_HELP_PINVOKE_CALLI);
2834             }
2835         }
2836 #endif // !defined(LEGACY_BACKEND) && !defined(_TARGET_X86_)
2837
2838         // Allocate the fgArgInfo for the call node;
2839         //
2840         call->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(this, call, numArgs);
2841     }
2842
2843
2844     fgFixupStructReturn(call);
2845
2846     /* First we morph the argument subtrees ('this' pointer, arguments, etc.).
2847      * During the first call to fgMorphArgs we also record the
2848      * information about late arguments we have in 'fgArgInfo'.
2849      * This information is used later to contruct the gtCallLateArgs */
2850
2851     /* Process the 'this' argument value, if present */
2852
2853     argx = call->gtCallObjp;
2854
2855     if  (argx)
2856     {
2857         argx = fgMorphTree(argx);
2858         call->gtCallObjp = argx;
2859         flagsSummary |= argx->gtFlags;
2860
2861         assert(call->gtCallType == CT_USER_FUNC ||
2862                call->gtCallType == CT_INDIRECT);
2863
2864         assert(argIndex == 0);
2865
2866         /* We must fill in or update the argInfo table */
2867
2868         if  (!lateArgsComputed)
2869         {
2870             assert(varTypeIsGC(call->gtCallObjp->gtType) ||
2871                    (call->gtCallObjp->gtType == TYP_I_IMPL));
2872
2873             /* this is a register argument - put it in the table */
2874             call->fgArgInfo->AddRegArg(argIndex,
2875                                        argx, 
2876                                        NULL, 
2877                                        genMapIntRegArgNumToRegNum(intArgRegNum),
2878                                        1, 
2879                                        1
2880 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2881                                        , false,
2882                                        REG_STK,
2883                                        nullptr
2884 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
2885                 );
2886         }
2887         else
2888         {
2889             /* this is a register argument - possibly update it in the table */
2890             call->fgArgInfo->RemorphRegArg(argIndex, argx, NULL, genMapIntRegArgNumToRegNum(intArgRegNum), 1, 1);
2891         }
2892         // this can't be a struct.
2893         assert(argx->gtType != TYP_STRUCT);
2894
2895         // FIXME: Issue #4025 Why do we need floating type for 'this' argument
2896         /* Increment the argument register count and argument index */
2897         if (!varTypeIsFloating(argx->gtType) || opts.compUseSoftFP)
2898         {
2899             intArgRegNum++;
2900 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
2901             fltArgSkippedRegMask |= genMapArgNumToRegMask(fltArgRegNum, TYP_FLOAT);
2902             fltArgRegNum++;
2903 #endif
2904         }
2905         else
2906         {
2907             fltArgRegNum++;
2908 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
2909             argSkippedRegMask |= genMapArgNumToRegMask(intArgRegNum, TYP_I_IMPL);
2910             intArgRegNum++;
2911 #endif
2912         }
2913         argIndex++;
2914         argSlots++;
2915     }
2916
2917 #ifdef _TARGET_X86_
2918     // Compute the maximum number of arguments that can be passed in registers.
2919     // For X86 we handle the varargs and unmanaged calling conventions
2920
2921     if  (call->gtFlags & GTF_CALL_POP_ARGS)
2922     {
2923         noway_assert(intArgRegNum < MAX_REG_ARG);
2924         // No more register arguments for varargs (CALL_POP_ARGS)
2925         maxRegArgs = intArgRegNum;
2926
2927         // Add in the ret buff arg
2928         if (callHasRetBuffArg)
2929             maxRegArgs++;
2930     }
2931
2932     if (call->IsUnmanaged())
2933     {
2934         noway_assert(intArgRegNum == 0);
2935
2936         if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
2937         {
2938             noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
2939                          call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF ||
2940                          call->gtCallArgs->gtOp.gtOp1->gtOper == GT_NOP); // the arg was already morphed to a register (fgMorph called twice)
2941             maxRegArgs = 1;
2942         }
2943         else
2944         {
2945             maxRegArgs = 0;
2946         }
2947
2948         // Add in the ret buff arg
2949         if (callHasRetBuffArg)
2950             maxRegArgs++;
2951     }
2952 #endif // _TARGET_X86_
2953
2954     /* Morph the user arguments */
2955
2956 #if defined(_TARGET_ARM_)
2957
2958     // The ARM ABI has a concept of back-filling of floating-point argument registers, according
2959     // to the "Procedure Call Standard for the ARM Architecture" document, especially
2960     // section 6.1.2.3 "Parameter passing". Back-filling is where floating-point argument N+1 can
2961     // appear in a lower-numbered register than floating point argument N. That is, argument
2962     // register allocation is not strictly increasing. To support this, we need to keep track of unused
2963     // floating-point argument registers that we can back-fill. We only support 4-byte float and
2964     // 8-byte double types, and one to four element HFAs composed of these types. With this, we will
2965     // only back-fill single registers, since there is no way with these types to create
2966     // an alignment hole greater than one register. However, there can be up to 3 back-fill slots
2967     // available (with 16 FP argument registers). Consider this code:
2968     //
2969     // struct HFA { float x, y, z; }; // a three element HFA
2970     // void bar(float a1,   // passed in f0
2971     //          double a2,  // passed in f2/f3; skip f1 for alignment
2972     //          HFA a3,     // passed in f4/f5/f6
2973     //          double a4,  // passed in f8/f9; skip f7 for alignment. NOTE: it doesn't fit in the f1 back-fill slot
2974     //          HFA a5,     // passed in f10/f11/f12
2975     //          double a6,  // passed in f14/f15; skip f13 for alignment. NOTE: it doesn't fit in the f1 or f7 back-fill slots
2976     //          float a7,   // passed in f1 (back-filled)
2977     //          float a8,   // passed in f7 (back-filled)
2978     //          float a9,   // passed in f13 (back-filled)
2979     //          float a10)  // passed on the stack in [OutArg+0]
2980     //
2981     // Note that if we ever support FP types with larger alignment requirements, then there could
2982     // be more than single register back-fills.
2983     //
2984     // Once we assign a floating-pointer register to the stack, they all must be on the stack.
2985     // See "Procedure Call Standard for the ARM Architecture", section 6.1.2.3, "The back-filling
2986     // continues only so long as no VFP CPRC has been allocated to a slot on the stack."
2987     // We set anyFloatStackArgs to true when a floating-point argument has been assigned to the stack
2988     // and prevent any additional floating-point arguments from going in registers.
2989
2990     bool anyFloatStackArgs = false;
2991
2992 #endif // _TARGET_ARM_
2993
2994 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2995     bool nonRegPassableStruct = false;
2996     SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
2997 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
2998
2999     bool hasStructArgument     = false;   // @TODO-ARM64-UNIX: Remove this bool during a future refactoring 
3000     bool hasMultiregStructArgs = false;
3001     for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2)
3002     {
3003         GenTreePtr * parentArgx = &args->gtOp.gtOp1;
3004
3005 #if FEATURE_MULTIREG_ARGS
3006         if (!hasStructArgument)
3007         {
3008             hasStructArgument = varTypeIsStruct(args->gtOp.gtOp1);
3009         }
3010 #endif // FEATURE_MULTIREG_ARGS
3011
3012         argx = fgMorphTree(*parentArgx);
3013         *parentArgx = argx;
3014         flagsSummary |= argx->gtFlags;
3015
3016         assert(args->IsList());
3017         assert(argx == args->Current());
3018
3019         /* Change the node to TYP_I_IMPL so we don't report GC info
3020          * NOTE: We deferred this from the importer because of the inliner */
3021
3022         if (argx->IsVarAddr())
3023             argx->gtType = TYP_I_IMPL;
3024
3025         bool passUsingFloatRegs;
3026         unsigned  argAlign = 1;
3027         // Setup any HFA information about 'argx'
3028         var_types hfaType  = GetHfaType(argx);
3029         bool      isHfaArg = varTypeIsFloating(hfaType);
3030         unsigned  hfaSlots = 0;
3031
3032         if (isHfaArg)
3033         {
3034             hfaSlots = GetHfaCount(argx);
3035
3036             // If we have a HFA struct it's possible we transition from a method that originally 
3037             // only had integer types to now start having FP types.  We have to communicate this
3038             // through this flag since LSRA later on will use this flag to determine whether 
3039             // or not to track the FP register set.
3040             //
3041             compFloatingPointUsed = true;
3042         }
3043
3044         unsigned             size         = 0;
3045         CORINFO_CLASS_HANDLE copyBlkClass = NULL;
3046         bool                 isRegArg     = false;
3047
3048         fgArgTabEntryPtr argEntry = NULL;
3049
3050         if (lateArgsComputed)
3051         {
3052             argEntry = gtArgEntryByArgNum(call, argIndex);
3053         }
3054
3055 #ifdef _TARGET_ARM_
3056
3057         bool passUsingIntRegs;
3058         if (lateArgsComputed)
3059         {
3060             passUsingFloatRegs = isValidFloatArgReg(argEntry->regNum);
3061             passUsingIntRegs   = isValidIntArgReg(argEntry->regNum);
3062         }
3063         else
3064         {
3065             passUsingFloatRegs = !callIsVararg && (isHfaArg || varTypeIsFloating(argx)) && !opts.compUseSoftFP;
3066             passUsingIntRegs   =  passUsingFloatRegs ? false : (intArgRegNum < MAX_REG_ARG);
3067         }
3068
3069         GenTreePtr curArg = argx;
3070         // If late args have already been computed, use the node in the argument table.
3071         if (argEntry != NULL && argEntry->isTmp)
3072         {
3073             curArg = argEntry->node;
3074         }
3075
3076         // We don't use the "size" return value from InferOpSizeAlign().
3077         codeGen->InferOpSizeAlign(curArg, &argAlign);
3078
3079         argAlign = roundUp(argAlign, TARGET_POINTER_SIZE);
3080         argAlign /= TARGET_POINTER_SIZE;
3081
3082         if (argAlign == 2)
3083         {
3084             if (passUsingFloatRegs)
3085             {
3086                 if (fltArgRegNum % 2 == 1)
3087                 {
3088                     fltArgSkippedRegMask |= genMapArgNumToRegMask(fltArgRegNum, TYP_FLOAT);
3089                     fltArgRegNum ++;
3090                 }
3091             }
3092             else if (passUsingIntRegs)
3093             {
3094                 if (intArgRegNum % 2 == 1)
3095                 {
3096                     argSkippedRegMask |= genMapArgNumToRegMask(intArgRegNum, TYP_I_IMPL);
3097                     intArgRegNum ++;
3098                 }
3099             }
3100
3101             if (argSlots % 2 == 1)
3102             {
3103                 argSlots ++;
3104             }
3105         }
3106
3107 #elif defined(_TARGET_ARM64_)
3108
3109         if (lateArgsComputed)
3110         {
3111             passUsingFloatRegs = isValidFloatArgReg(argEntry->regNum);
3112         }
3113         else
3114         {
3115             passUsingFloatRegs = !callIsVararg && (isHfaArg || varTypeIsFloating(argx));
3116         }
3117
3118 #elif defined(_TARGET_AMD64_)
3119 #if defined(UNIX_AMD64_ABI)        
3120         if (lateArgsComputed)
3121         {
3122             passUsingFloatRegs = isValidFloatArgReg(argEntry->regNum);
3123         }
3124         else
3125         {
3126             passUsingFloatRegs = varTypeIsFloating(argx);
3127         }
3128         bool passUsingIntRegs;
3129         passUsingIntRegs = passUsingFloatRegs ? false : (intArgRegNum < MAX_REG_ARG);
3130 #else // !UNIX_AMD64_ABI
3131         passUsingFloatRegs = varTypeIsFloating(argx);
3132 #endif // !UNIX_AMD64_ABI
3133 #elif defined(_TARGET_X86_)
3134
3135         passUsingFloatRegs = false;
3136
3137 #else
3138     #error Unsupported or unset target architecture
3139 #endif // _TARGET_*
3140
3141         bool         isBackFilled     = false;
3142         unsigned     nextFltArgRegNum = fltArgRegNum;  // This is the next floating-point argument register number to use
3143         var_types    structBaseType   = TYP_STRUCT;
3144         unsigned     structSize = 0;
3145
3146 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3147         unsigned int structFloatRegs = 0;
3148         unsigned int structIntRegs = 0;
3149 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3150         bool isStructArg = varTypeIsStruct(argx);
3151
3152         if (lateArgsComputed)
3153         {
3154 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3155             // Get the struct description for the already completed struct argument.
3156             fgArgTabEntryPtr fgEntryPtr = gtArgEntryByNode(call, argx);
3157             assert(fgEntryPtr != nullptr);
3158
3159             // As described in few other places, this can happen when the argx was morphed 
3160             // into an arg setup node - COPYBLK. The COPYBLK has always a type of void.
3161             // In such case the fgArgTabEntry keeps track of whether the original node (before morphing)
3162             // was a struct and the struct classification. 
3163             isStructArg = fgEntryPtr->isStruct;
3164
3165             if (isStructArg)
3166             {
3167                 structDesc.CopyFrom(fgEntryPtr->structDesc);
3168             }
3169 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3170
3171             assert(argEntry != NULL);
3172             if (argEntry->IsBackFilled())
3173             {
3174                 isRegArg = true;
3175                 size = argEntry->numRegs;
3176                 nextFltArgRegNum = genMapFloatRegNumToRegArgNum(argEntry->regNum);
3177                 assert(size == 1);
3178                 isBackFilled = true;
3179             }
3180             else if (argEntry->regNum == REG_STK)
3181             {
3182                 isRegArg = false;
3183                 assert(argEntry->numRegs == 0);
3184                 size = argEntry->numSlots;
3185             }
3186             else
3187             {
3188                 isRegArg = true;
3189                 assert(argEntry->numRegs > 0);
3190                 size = argEntry->numRegs + argEntry->numSlots;
3191             }
3192
3193             // This size has now been computed
3194             assert(size != 0);
3195         }
3196         else  // !lateArgsComputed
3197         {
3198             //
3199             // Figure out the size of the argument. This is either in number of registers, or number of TARGET_POINTER_SIZE
3200             // stack slots, or the sum of these if the argument is split between the registers and the stack.
3201             //
3202             if (argx->IsArgPlaceHolderNode() || (!isStructArg))
3203             {
3204 #if   defined(_TARGET_AMD64_)
3205 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3206                 if (!isStructArg)
3207                 {
3208                     size = 1; // On AMD64, all primitives fit in a single (64-bit) 'slot'
3209                 }
3210                 else
3211                 {
3212                     size = (unsigned)(roundUp(info.compCompHnd->getClassSize(argx->gtArgPlace.gtArgPlaceClsHnd), TARGET_POINTER_SIZE)) / TARGET_POINTER_SIZE;
3213                     eeGetSystemVAmd64PassStructInRegisterDescriptor(argx->gtArgPlace.gtArgPlaceClsHnd, &structDesc);
3214                     if (size > 1)
3215                     {
3216                         hasMultiregStructArgs = true;
3217                     }
3218                 }
3219 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
3220                 size = 1; // On AMD64, all primitives fit in a single (64-bit) 'slot'
3221 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3222 #elif defined(_TARGET_ARM64_)    
3223                 if (isStructArg)
3224                 {
3225                     if (isHfaArg)
3226                     {
3227                         size = GetHfaCount(argx);
3228                         // HFA structs are passed by value in multiple registers
3229                         hasMultiregStructArgs = true;
3230                     }
3231                     else
3232                     {
3233                         // Structs are either passed in 1 or 2 (64-bit) slots
3234                         size = (unsigned)(roundUp(info.compCompHnd->getClassSize(argx->gtArgPlace.gtArgPlaceClsHnd), TARGET_POINTER_SIZE)) / TARGET_POINTER_SIZE;
3235
3236                         if (size == 2)
3237                         {
3238                             // Structs that are the size of 2 pointers are passed by value in multiple registers
3239                             hasMultiregStructArgs = true;
3240                         }
3241                         else if (size > 2)
3242                         {
3243                             size = 1;  // Structs that are larger that 2 pointers (except for HFAs) are passed by reference (to a copy)
3244                         }
3245                     }
3246                     // Note that there are some additional rules for multireg structs.
3247                     // (i.e they cannot be split betwen registers and the stack)
3248                 }
3249                 else
3250                 {
3251                     size = 1; // Otherwise, all primitive types fit in a single (64-bit) 'slot'
3252                 }
3253 #elif defined(_TARGET_ARM_)
3254                 if (isStructArg)
3255                 {
3256                     size = (unsigned)(roundUp(info.compCompHnd->getClassSize(argx->gtArgPlace.gtArgPlaceClsHnd), TARGET_POINTER_SIZE)) / TARGET_POINTER_SIZE;
3257                 }
3258                 else
3259                 {
3260                     // The typical case
3261                     size = genTypeStSz(argx->gtType);
3262                 }
3263 #elif defined(_TARGET_X86_)
3264                 size = genTypeStSz(argx->gtType);
3265 #else 
3266 #error Unsupported or unset target architecture
3267 #endif // _TARGET_XXX_
3268             }
3269 #ifdef _TARGET_ARM_
3270             else if (isHfaArg)
3271             {
3272                 size = GetHfaCount(argx);
3273             }
3274 #endif // _TARGET_ARM_
3275             else // struct type
3276             {
3277                 // We handle two opcodes: GT_MKREFANY and GT_OBJ
3278                 if (argx->gtOper == GT_MKREFANY)
3279                 {
3280                     if (varTypeIsStruct(argx))
3281                     {
3282                         isStructArg = true;
3283                     }
3284 #ifdef _TARGET_AMD64_
3285 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3286                     if (varTypeIsStruct(argx))
3287                     {
3288                         size = info.compCompHnd->getClassSize(impGetRefAnyClass());
3289                         unsigned roundupSize = (unsigned)roundUp(size, TARGET_POINTER_SIZE);
3290                         size = roundupSize / TARGET_POINTER_SIZE;
3291                         eeGetSystemVAmd64PassStructInRegisterDescriptor(impGetRefAnyClass(), &structDesc);
3292                     }
3293                     else
3294 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3295                     {
3296                         size = 1;
3297                     }
3298 #else
3299                     size = 2;
3300 #endif
3301                 }
3302                 else // We must have a GT_OBJ with a struct type, but the GT_OBJ may be be a child of a GT_COMMA
3303                 {
3304                     GenTreePtr   argObj         = argx;
3305                     GenTreePtr*  parentOfArgObj = parentArgx;
3306
3307                     assert(args->IsList());
3308                     assert(argx == args->Current());
3309
3310                     /* The GT_OBJ may be be a child of a GT_COMMA */
3311                     while (argObj->gtOper == GT_COMMA)
3312                     {
3313                         parentOfArgObj = &argObj->gtOp.gtOp2;
3314                         argObj         = argObj->gtOp.gtOp2;
3315                     }
3316
3317                     if (argObj->gtOper != GT_OBJ)
3318                         BADCODE("illegal argument tree in fgMorphArgs");
3319
3320                     CORINFO_CLASS_HANDLE objClass = argObj->gtObj.gtClass;
3321 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3322                     eeGetSystemVAmd64PassStructInRegisterDescriptor(objClass, &structDesc);
3323 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3324
3325                     unsigned originalSize = info.compCompHnd->getClassSize(objClass);
3326                     originalSize = (originalSize == 0 ? TARGET_POINTER_SIZE : originalSize);
3327                     unsigned roundupSize  = (unsigned)roundUp(originalSize, TARGET_POINTER_SIZE);
3328
3329                     structSize = originalSize;
3330
3331 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3332                     // On System V OS-es a struct is never passed by reference.
3333                     // It is either passed by value on the stack or in registers.
3334                     bool     passStructInRegisters = false;
3335 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
3336                     bool     passStructByRef = false;
3337 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
3338
3339                     // The following if-then-else needs to be carefully refactored
3340                     // Basically the else portion wants to turn a struct load (a GT_OBJ)'
3341                     // into a GT_IND of the appropriate size. 
3342                     // It can do this with structs sizes that are 1,2,4, or 8 bytes
3343                     // It can't do this when FEATURE_UNIX_AMD64_STRUCT_PASSING is defined  (Why?)
3344                     // TODO-Cleanup: Remove the #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING below
3345                     // It also can't do this if we have a HFA arg, 
3346                     // unless we have a 1-elem HFA in which case we want to do the optization
3347                     // 
3348 #ifndef _TARGET_X86_
3349 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
3350                     // Check for struct argument with size 1, 2, 4 or 8 bytes
3351                     // As we can optimize these by turning them into a GT_IND of the correct type
3352                     if ((originalSize > TARGET_POINTER_SIZE) || ((originalSize & (originalSize - 1)) != 0) || (isHfaArg && (hfaSlots != 1)))
3353 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3354                     {
3355                         // Normalize 'size' to the number of pointer sized items
3356                         // 'size' is the number of register slots that we will use to pass the argument
3357                         size = roundupSize / TARGET_POINTER_SIZE;
3358 #if defined(_TARGET_AMD64_)
3359 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
3360                         size = 1;      // This must be copied to a temp and passed by address
3361                         passStructByRef = true;
3362                         copyBlkClass = objClass;
3363 #else // FEATURE_UNIX_AMD64_STRUCT_PASSING
3364                         if (!structDesc.passedInRegisters)
3365                         {
3366                             passStructInRegisters = false;
3367                             copyBlkClass = NO_CLASS_HANDLE;
3368                         }
3369                         else
3370                         {
3371                             // The objClass is used to materialize the struct on stack.
3372                             passStructInRegisters = true;
3373                             copyBlkClass = objClass;
3374                         }
3375 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3376 #elif defined(_TARGET_ARM64_)
3377                         if ((size > 2) && !isHfaArg)
3378                         {
3379                             size = 1;      // This must be copied to a temp and passed by address
3380                             passStructByRef = true;
3381                             copyBlkClass = objClass;
3382                         }
3383 #endif
3384
3385 #ifdef _TARGET_ARM_
3386                         // If we're passing a promoted struct local var, 
3387                         // we may need to skip some registers due to alignment; record those.
3388                         GenTreePtr lclVar = fgIsIndirOfAddrOfLocal(argObj);
3389                         if (lclVar != NULL)
3390                         {
3391                             LclVarDsc*  varDsc = &lvaTable[lclVar->gtLclVarCommon.gtLclNum];
3392                             if (varDsc->lvPromoted)
3393                             {
3394                                 assert(argObj->OperGet() == GT_OBJ);
3395                                 if (lvaGetPromotionType(varDsc) == PROMOTION_TYPE_INDEPENDENT)
3396                                 {
3397                                     fgAddSkippedRegsInPromotedStructArg(varDsc, intArgRegNum, &argSkippedRegMask);
3398                                 }
3399                             }
3400                         }
3401 #endif // _TARGET_ARM_
3402                     }
3403 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
3404                     else   // We have a struct argument with size 1, 2, 4 or 8 bytes
3405                     {
3406                         // change our GT_OBJ into a GT_IND of the correct type.
3407                         // We've already ensured above that size is a power of 2, and less than or equal to pointer size.
3408                         structBaseType = argOrReturnTypeForStruct(originalSize, objClass, false /* forReturn */);
3409                         if (isHfaArg)
3410                         {
3411                             // If we reach here with an HFA arg it has to be a one element HFA
3412                             assert(hfaSlots == 1);
3413                             structBaseType = hfaType;   // change the indirection type to a floating point type
3414                         }
3415                         noway_assert(structBaseType != TYP_UNKNOWN);
3416
3417                         argObj->ChangeOper(GT_IND);
3418
3419                         // Now see if we can fold *(&X) into X
3420                         if (argObj->gtOp.gtOp1->gtOper == GT_ADDR)
3421                         {
3422                             GenTreePtr temp = argObj->gtOp.gtOp1->gtOp.gtOp1;
3423
3424                             // Keep the DONT_CSE flag in sync
3425                             // (as the addr always marks it for its op1)
3426                             temp->gtFlags &= ~GTF_DONT_CSE;
3427                             temp->gtFlags |= (argObj->gtFlags & GTF_DONT_CSE);
3428                             DEBUG_DESTROY_NODE(argObj->gtOp.gtOp1);   // GT_ADDR
3429                             DEBUG_DESTROY_NODE(argObj);               // GT_IND
3430
3431                             argObj = temp;
3432                             *parentOfArgObj = temp;
3433
3434                             // If the OBJ had been the top level node, we've now changed argx.
3435                             if (parentOfArgObj == parentArgx)
3436                                 argx = temp;
3437                         }
3438                         if (argObj->gtOper == GT_LCL_VAR)
3439                         {
3440                             unsigned lclNum = argObj->gtLclVarCommon.gtLclNum;
3441                             LclVarDsc *  varDsc = &lvaTable[lclNum];
3442
3443                             if (varDsc->lvPromoted)
3444                             {
3445                                 if (varDsc->lvFieldCnt == 1) 
3446                                 {
3447                                     // get the first and only promoted field
3448                                     LclVarDsc *  fieldVarDsc = &lvaTable[varDsc->lvFieldLclStart];
3449                                     if (genTypeSize(fieldVarDsc->TypeGet()) >= originalSize)
3450                                     {
3451                                         // we will use the first and only promoted field
3452                                         argObj->gtLclVarCommon.SetLclNum(varDsc->lvFieldLclStart);
3453
3454                                         if (varTypeCanReg(fieldVarDsc->TypeGet()) && (genTypeSize(fieldVarDsc->TypeGet()) == originalSize))
3455                                         {
3456                                             // Just use the existing field's type
3457                                             argObj->gtType = fieldVarDsc->TypeGet();
3458                                         }
3459                                         else 
3460                                         {
3461                                             // Can't use the existing field's type, so use GT_LCL_FLD to swizzle
3462                                             // to a new type
3463                                             argObj->ChangeOper(GT_LCL_FLD);
3464                                             argObj->gtType = structBaseType;
3465                                         }
3466                                         assert(varTypeCanReg(argObj->TypeGet()));
3467                                         assert(copyBlkClass == NO_CLASS_HANDLE);
3468                                     }
3469                                     else
3470                                     {
3471                                         // use GT_LCL_FLD to swizzle the single field struct to a new type
3472                                         lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
3473                                         argObj->ChangeOper(GT_LCL_FLD);
3474                                         argObj->gtType = structBaseType;
3475                                     }
3476                                 }
3477                                 else
3478                                 {
3479                                     // The struct fits into a single register, but it has been promoted into its
3480                                     // constituent fields, and so we have to re-assemble it
3481                                     copyBlkClass = objClass;
3482 #ifdef _TARGET_ARM_
3483                                     // Alignment constraints may cause us not to use (to "skip") some argument registers.
3484                                     // Add those, if any, to the skipped (int) arg reg mask.
3485                                     fgAddSkippedRegsInPromotedStructArg(varDsc, intArgRegNum, &argSkippedRegMask);
3486 #endif // _TARGET_ARM_
3487                                 }
3488                             }
3489                             else if (!varTypeIsIntegralOrI(varDsc->TypeGet()))
3490                             {
3491                                 // Not a promoted struct, so just swizzle the type by using GT_LCL_FLD
3492                                 argObj->ChangeOper(GT_LCL_FLD);
3493                                 argObj->gtType = structBaseType;
3494                             }
3495                         }
3496                         else
3497                         {
3498                             // Not a GT_LCL_VAR, so we can just change the type on the node
3499                             argObj->gtType = structBaseType;
3500                         }
3501                         assert(varTypeCanReg(argObj->TypeGet()) ||
3502                                ((copyBlkClass != NO_CLASS_HANDLE) && varTypeIsIntegral(structBaseType)));
3503
3504                         size = 1;
3505                     }
3506 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3507
3508 #endif // not _TARGET_X86_
3509                     // We still have a struct unless we converted the GT_OBJ into a GT_IND above...
3510                     if ((structBaseType == TYP_STRUCT) &&
3511 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3512                         !passStructInRegisters
3513 #else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3514                         !passStructByRef
3515 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3516                         )
3517                     {
3518                         if (isHfaArg && passUsingFloatRegs)
3519                         {
3520                             size = GetHfaCount(argx);  // GetHfaCount returns number of elements in the HFA
3521                         }
3522                         else
3523                         {
3524                             // if the valuetype size is not a multiple of sizeof(void*),
3525                             // we must copyblk to a temp before doing the obj to avoid
3526                             // the obj reading memory past the end of the valuetype
3527 #if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
3528                         // TODO-X86-CQ: [1091733] Revisit for small structs, we should use push instruction
3529                             copyBlkClass = objClass;
3530                             size = roundupSize / TARGET_POINTER_SIZE;   // Normalize size to number of pointer sized items
3531 #else // !defined(_TARGET_X86_) || defined(LEGACY_BACKEND)
3532                             if (roundupSize > originalSize)
3533                             {
3534                                 copyBlkClass = objClass;
3535
3536                                 // There are a few special cases where we can omit using a CopyBlk
3537                                 // where we normally would need to use one.
3538
3539                                 GenTreePtr  objAddr = argObj->gtObj.gtOp1;
3540                                 if (objAddr->gtOper == GT_ADDR)
3541                                 {
3542                                     // exception : no need to use CopyBlk if the valuetype is on the stack
3543                                     if (objAddr->gtFlags & GTF_ADDR_ONSTACK)
3544                                     {
3545                                         copyBlkClass = NO_CLASS_HANDLE;
3546                                     }
3547                                     // exception : no need to use CopyBlk if the valuetype is already a struct local
3548                                     else if (objAddr->gtOp.gtOp1->gtOper == GT_LCL_VAR)
3549                                     {
3550                                         copyBlkClass = NO_CLASS_HANDLE;
3551                                     }
3552                                 }
3553                             }
3554
3555                             size = roundupSize / TARGET_POINTER_SIZE;   // Normalize size to number of pointer sized items
3556 #endif // !defined(_TARGET_X86_) || defined(LEGACY_BACKEND)
3557                         }
3558                     }
3559                 }
3560                 if (size > 1)
3561                 {
3562                     hasMultiregStructArgs = true;
3563                 }
3564             }
3565
3566             // The 'size' value has now must have been set. (the original value of zero is an invalid value)
3567             assert(size != 0);
3568
3569             //
3570             // Figure out if the argument will be passed in a register.
3571             //
3572             bool passedInRegisters = true;
3573 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3574             passedInRegisters = !isStructArg;
3575             if (!passedInRegisters)
3576             {
3577                 if (structDesc.passedInRegisters)
3578                 {
3579                     passedInRegisters = true;
3580                 }
3581                 else
3582                 {
3583                     passedInRegisters = false;
3584                 }
3585             }
3586
3587 #endif
3588             if (passedInRegisters && isRegParamType(genActualType(argx->TypeGet())))
3589             {
3590 #ifdef _TARGET_ARM_
3591                 if (passUsingFloatRegs)
3592                 {
3593                     // First, see if it can be back-filled
3594                     if (!anyFloatStackArgs &&                   // Is it legal to back-fill? (We haven't put any FP args on the stack yet)
3595                         (fltArgSkippedRegMask != RBM_NONE) &&   // Is there an available back-fill slot?
3596                         (size == 1))                            // The size to back-fill is one float register
3597                     {
3598                         // Back-fill the register.
3599                         isBackFilled = true;
3600                         regMaskTP backFillBitMask = genFindLowestBit(fltArgSkippedRegMask);
3601                         fltArgSkippedRegMask &= ~backFillBitMask;   // Remove the back-filled register(s) from the skipped mask
3602                         nextFltArgRegNum = genMapFloatRegNumToRegArgNum(genRegNumFromMask(backFillBitMask));
3603                         assert(nextFltArgRegNum < MAX_FLOAT_REG_ARG);
3604                     }
3605
3606                     // Does the entire float, double, or HFA fit in the FP arg registers?
3607                     // Check if the last register needed is still in the argument register range.
3608                     isRegArg = (nextFltArgRegNum + size - 1) < MAX_FLOAT_REG_ARG;
3609
3610                     if (!isRegArg)
3611                     {
3612                         anyFloatStackArgs = true;
3613                     }
3614                 }
3615                 else
3616                 {
3617                     isRegArg = intArgRegNum < MAX_REG_ARG;
3618                 }
3619 #elif _TARGET_ARM64_
3620                 if (passUsingFloatRegs)
3621                 {
3622                     // Check if the last register needed is still in the fp argument register range.
3623                     isRegArg = (nextFltArgRegNum + (size - 1)) < MAX_FLOAT_REG_ARG;
3624
3625                     // Do we have a HFA arg that we wanted to pass in registers, but we ran out of FP registers?
3626                     if (isHfaArg && !isRegArg)
3627                     {
3628                         // recompute the 'size' so that it represent the number of stack slots rather than the number of registers
3629                         //
3630                         unsigned roundupSize = (unsigned)roundUp(structSize, TARGET_POINTER_SIZE);
3631                         size = roundupSize / TARGET_POINTER_SIZE;
3632                     }
3633                 }
3634                 else
3635                 {
3636                     // Check if the last register needed is still in the int argument register range.
3637                     isRegArg = (intArgRegNum + (size - 1)) < maxRegArgs;
3638                 }
3639 #else // not _TARGET_ARM_ or _TARGET_ARM64_
3640
3641 #if defined(UNIX_AMD64_ABI)
3642
3643 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3644                 // Here a struct can be passed in register following the classifications of its members and size.
3645                 // Now make sure there are actually enough registers to do so.
3646                 if (isStructArg)
3647                 {
3648                     for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
3649                     {
3650                         if (structDesc.IsIntegralSlot(i))
3651                         {
3652                             structIntRegs++;
3653                         }
3654                         else if (structDesc.IsSseSlot(i))
3655                         {
3656                             structFloatRegs++;
3657                         }
3658                     }
3659
3660                     if (((nextFltArgRegNum + structFloatRegs) > MAX_FLOAT_REG_ARG) ||
3661                         ((intArgRegNum + structIntRegs) > MAX_REG_ARG))
3662                     {
3663                         isRegArg = false;
3664                         nonRegPassableStruct = true;
3665                     }
3666                     else
3667                     {
3668                         isRegArg = true;
3669                         nonRegPassableStruct = false;
3670                     }
3671                 }
3672                 else
3673 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3674                 {
3675                     if (passUsingFloatRegs)
3676                     {
3677                         isRegArg = nextFltArgRegNum < MAX_FLOAT_REG_ARG;
3678                     }
3679                     else
3680                     {
3681                         isRegArg = intArgRegNum < MAX_REG_ARG;
3682                     }
3683                 }
3684 #else // !defined(UNIX_AMD64_ABI)
3685                 isRegArg = (intArgRegNum+(size-1)) < maxRegArgs;
3686 #endif // !defined(UNIX_AMD64_ABI)
3687 #endif // _TARGET_ARM_
3688             }
3689             else
3690             {
3691                 isRegArg = false;
3692
3693 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3694                 nonRegPassableStruct = true;
3695 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3696             }
3697         }
3698
3699         //
3700         // Now we know if the argument goes in registers or not and how big it is,
3701         // whether we had to just compute it or this is a re-morph call and we looked it up.
3702         //
3703
3704 #ifdef _TARGET_ARM_
3705
3706         // If we ever allocate a floating point argument to the stack, then all
3707         // subsequent HFA/float/double arguments go on the stack.
3708         if (!isRegArg && passUsingFloatRegs)
3709         {
3710             for (; fltArgRegNum < MAX_FLOAT_REG_ARG; ++fltArgRegNum)
3711             {
3712                 fltArgSkippedRegMask |= genMapArgNumToRegMask(fltArgRegNum, TYP_FLOAT);
3713             }
3714         }
3715
3716         // If we think we're going to split a struct between integer registers and the stack, check to
3717         // see if we've already assigned a floating-point arg to the stack.
3718         if (isRegArg &&                                 // We decided above to use a register for the argument
3719             !passUsingFloatRegs &&                      // We're using integer registers
3720             (intArgRegNum + size > MAX_REG_ARG) &&      // We're going to split a struct type onto registers and stack
3721             anyFloatStackArgs)                          // We've already used the stack for a floating-point argument
3722         {
3723             isRegArg = false;               // Change our mind; don't pass this struct partially in registers
3724
3725             // Skip the rest of the integer argument registers
3726             for (; intArgRegNum < MAX_REG_ARG; ++intArgRegNum)
3727             {
3728                 argSkippedRegMask |= genMapArgNumToRegMask(intArgRegNum, TYP_I_IMPL);
3729             }
3730         }
3731
3732 #endif // _TARGET_ARM_
3733         if (isRegArg)
3734         {
3735             regNumber nextRegNum = REG_STK;
3736 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3737             regNumber nextOtherRegNum = REG_STK;
3738
3739             if (isStructArg && structDesc.passedInRegisters)
3740             {
3741                 // It is a struct passed in registers. Assign the next available register.
3742                 unsigned int curIntReg = intArgRegNum;
3743                 unsigned int curFloatReg = nextFltArgRegNum;
3744                 for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
3745                 {
3746                     if (structDesc.IsIntegralSlot(i))
3747                     {
3748                         if (i == 0)
3749                         {
3750                             nextRegNum = genMapIntRegArgNumToRegNum(curIntReg);
3751
3752                             // For non-completed args the counters are incremented already
3753                             // in the !lateArgsComputed above.
3754                             if (lateArgsComputed)
3755                             {
3756                                 structIntRegs++;
3757                             }
3758                         }
3759                         else if (i == 1)
3760                         {
3761                             nextOtherRegNum = genMapIntRegArgNumToRegNum(curIntReg);
3762
3763                             if (lateArgsComputed)
3764                             {
3765                                 structIntRegs++;
3766                             }
3767                         }
3768                         else
3769                         {
3770                             assert(false && "fgMorphArgs Invalid index for int classification.");
3771                         }
3772
3773                         curIntReg++;
3774                     }
3775                     else if (structDesc.IsSseSlot(i))
3776                     {
3777                         if (i == 0)
3778                         {
3779                             nextRegNum = genMapFloatRegArgNumToRegNum(curFloatReg);
3780
3781                             if (lateArgsComputed)
3782                             {
3783                                 structFloatRegs++;
3784                             }
3785                         }
3786                         else if (i == 1)
3787                         {
3788                             nextOtherRegNum = genMapFloatRegArgNumToRegNum(curFloatReg);
3789
3790                             if (lateArgsComputed)
3791                             {
3792                                 structFloatRegs++;
3793                             }
3794                         }
3795                         else
3796                         {
3797                             assert(false && "fgMorphArgs Invalid index for SSE classification.");
3798                         }
3799
3800                         curFloatReg++;
3801                     }
3802                 }
3803             }
3804             else
3805 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3806             {
3807                 // fill in or update the argInfo table 
3808                 nextRegNum = passUsingFloatRegs ? genMapFloatRegArgNumToRegNum(nextFltArgRegNum) : genMapIntRegArgNumToRegNum(intArgRegNum);
3809             }
3810
3811 #ifdef _TARGET_AMD64_
3812 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
3813             assert(size == 1);
3814 #endif
3815 #endif
3816
3817 #ifndef LEGACY_BACKEND
3818             // If there are nonstandard args (outside the calling convention) they were inserted above
3819             // and noted them in a table so we can recognize them here and build their argInfo.
3820             // 
3821             // They should not affect the placement of any other args or stack space required.
3822             // Example: on AMD64 R10 and R11 are used for indirect VSD (generic interface) and cookie calls.
3823             bool nonStandardFound = false;
3824             for (int i=0; i<nonStandardArgs.Height(); i++)
3825             {
3826                 hasNonStandardArg = true;
3827                 if (argx == nonStandardArgs.Index(i).node)
3828                 {
3829                     fgArgTabEntry* argEntry = call->fgArgInfo->AddRegArg(argIndex, 
3830                                                                          argx,
3831                                                                          args, 
3832                                                                          nonStandardArgs.Index(i).reg, 
3833                                                                          size, 
3834                                                                          argAlign
3835 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3836                                                                          , isStructArg, 
3837                                                                          nextOtherRegNum, 
3838                                                                          &structDesc
3839 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3840                     );
3841                     argEntry->isNonStandard = true;
3842                     argIndex++;
3843                     nonStandardFound = true;
3844                     break;
3845                 }
3846             }
3847             if (nonStandardFound)
3848                 continue;
3849 #endif // !LEGACY_BACKEND
3850
3851             if (!lateArgsComputed)
3852             {
3853                 // This is a register argument - put it in the table
3854                 fgArgTabEntryPtr newArg = call->fgArgInfo->AddRegArg(argIndex, 
3855                                                                      argx, 
3856                                                                      args, 
3857                                                                      nextRegNum, 
3858                                                                      size, 
3859                                                                      argAlign
3860 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3861                                                                      , isStructArg, 
3862                                                                      nextOtherRegNum, 
3863                                                                      &structDesc
3864 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3865                     );
3866                 (void)newArg; //prevent "unused variable" error from GCC
3867
3868                 newArg->SetIsHfaRegArg(passUsingFloatRegs && isHfaArg); // Note on Arm32 a HFA is passed in int regs for varargs
3869
3870 #ifdef _TARGET_ARM_
3871                 newArg->SetIsBackFilled(isBackFilled);
3872 #endif // _TARGET_ARM_
3873             }
3874             else
3875             {
3876                 // This is a register argument - possibly update it in the table
3877                 fgArgTabEntryPtr entry = call->fgArgInfo->RemorphRegArg(argIndex, argx, args, nextRegNum, size, argAlign);
3878                 if (entry->isNonStandard)
3879                 {
3880                     argIndex++;
3881                     continue;
3882                 }
3883             }
3884
3885             // Setup the next argRegNum value
3886             if (!isBackFilled)
3887             {
3888 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3889                 if (isStructArg)
3890                 {
3891                     intArgRegNum += structIntRegs;
3892                     fltArgRegNum += structFloatRegs;
3893                 }
3894                 else
3895 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3896                 {
3897                     if (passUsingFloatRegs)
3898                     {
3899                         fltArgRegNum += size;
3900
3901 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
3902                         argSkippedRegMask |= genMapArgNumToRegMask(intArgRegNum, TYP_I_IMPL);
3903                         intArgRegNum = min(intArgRegNum + size, MAX_REG_ARG);
3904 #endif // _TARGET_AMD64_
3905 #ifdef _TARGET_ARM_
3906                         if (fltArgRegNum > MAX_FLOAT_REG_ARG)
3907                         {
3908                             // This indicates a partial enregistration of a struct type
3909                             assert(varTypeIsStruct(argx));
3910                             unsigned numRegsPartial = size - (fltArgRegNum - MAX_FLOAT_REG_ARG);
3911                             assert((unsigned char)numRegsPartial == numRegsPartial);
3912                             call->fgArgInfo->SplitArg(argIndex, numRegsPartial, size - numRegsPartial);
3913                             fltArgRegNum = MAX_FLOAT_REG_ARG;
3914                         }
3915 #endif // _TARGET_ARM_
3916                     }
3917                     else
3918                     {
3919                         intArgRegNum += size;
3920
3921 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
3922                         fltArgSkippedRegMask |= genMapArgNumToRegMask(fltArgRegNum, TYP_DOUBLE);
3923                         fltArgRegNum = min(fltArgRegNum + size, MAX_FLOAT_REG_ARG);
3924 #endif // _TARGET_AMD64_
3925 #ifdef _TARGET_ARM_
3926                         if (intArgRegNum > MAX_REG_ARG)
3927                         {
3928                             // This indicates a partial enregistration of a struct type
3929                             assert((isStructArg) || argx->OperIsCopyBlkOp() ||
3930                                 (argx->gtOper == GT_COMMA && (args->gtFlags & GTF_ASG)));
3931                             unsigned numRegsPartial = size - (intArgRegNum - MAX_REG_ARG);
3932                             assert((unsigned char)numRegsPartial == numRegsPartial);
3933                             call->fgArgInfo->SplitArg(argIndex, numRegsPartial, size - numRegsPartial);
3934                             intArgRegNum = MAX_REG_ARG;
3935                             fgPtrArgCntCur += size - numRegsPartial;
3936                         }
3937 #endif // _TARGET_ARM_
3938                     }
3939                 }
3940             }
3941         }
3942         else  // We have an argument that is not passed in a register
3943         {
3944             fgPtrArgCntCur += size;
3945
3946             // If the register arguments have not been determined then we must fill in the argInfo
3947
3948             if  (!lateArgsComputed)
3949             {
3950                 // This is a stack argument - put it in the table
3951                 call->fgArgInfo->AddStkArg(argIndex, argx, args, size, argAlign FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(isStructArg));
3952
3953             }
3954             else
3955             {
3956                 // This is a stack argument - possibly update it in the table
3957                 call->fgArgInfo->RemorphStkArg(argIndex, argx, args, size, argAlign);
3958             }
3959         }
3960         if (copyBlkClass != NO_CLASS_HANDLE)
3961         {
3962             noway_assert(!lateArgsComputed);
3963             fgMakeOutgoingStructArgCopy(call, args, argIndex, copyBlkClass FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(&structDesc));
3964         }
3965
3966 #ifndef LEGACY_BACKEND
3967         if (argx->gtOper == GT_MKREFANY)
3968         {
3969             NYI_X86("MKREFANY");
3970
3971             // 'Lower' the MKREFANY tree and insert it.
3972             noway_assert(!lateArgsComputed);
3973
3974             // Get a new temp
3975             // Here we don't need unsafe value cls check since the addr of temp is used only in mkrefany
3976             unsigned   tmp = lvaGrabTemp(true DEBUGARG("by-value mkrefany struct argument"));
3977             lvaSetStruct(tmp, impGetRefAnyClass(), false);
3978
3979
3980             // Build the mkrefany as a comma node:
3981             // (tmp.ptr=argx),(tmp.type=handle)
3982             GenTreeLclFld* destPtrSlot  = gtNewLclFldNode(tmp, TYP_I_IMPL, offsetof(CORINFO_RefAny, dataPtr));
3983             GenTreeLclFld* destTypeSlot = gtNewLclFldNode(tmp, TYP_I_IMPL, offsetof(CORINFO_RefAny, type));
3984             destPtrSlot->gtFieldSeq  = GetFieldSeqStore()->CreateSingleton(GetRefanyDataField());
3985             destPtrSlot->gtFlags |= GTF_VAR_DEF;
3986             destTypeSlot->gtFieldSeq = GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField());
3987             destTypeSlot->gtFlags |= GTF_VAR_DEF;
3988
3989             GenTreePtr asgPtrSlot   = gtNewAssignNode(destPtrSlot, argx->gtOp.gtOp1);
3990             GenTreePtr asgTypeSlot  = gtNewAssignNode(destTypeSlot, argx->gtOp.gtOp2);
3991             GenTreePtr asg = gtNewOperNode(GT_COMMA, TYP_VOID, asgPtrSlot, asgTypeSlot);
3992
3993             // Change the expression to "(tmp=val)"
3994             args->gtOp.gtOp1 = asg;
3995
3996             // EvalArgsToTemps will cause tmp to actually get loaded as the argument
3997             call->fgArgInfo->EvalToTmp(argIndex, tmp, asg);
3998             lvaSetVarAddrExposed(tmp);
3999         }
4000 #endif // !LEGACY_BACKEND
4001
4002         argIndex++;
4003 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
4004         if (nonRegPassableStruct)
4005         {
4006             nonRegPassedStructSlots += size;
4007         }
4008         else
4009 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
4010         {
4011             argSlots += size;
4012         }
4013     } // end foreach argument loop
4014
4015     if  (!lateArgsComputed)
4016     {
4017         call->fgArgInfo->ArgsComplete();
4018
4019         call->gtCallRegUsedMask = genIntAllRegArgMask(intArgRegNum) & ~argSkippedRegMask;
4020         if (fltArgRegNum > 0)
4021         {
4022 #if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
4023             call->gtCallRegUsedMask |= genFltAllRegArgMask(fltArgRegNum) & ~fltArgSkippedRegMask;
4024 #endif
4025         }
4026     }
4027
4028     if (call->gtCallArgs)
4029     {
4030         UpdateGT_LISTFlags(call->gtCallArgs);
4031     }
4032
4033     /* Process the function address, if indirect call */
4034
4035     if (call->gtCallType == CT_INDIRECT)
4036         call->gtCallAddr = fgMorphTree(call->gtCallAddr);
4037
4038     call->fgArgInfo->RecordStkLevel(fgPtrArgCntCur);
4039
4040     if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != NULL))
4041         fgPtrArgCntCur++;
4042
4043     /* Remember the maximum value we ever see */
4044
4045     if  (fgPtrArgCntMax < fgPtrArgCntCur)
4046          fgPtrArgCntMax = fgPtrArgCntCur;
4047
4048     /* The call will pop all the arguments we pushed */
4049
4050     fgPtrArgCntCur = genPtrArgCntSav;
4051
4052 #if FEATURE_FIXED_OUT_ARGS
4053
4054     // Update the outgoing argument size.
4055     // If the call is a fast tail call, it will setup its arguments in incoming arg
4056     // area instead of the out-going arg area.  Therefore, don't consider fast tail
4057     // calls to update lvaOutgoingArgSpaceSize.
4058     if (!call->IsFastTailCall())
4059     {
4060         unsigned preallocatedArgCount = call->fgArgInfo->GetNextSlotNum();
4061
4062 #if defined(UNIX_AMD64_ABI)
4063         opts.compNeedToAlignFrame = true;   // this is currently required for the UNIX ABI to work correctly  
4064
4065         // ToDo: Remove this re-calculation preallocatedArgCount and use the value assigned above.
4066
4067         // First slots go in registers only, no stack needed.
4068         // TODO-Amd64-Unix-CQ This calculation is only accurate for integer arguments,
4069         // and ignores floating point args (it is overly conservative in that case).
4070         if (argSlots <= MAX_REG_ARG)
4071         {
4072             preallocatedArgCount = nonRegPassedStructSlots;
4073         }
4074         else
4075         {
4076             preallocatedArgCount = argSlots + nonRegPassedStructSlots - MAX_REG_ARG;
4077         }
4078 #endif  // UNIX_AMD64_ABI
4079
4080         // Check if we need to increase the size of our Outgoing Arg Space
4081         if (preallocatedArgCount * REGSIZE_BYTES > lvaOutgoingArgSpaceSize)
4082         {
4083             lvaOutgoingArgSpaceSize = preallocatedArgCount * REGSIZE_BYTES;
4084
4085             // If a function has localloc, we will need to move the outgoing arg space when the
4086             // localloc happens. When we do this, we need to maintain stack alignment. To avoid
4087             // leaving alignment-related holes when doing this move, make sure the outgoing
4088             // argument space size is a multiple of the stack alignment by aligning up to the next
4089             // stack alignment boundary.
4090             if (compLocallocUsed)
4091             {
4092                 lvaOutgoingArgSpaceSize = (unsigned) roundUp(lvaOutgoingArgSpaceSize, STACK_ALIGN);
4093             }
4094         }        
4095 #ifdef DEBUG
4096         if (verbose)
4097         {
4098             printf("argSlots=%d, preallocatedArgCount=%d, nextSlotNum=%d, lvaOutgoingArgSpaceSize=%d",
4099                    argSlots, preallocatedArgCount, call->fgArgInfo->GetNextSlotNum(), lvaOutgoingArgSpaceSize);
4100         }
4101 #endif
4102     }
4103 #endif // FEATURE_FIXED_OUT_ARGS
4104
4105     /* Update the 'side effect' flags value for the call */
4106
4107     call->gtFlags |= (flagsSummary & GTF_ALL_EFFECT);
4108
4109     // If the register arguments have already been determined
4110     // or we have no register arguments then we are done.
4111
4112     bool needEvalArgsToTemps = true;
4113
4114     if (lateArgsComputed || (intArgRegNum == 0 && fltArgRegNum == 0 && !hasNonStandardArg && !hasStructArgument))
4115     {
4116         needEvalArgsToTemps = false;
4117     }
4118
4119     if (needEvalArgsToTemps)
4120     {
4121         // This is the first time that we morph this call AND it has register arguments.
4122         // Follow into the code below and do the 'defer or eval to temp' analysis.
4123
4124         call->fgArgInfo->SortArgs();
4125
4126         call->fgArgInfo->EvalArgsToTemps();
4127
4128         // We may have updated the arguments
4129         if (call->gtCallArgs)
4130         {
4131             UpdateGT_LISTFlags(call->gtCallArgs);
4132         }
4133     }
4134
4135 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
4136
4137     // Rewrite the struct args to be passed by value on stack or in registers.
4138     fgMorphSystemVStructArgs(call, hasStructArgument);
4139
4140 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
4141
4142     // In the future we can migrate UNIX_AMD64 to use this
4143     // method instead of fgMorphSystemVStructArgs
4144 #ifndef LEGACY_BACKEND
4145     // We only build GT_LISTs for MultiReg structs for the RyuJIT backend
4146     if (hasMultiregStructArgs)
4147     {
4148         fgMorphMultiregStructArgs(call);
4149     }
4150 #endif // LEGACY_BACKEND
4151
4152 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
4153
4154 #ifdef DEBUG
4155     if (verbose)
4156     {
4157         fgArgInfoPtr argInfo = call->fgArgInfo;
4158
4159         for (unsigned curInx = 0; curInx < argInfo->ArgCount(); curInx++)
4160         {
4161             fgArgTabEntryPtr curArgEntry = argInfo->ArgTable()[curInx];
4162             curArgEntry->Dump();
4163         }
4164     }
4165 #endif
4166
4167     return call;
4168 }
4169 #ifdef _PREFAST_
4170 #pragma warning(pop)
4171 #endif
4172
4173 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
4174 // fgMorphSystemVStructArgs:
4175 //   Rewrite the struct args to be passed by value on stack or in registers.
4176 //
4177 // args:
4178 //   call: The call whose arguments need to be morphed.
4179 //   hasStructArgument: Whether this call has struct arguments.
4180 //   
4181 void Compiler::fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgument)
4182 {
4183     unsigned flagsSummary = 0;
4184     GenTreePtr      args;
4185     GenTreePtr      argx;
4186
4187     if (hasStructArgument)
4188     {
4189         fgArgInfoPtr allArgInfo = call->fgArgInfo;
4190
4191         for (args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
4192         {
4193             // For late arguments the arg tree that is overridden is in the gtCallLateArgs list. 
4194             // For such late args the gtCallArgList contains the setup arg node (evaluating the arg.) 
4195             // The tree from the gtCallLateArgs list is passed to the callee. The fgArgEntry node contains the mapping
4196             // between the nodes in both lists. If the arg is not a late arg, the fgArgEntry->node points to itself,
4197             // otherwise points to the list in the late args list.
4198             bool isLateArg = (args->gtOp.gtOp1->gtFlags & GTF_LATE_ARG) != 0;
4199             fgArgTabEntryPtr fgEntryPtr = gtArgEntryByNode(call, args->gtOp.gtOp1);
4200             assert(fgEntryPtr != nullptr);
4201             GenTreePtr argx = fgEntryPtr->node;
4202             GenTreePtr lateList = nullptr;
4203             GenTreePtr lateNode = nullptr;
4204
4205             if (isLateArg)
4206             {
4207                 for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
4208                 {
4209                     assert(list->IsList());
4210
4211                     GenTreePtr argNode = list->Current();
4212                     if (argx == argNode)
4213                     {
4214                         lateList = list;
4215                         lateNode = argNode;
4216                         break;
4217                     }
4218                 }
4219                 assert(lateList != nullptr && lateNode != nullptr);
4220             }
4221             GenTreePtr arg = argx;
4222             bool argListCreated = false;
4223
4224             var_types  type = arg->TypeGet();
4225
4226             if (varTypeIsStruct(type))
4227             {
4228                 var_types originalType = type;
4229                 // If we have already processed the arg...
4230                 if (arg->OperGet() == GT_LIST && varTypeIsStruct(arg))
4231                 {
4232                     continue;
4233                 }
4234
4235                 // If already OBJ it is set properly already.
4236                 if (arg->OperGet() == GT_OBJ)
4237                 {
4238                     assert(!fgEntryPtr->structDesc.passedInRegisters);
4239                     continue;
4240                 }
4241
4242                 assert(
4243                     arg->OperGet() == GT_LCL_VAR ||
4244                     arg->OperGet() == GT_LCL_FLD ||
4245                     (arg->OperGet() == GT_ADDR &&
4246                         (arg->gtOp.gtOp1->OperGet() == GT_LCL_FLD ||
4247                          arg->gtOp.gtOp1->OperGet() == GT_LCL_VAR)));
4248
4249                 GenTreeLclVarCommon* lclCommon = arg->OperGet() == GT_ADDR ?
4250                     arg->gtOp.gtOp1->AsLclVarCommon() : arg->AsLclVarCommon();
4251                 if (fgEntryPtr->structDesc.passedInRegisters)
4252                 {
4253                     if (fgEntryPtr->structDesc.eightByteCount == 1)
4254                     {
4255                         // Change the type and below the code will change the LclVar to a LCL_FLD
4256                         type = GetTypeFromClassificationAndSizes(fgEntryPtr->structDesc.eightByteClassifications[0], fgEntryPtr->structDesc.eightByteSizes[0]);
4257                     }
4258                     else if (fgEntryPtr->structDesc.eightByteCount == 2)
4259                     {
4260                         // Create LCL_FLD for each eightbyte.
4261                         argListCreated = true;
4262
4263                         // Second eightbyte.
4264                         GenTreeLclFld* newLclField = new(this, GT_LCL_FLD) GenTreeLclFld(
4265                             GetTypeFromClassificationAndSizes(
4266                                 fgEntryPtr->structDesc.eightByteClassifications[1],
4267                                 fgEntryPtr->structDesc.eightByteSizes[1]),
4268                             lclCommon->gtLclNum,
4269                             fgEntryPtr->structDesc.eightByteOffsets[1]);
4270                         // Note this should actually be: secondNode = gtNewArgList(newLclField)
4271                         GenTreeArgList* secondNode = gtNewListNode(newLclField, nullptr);
4272                         secondNode->gtType = originalType; // Preserve the type. It is a special case.
4273                         newLclField->gtFieldSeq = FieldSeqStore::NotAField();
4274
4275                         // First field
4276                         arg->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
4277                         arg->gtType = GetTypeFromClassificationAndSizes(
4278                             fgEntryPtr->structDesc.eightByteClassifications[0],
4279                             fgEntryPtr->structDesc.eightByteSizes[0]);
4280                         arg = gtNewListNode(arg, secondNode);
4281                         arg->gtType = type; // Preserve the type. It is a special case.
4282                     }
4283                     else
4284                     {
4285                         assert(false && "More than two eightbytes detected for CLR."); // No more than two eightbytes for the CLR.
4286                     }
4287                 }
4288
4289                 // If we didn't change the type of the struct, it means
4290                 // its classification doesn't support to be passed directly through a
4291                 // register, so we need to pass a pointer to the destination where
4292                 // where we copied the struct to.
4293                 if (!argListCreated)
4294                 {
4295                     if (fgEntryPtr->structDesc.passedInRegisters)
4296                     {
4297                         arg->gtType = type;
4298                     }
4299                     else
4300                     {
4301                         // Make sure this is an addr node.
4302                         if (arg->OperGet() != GT_ADDR && arg->OperGet() != GT_LCL_VAR_ADDR)
4303                         {
4304                             arg = gtNewOperNode(GT_ADDR, TYP_I_IMPL, arg);
4305                         }
4306
4307                         assert(arg->OperGet() == GT_ADDR || arg->OperGet() == GT_LCL_VAR_ADDR);
4308
4309                         // Create an Obj of the temp to use it as a call argument.
4310                         arg = new (this, GT_OBJ) GenTreeObj(originalType, arg, lvaGetStruct(lclCommon->gtLclNum));
4311                         arg->gtFlags |= GTF_EXCEPT;
4312                         flagsSummary |= GTF_EXCEPT;
4313                     }
4314                 }
4315             }
4316
4317             if (argx != arg)
4318             {
4319                 bool isLateArg = (args->gtOp.gtOp1->gtFlags & GTF_LATE_ARG) != 0;
4320                 fgArgTabEntryPtr fgEntryPtr = gtArgEntryByNode(call, args->gtOp.gtOp1);
4321                 assert(fgEntryPtr != nullptr);
4322                 GenTreePtr argx = fgEntryPtr->node;
4323                 GenTreePtr lateList = nullptr;
4324                 GenTreePtr lateNode = nullptr;
4325                 if (isLateArg)
4326                 {
4327                     for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
4328                     {
4329                         assert(list->IsList());
4330
4331                         GenTreePtr argNode = list->Current();
4332                         if (argx == argNode)
4333                         {
4334                             lateList = list;
4335                             lateNode = argNode;
4336                             break;
4337                         }
4338                     }
4339                     assert(lateList != nullptr && lateNode != nullptr);
4340                 }
4341
4342                 fgEntryPtr->node = arg;
4343                 if (isLateArg)
4344                 {
4345                     lateList->gtOp.gtOp1 = arg;
4346                 }
4347                 else
4348                 {
4349                     args->gtOp.gtOp1 = arg;
4350                 }
4351             }
4352         }
4353     }
4354
4355     // Update the flags
4356     call->gtFlags |= (flagsSummary & GTF_ALL_EFFECT);
4357 }
4358 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
4359
4360 //-----------------------------------------------------------------------------
4361 // fgMorphMultiregStructArgs:  Locate the TYP_STRUCT arguments and 
4362 //                             call fgMorphMultiregStructArg on each of them.
4363 //
4364 // Arguments:
4365 //    call:    a GenTreeCall node that has one or more TYP_STRUCT arguments
4366 //
4367 // Notes:
4368 //    We only call fgMorphMultiregStructArg for the register passed TYP_STRUCT arguments.
4369 //    The call to fgMorphMultiregStructArg will mutate the argument into the GT_LIST form
4370 //    whicj is only used for register arguments.
4371 //    If this method fails to find any TYP_STRUCT arguments it will assert.
4372 //
4373 void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
4374 {
4375     GenTreePtr   args;
4376     GenTreePtr   argx;
4377     bool         foundStructArg = false;
4378     unsigned     initialFlags = call->gtFlags;
4379     unsigned     flagsSummary = 0;
4380     fgArgInfoPtr allArgInfo = call->fgArgInfo;
4381
4382     // Currently only ARM64 is using this method to morph the MultiReg struct args
4383     //  in the future AMD64_UNIX and for HFAs ARM32, will also use this method
4384     //
4385 #ifdef _TARGET_ARM_
4386     NYI_ARM("fgMorphMultiregStructArgs");
4387 #endif
4388 #ifdef _TARGET_X86_
4389     assert("Logic error: no MultiregStructArgs for X86");
4390 #endif
4391 #ifdef _TARGET_AMD64_
4392 #if defined(UNIX_AMD64_ABI)
4393     NYI_AMD64("fgMorphMultiregStructArgs (UNIX ABI)");
4394 #else
4395 #endif
4396     assert("Logic error: no MultiregStructArgs for Windows X64 ABI");
4397 #endif
4398
4399     for (args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
4400     {
4401         // For late arguments the arg tree that is overridden is in the gtCallLateArgs list. 
4402         // For such late args the gtCallArgList contains the setup arg node (evaluating the arg.) 
4403         // The tree from the gtCallLateArgs list is passed to the callee. The fgArgEntry node contains the mapping
4404         // between the nodes in both lists. If the arg is not a late arg, the fgArgEntry->node points to itself,
4405         // otherwise points to the list in the late args list.
4406         bool isLateArg = (args->gtOp.gtOp1->gtFlags & GTF_LATE_ARG) != 0;
4407         fgArgTabEntryPtr fgEntryPtr = gtArgEntryByNode(call, args->gtOp.gtOp1);
4408         assert(fgEntryPtr != nullptr);
4409         GenTreePtr argx = fgEntryPtr->node;
4410         GenTreePtr lateList = nullptr;
4411         GenTreePtr lateNode = nullptr;
4412
4413         if (isLateArg)
4414         {
4415             for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
4416             {
4417                 assert(list->IsList());
4418
4419                 GenTreePtr argNode = list->Current();
4420                 if (argx == argNode)
4421                 {
4422                     lateList = list;
4423                     lateNode = argNode;
4424                     break;
4425                 }
4426             }
4427             assert(lateList != nullptr && lateNode != nullptr);
4428         }
4429
4430         GenTreePtr arg = argx;
4431
4432         if (arg->TypeGet() == TYP_STRUCT)
4433         {
4434             foundStructArg = true;
4435
4436             arg = fgMorphMultiregStructArg(arg, fgEntryPtr);
4437
4438             // Did we replace 'argx' with a new tree?
4439             if (arg != argx)
4440             {
4441                 fgEntryPtr->node = arg;   // Record the new value for the arg in the fgEntryPtr->node
4442
4443                 // link the new arg node into either the late arg list or the gtCallArgs list
4444                 if (isLateArg)
4445                 {
4446                     lateList->gtOp.gtOp1 = arg;
4447                 }
4448                 else
4449                 {
4450                     args->gtOp.gtOp1 = arg;
4451                 }
4452             }
4453         }
4454     }
4455
4456     // We should only call this method when we actually have one or more multireg struct args
4457     assert(foundStructArg);
4458
4459     // Update the flags
4460     call->gtFlags |= (flagsSummary & GTF_ALL_EFFECT);
4461 }
4462
4463
4464 //-----------------------------------------------------------------------------
4465 // fgMorphMultiregStructArg:  Given a multireg TYP_STRUCT arg from a call argument list
4466 //   Morph the argument into a set of GT_LIST nodes.
4467 //
4468 // Arguments:
4469 //     arg        - A GenTree node containing a TYP_STRUCT arg that 
4470 //                  is to be passed in multiple registers
4471 //     fgEntryPtr - the fgArgTabEntry information for the current 'arg'
4472 //
4473 // Notes:
4474 //    arg must be a GT_OBJ or GT_LCL_VAR or GT_LCL_FLD of TYP_STRUCT that is suitable
4475 //    for passing in multiple registers.
4476 //    If arg is a LclVar we check if it is struct promoted and has the right number of fields
4477 //    and if they are at the appropriate offsets we will use the struct promted fields
4478 //    in the GT_LIST nodes that we create.
4479 //    If we have a GT_LCL_VAR that isn't struct promoted or doesn't meet the requirements
4480 //    we will use a set of GT_LCL_FLDs nodes to access the various portions of the struct
4481 //    this also forces the struct to be stack allocated into the local frame.
4482 //    For the GT_OBJ case will clone the address expression and generate two (or more)
4483 //    indirections.
4484 //    Currently the implementation only handles ARM64 and will NYI for other architectures.
4485 //
4486 GenTreePtr    Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr)
4487 {
4488     assert(arg->TypeGet() == TYP_STRUCT);
4489
4490 #ifndef _TARGET_ARM64_
4491     NYI("fgMorphMultiregStructArg requires implementation for this target");
4492 #endif
4493
4494 #if FEATURE_MULTIREG_ARGS
4495     // Examine 'arg' and setup argValue objClass and structSize
4496     //
4497     CORINFO_CLASS_HANDLE objClass   = NO_CLASS_HANDLE;
4498     GenTreePtr           argValue   = arg;   // normally argValue will be arg, but see right below
4499     unsigned             structSize = 0;
4500
4501     if (arg->OperGet() == GT_OBJ)
4502     {
4503         GenTreeObj*  argObj = arg->AsObj();
4504         objClass   = argObj->gtClass;
4505         structSize = info.compCompHnd->getClassSize(objClass);
4506
4507         // If we have a GT_OBJ of a GT_ADDR then we set argValue to the child node of the GT_ADDR
4508         //
4509         if (argObj->gtOp1->OperGet() == GT_ADDR)
4510         {
4511             argValue = argObj->gtOp1->gtOp.gtOp1;
4512         }
4513     }
4514     else if (arg->OperGet() == GT_LCL_VAR)
4515     {
4516         GenTreeLclVarCommon* varNode = arg->AsLclVarCommon();
4517         unsigned varNum = varNode->gtLclNum;
4518         assert(varNum < lvaCount);
4519         LclVarDsc* varDsc = &lvaTable[varNum];
4520
4521         objClass   = lvaGetStruct(varNum);
4522         structSize = varDsc->lvExactSize;
4523     }
4524     noway_assert(objClass != nullptr);
4525
4526     var_types  hfaType    = TYP_UNDEF;
4527     var_types  elemType   = TYP_UNDEF;
4528     unsigned   elemCount  = 0;
4529     unsigned   elemSize   = 0;
4530     var_types  type[MAX_ARG_REG_COUNT] = {};   // TYP_UNDEF = 0
4531
4532     hfaType = GetHfaType(objClass);   // set to float or double if it is an HFA, otherwise TYP_UNDEF
4533     if (varTypeIsFloating(hfaType))
4534     {
4535         elemType = hfaType;
4536         elemSize = genTypeSize(elemType);
4537         elemCount = structSize / elemSize;
4538         assert(elemSize*elemCount == structSize);
4539         for (unsigned inx = 0; inx<elemCount; inx++)
4540         {
4541             type[inx] = elemType;
4542         }
4543     }
4544     else
4545     {
4546         assert(structSize <= 2 * TARGET_POINTER_SIZE);
4547         BYTE gcPtrs[2] = { TYPE_GC_NONE, TYPE_GC_NONE };
4548         info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]);
4549         elemCount = 2;
4550         type[0] = getJitGCType(gcPtrs[0]);
4551         type[1] = getJitGCType(gcPtrs[1]);
4552
4553         if ((argValue->OperGet() == GT_LCL_FLD) ||
4554             (argValue->OperGet() == GT_LCL_VAR))
4555         {
4556             // We can safely widen this to 16 bytes since we are loading from 
4557             // a GT_LCL_VAR or a GT_LCL_FLD which is properly padded and 
4558             // lives in the stack frame or will be a promoted field.
4559             //
4560             elemSize = TARGET_POINTER_SIZE;
4561             structSize = 2 * TARGET_POINTER_SIZE;
4562         }
4563         else // we must have a GT_OBJ
4564         {
4565             assert(argValue->OperGet() == GT_OBJ);
4566
4567             // We need to load the struct from an arbitrary address
4568             // and we can't read past the end of the structSize
4569             // We adjust the second load type here
4570             // 
4571             if (structSize < 2 * TARGET_POINTER_SIZE)
4572             {
4573                 switch (structSize - TARGET_POINTER_SIZE) {
4574                 case 1:
4575                     type[1] = TYP_BYTE;
4576                     break;
4577                 case 2:
4578                     type[1] = TYP_SHORT;
4579                     break;
4580                 case 4:
4581                     type[1] = TYP_INT;
4582                     break;
4583                 default:
4584                     noway_assert(!"NYI: odd sized struct in fgMorphMultiregStructArg");
4585                     break;
4586                 }
4587             }
4588         }      
4589     }
4590     // We should still have a TYP_STRUCT
4591     assert(argValue->TypeGet() == TYP_STRUCT);
4592
4593     GenTreeArgList*  newArg = nullptr;
4594
4595     // Are we passing a struct LclVar?
4596     //
4597     if (argValue->OperGet() == GT_LCL_VAR)
4598     {
4599         GenTreeLclVarCommon* varNode = argValue->AsLclVarCommon();
4600         unsigned   varNum = varNode->gtLclNum;
4601         assert(varNum < lvaCount);
4602         LclVarDsc* varDsc = &lvaTable[varNum];
4603
4604         // At this point any TYP_STRUCT LclVar must be a 16-byte struct
4605         // or an HFA struct, both which are passed by value.
4606         //
4607         assert((varDsc->lvSize() == 2*TARGET_POINTER_SIZE) || varDsc->lvIsHfa());
4608
4609         varDsc->lvIsMultiRegArgOrRet = true;
4610
4611 #ifdef DEBUG
4612         if (verbose)
4613         {
4614             JITDUMP("Multireg struct argument V%02u : ");
4615             fgEntryPtr->Dump();
4616         }
4617 #endif // DEBUG
4618
4619         // This local variable must match the layout of the 'objClass' type exactly
4620         if (varDsc->lvIsHfa())
4621         {
4622             // We have a HFA struct
4623             noway_assert(elemType == (varDsc->lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE));
4624             noway_assert(elemSize == genTypeSize(elemType));
4625             noway_assert(elemCount == (varDsc->lvExactSize / elemSize));
4626             noway_assert(elemSize*elemCount == varDsc->lvExactSize);
4627
4628             for (unsigned inx = 0; (inx < elemCount); inx++)
4629             {
4630                 noway_assert(type[inx] == elemType);
4631             }
4632         }
4633         else
4634         {
4635             // We must have a 16-byte struct (non-HFA)
4636             noway_assert(elemCount == 2);
4637
4638             for (unsigned inx = 0; inx < elemCount; inx++)
4639             {
4640                 CorInfoGCType currentGcLayoutType = (CorInfoGCType)varDsc->lvGcLayout[inx];
4641
4642                 // We setup the type[inx] value above using the GC info from 'objClass'
4643                 // This GT_LCL_VAR must have the same GC layout info
4644                 // 
4645                 if (currentGcLayoutType != TYPE_GC_NONE)
4646                 {
4647                     noway_assert(type[inx] == getJitGCType((BYTE)currentGcLayoutType));
4648                 }
4649                 else
4650                 {
4651                     // We may have use a small type when we setup the type[inx] values above 
4652                     // We can safely widen this to TYP_I_IMPL 
4653                     type[inx] = TYP_I_IMPL;
4654                 }
4655             }
4656         }
4657
4658         // Is this LclVar a promoted struct with exactly 2 fields?
4659         // TODO-ARM64-CQ: Support struct promoted HFA types here
4660         if (varDsc->lvPromoted && (varDsc->lvFieldCnt == 2))
4661         {
4662             // See if we have two promoted fields that start at offset 0 and 8?
4663             unsigned loVarNum = lvaGetFieldLocal(varDsc, 0);
4664             unsigned hiVarNum = lvaGetFieldLocal(varDsc, TARGET_POINTER_SIZE);
4665
4666             // Did we find the promoted fields at the necessary offsets?
4667             if ((loVarNum != BAD_VAR_NUM) && (hiVarNum != BAD_VAR_NUM))
4668             {
4669                 LclVarDsc* loVarDsc = &lvaTable[loVarNum];
4670                 LclVarDsc* hiVarDsc = &lvaTable[hiVarNum];
4671
4672                 var_types  loType = loVarDsc->lvType;
4673                 var_types  hiType = hiVarDsc->lvType;
4674
4675                 if (varTypeIsFloating(loType) || varTypeIsFloating(hiType))
4676                 {
4677                     // TODO-LSRA - It currently doesn't support the passing of floating point LCL_VARS in the integer registers
4678                     // So for now we will use GT_LCLFLD's to pass this struct (it won't be enregistered)
4679                     //
4680                     JITDUMP("Multireg struct V%02u will be passed using GT_LCLFLD because it has float fields.\n", varNum);
4681                     //
4682                     // we call lvaSetVarDoNotEnregister and do the proper transformation below.
4683                     //
4684                 }
4685                 else
4686                 {
4687                     // We can use the struct promoted field as the two arguments
4688
4689                     GenTreePtr loLclVar = gtNewLclvNode(loVarNum, loType, loVarNum);
4690                     GenTreePtr hiLclVar = gtNewLclvNode(hiVarNum, hiType, hiVarNum);
4691
4692                     // Create a new tree for 'arg'
4693                     //    replace the existing LDOBJ(ADDR(LCLVAR)) 
4694                     //    with a LIST(LCLVAR-LO, LIST(LCLVAR-HI, nullptr))
4695                     //
4696                     newArg = gtNewListNode(loLclVar, gtNewArgList(hiLclVar));
4697                 }
4698             }
4699         }
4700         else
4701         {
4702             //
4703             // We will create a list of GT_LCL_FLDs nodes to pass this struct
4704             //
4705             lvaSetVarDoNotEnregister(varNum DEBUG_ARG(DNER_LocalField));
4706         }
4707     }
4708
4709     // If we didn't set newarg to a new List Node tree
4710     //
4711     if (newArg == nullptr)
4712     {
4713         if (fgEntryPtr->regNum == REG_STK)
4714         {
4715             // We leave this stack passed argument alone
4716             return arg;
4717         }
4718
4719         // Are we passing a GT_LCL_FLD (or a GT_LCL_VAR that was not struct promoted )
4720         // A GT_LCL_FLD could also contain a 16-byte struct or HFA struct inside it?
4721         //
4722         if ((argValue->OperGet() == GT_LCL_FLD) || (argValue->OperGet() == GT_LCL_VAR))
4723         {
4724             GenTreeLclVarCommon* varNode = argValue->AsLclVarCommon();
4725             unsigned   varNum = varNode->gtLclNum;
4726             assert(varNum < lvaCount);
4727             LclVarDsc* varDsc = &lvaTable[varNum];
4728
4729             unsigned baseOffset = (argValue->OperGet() == GT_LCL_FLD) ? argValue->gtLclFld.gtLclOffs : 0;
4730             unsigned lastOffset = baseOffset + (elemCount * elemSize);
4731
4732             // The allocated size of our LocalVar must be at least as big as lastOffset
4733             assert(varDsc->lvSize() >= lastOffset);
4734
4735             if (varDsc->lvStructGcCount > 0)
4736             {
4737                 // alignment of the baseOffset is required
4738                 noway_assert((baseOffset % TARGET_POINTER_SIZE) == 0);
4739                 noway_assert(elemSize == TARGET_POINTER_SIZE);
4740                 unsigned baseIndex = baseOffset / TARGET_POINTER_SIZE;
4741                 const BYTE * gcPtrs = varDsc->lvGcLayout;  // Get the GC layout for the local variable
4742                 for (unsigned inx = 0; (inx < elemCount); inx++)
4743                 {
4744                     // The GC information must match what we setup using 'objClass'
4745                     noway_assert(type[inx] == getJitGCType(gcPtrs[baseIndex + inx]));
4746                 }
4747             }
4748             else //  this varDsc contains no GC pointers
4749             {
4750                 for (unsigned inx = 0; inx<elemCount; inx++)
4751                 {
4752                     // The GC information must match what we setup using 'objClass'               
4753                     noway_assert(!varTypeIsGC(type[inx]));
4754                 }
4755             }
4756
4757             //
4758             // We create a list of GT_LCL_FLDs nodes to pass this struct
4759             //
4760             lvaSetVarDoNotEnregister(varNum DEBUG_ARG(DNER_LocalField));
4761
4762             // Start building our list from the last element
4763             unsigned offset = lastOffset;
4764             unsigned inx = elemCount;
4765
4766             // Create a new tree for 'arg'
4767             //    replace the existing LDOBJ(ADDR(LCLVAR)) 
4768             //    with a LIST(LCLFLD-LO, LIST(LCLFLD-HI, nullptr) ...)
4769             //
4770             while (inx > 0)
4771             {
4772                 inx--;
4773                 offset -= elemSize;
4774                 GenTreePtr nextLclFld = gtNewLclFldNode(varNum, type[inx], offset);
4775                 if (newArg == nullptr)
4776                 {
4777                     newArg = gtNewArgList(nextLclFld);
4778                 }
4779                 else
4780                 {
4781                     newArg = gtNewListNode(nextLclFld, newArg);
4782                 }
4783             }
4784         }
4785         // Are we passing a GT_OBJ struct?
4786         //
4787         else if (argValue->OperGet() == GT_OBJ)
4788         {
4789             GenTreeObj*  argObj   = argValue->AsObj();
4790             GenTreePtr   baseAddr = argObj->gtOp1;
4791             var_types    addrType = baseAddr->TypeGet();
4792
4793             // Create a new tree for 'arg'
4794             //    replace the existing LDOBJ(EXPR) 
4795             //    with a LIST(IND(EXPR), LIST(IND(EXPR+8), nullptr) ...)
4796             //
4797
4798             // Start building our list from the last element
4799             unsigned offset = structSize;
4800             unsigned inx = elemCount;
4801             while (inx > 0)
4802             {
4803                 inx--;
4804                 elemSize = genTypeSize(type[inx]);
4805                 offset -= elemSize;
4806                 GenTreePtr  curAddr = baseAddr;
4807                 if (offset != 0)
4808                 {
4809                     GenTreePtr  baseAddrDup = gtCloneExpr(baseAddr);
4810                     noway_assert(baseAddrDup != nullptr);
4811                     curAddr = gtNewOperNode(GT_ADD, addrType, baseAddrDup, gtNewIconNode(offset, TYP_I_IMPL));
4812                 }
4813                 else
4814                 {
4815                     curAddr = baseAddr;
4816                 }
4817                 GenTreePtr curItem = gtNewOperNode(GT_IND, type[inx], curAddr);
4818                 if (newArg == nullptr)
4819                 {
4820                     newArg = gtNewArgList(curItem);
4821                 }
4822                 else
4823                 {
4824                     newArg = gtNewListNode(curItem, newArg);
4825                 }
4826             }
4827         }
4828     }
4829
4830     // If we reach here we should have set newArg to something 
4831     if (newArg == nullptr)
4832     {
4833 #ifdef DEBUG
4834         gtDispTree(argValue);
4835 #endif
4836         assert(!"Missing case in fgMorphMultiregStructArg");
4837     }
4838
4839 #ifdef DEBUG
4840     if (verbose)
4841     {
4842         printf("fgMorphMultiregStructArg created tree:\n");
4843         gtDispTree(newArg);
4844     }
4845 #endif
4846
4847     arg = newArg;   // consider calling fgMorphTree(newArg);
4848
4849 #endif // FEATURE_MULTIREG_ARGS
4850
4851     return arg;
4852 }
4853
4854
4855 // Make a copy of a struct variable if necessary, to pass to a callee.
4856 // returns: tree that computes address of the outgoing arg
4857 void
4858 Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, 
4859                                       GenTree* args, 
4860                                       unsigned argIndex, 
4861                                       CORINFO_CLASS_HANDLE copyBlkClass
4862                                       FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr))
4863 {
4864     GenTree* argx = args->Current();
4865     noway_assert(argx->gtOper != GT_MKREFANY);
4866     // See if we need to insert a copy at all
4867     // Case 1: don't need a copy if it is the last use of a local.  We can't determine that all of the time
4868     // but if there is only one use and no loops, the use must be last.
4869     if (argx->gtOper == GT_OBJ)
4870     {
4871         GenTree* lcl = argx->gtOp.gtOp1;
4872         if (lcl->OperIsLocal())
4873         {
4874             unsigned varNum = lcl->AsLclVarCommon()->GetLclNum();
4875             if (lvaIsImplicitByRefLocal(varNum))
4876             {
4877                 LclVarDsc* varDsc = &lvaTable[varNum];
4878                 if (varDsc->lvRefCnt == 1 && !fgMightHaveLoop())
4879                 {
4880                     varDsc->lvRefCnt = 0;
4881                     args->gtOp.gtOp1 = lcl;
4882                     fgArgTabEntryPtr fp = Compiler::gtArgEntryByNode(call, argx);
4883                     fp->node = lcl;
4884
4885                     JITDUMP("did not have to make outgoing copy for V%2d", varNum);
4886                     varDsc->lvRefCnt = 0;
4887                     return;
4888                 }
4889                 else
4890                 {
4891                     varDsc->lvRefCnt = 0;
4892                 }
4893             }
4894         }
4895     }
4896
4897     if (fgOutgoingArgTemps == nullptr)
4898         fgOutgoingArgTemps = hashBv::Create(this);
4899
4900     unsigned   tmp = 0;
4901     bool found = false;
4902             
4903     // Attempt to find a local we have already used for an outgoing struct and reuse it.
4904     // We do not reuse within a statement.
4905     if (!opts.MinOpts())
4906     {
4907         indexType lclNum;
4908         FOREACH_HBV_BIT_SET(lclNum, fgOutgoingArgTemps)
4909         {
4910             LclVarDsc* varDsc = &lvaTable[lclNum];
4911             if (typeInfo::AreEquivalent(varDsc->lvVerTypeInfo, typeInfo(TI_STRUCT, copyBlkClass))
4912                 && !fgCurrentlyInUseArgTemps->testBit(lclNum))
4913             {
4914                 tmp = (unsigned) lclNum;
4915                 found = true;
4916                 JITDUMP("reusing outgoing struct arg");
4917                 break;
4918             }
4919         }
4920         NEXT_HBV_BIT_SET;
4921     }
4922
4923     // Create the CopyBlk tree and insert it.
4924     if (!found)
4925     {
4926         // Get a new temp
4927         // Here We don't need unsafe value cls check, since the addr of this temp is used only in copyblk.
4928         tmp = lvaGrabTemp(true DEBUGARG("by-value struct argument"));
4929         lvaSetStruct(tmp, copyBlkClass, false);
4930         fgOutgoingArgTemps->setBit(tmp);
4931     }
4932
4933     fgCurrentlyInUseArgTemps->setBit(tmp);
4934
4935     // TYP_SIMD structs should not be enregistered, since ABI requires it to be
4936     // allocated on stack and address of it needs to be passed.
4937     if (lclVarIsSIMDType(tmp))
4938     {
4939         lvaSetVarDoNotEnregister(tmp DEBUGARG(DNER_IsStruct));
4940     }
4941
4942     // Create a reference to the temp
4943     GenTreePtr  dest = gtNewLclvNode(tmp, lvaTable[tmp].lvType);
4944     dest->gtFlags |= (GTF_DONT_CSE | GTF_VAR_DEF);  // This is a def of the local, "entire" by construction.
4945     dest = gtNewOperNode(GT_ADDR, TYP_BYREF, dest);
4946     lvaTable[tmp].incRefCnts(compCurBB->getBBWeight(this), this);
4947
4948     GenTreePtr  src;
4949     if (argx->gtOper == GT_OBJ)
4950     {
4951         src = argx->gtOp.gtOp1;
4952     }
4953     else
4954     {
4955         argx->gtFlags |= GTF_DONT_CSE;
4956         src = gtNewOperNode(GT_ADDR, TYP_BYREF, argx);
4957     }
4958
4959     // Copy the valuetype to the temp
4960     GenTreePtr copyBlk = gtNewCpObjNode(dest, src, copyBlkClass, false);
4961     copyBlk = fgMorphCopyBlock(copyBlk);
4962
4963 #if FEATURE_FIXED_OUT_ARGS
4964
4965     // Do the copy early, and evalute the temp later (see EvalArgsToTemps)
4966     // When on Unix create LCL_FLD for structs passed in more than one registers. See fgMakeTmpArgNode
4967     GenTreePtr arg = copyBlk;
4968
4969 #else // FEATURE_FIXED_OUT_ARGS
4970
4971     // Structs are always on the stack, and thus never need temps
4972     // so we have to put the copy and temp all into one expression
4973     GenTreePtr arg = fgMakeTmpArgNode(
4974         tmp
4975         FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(structDescPtr->passedInRegisters));
4976
4977     // Change the expression to "(tmp=val),tmp"
4978     arg = gtNewOperNode(GT_COMMA, arg->TypeGet(), copyBlk, arg);
4979
4980 #endif // FEATURE_FIXED_OUT_ARGS
4981
4982     args->gtOp.gtOp1 = arg;
4983     call->fgArgInfo->EvalToTmp(argIndex, tmp, arg);
4984
4985     return;
4986 }
4987
4988 #ifdef _TARGET_ARM_
4989 // See declaration for specification comment.
4990 void                Compiler::fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc,
4991                                                                   unsigned   firstArgRegNum,
4992                                                                   regMaskTP* pArgSkippedRegMask)
4993 {
4994     assert(varDsc->lvPromoted);
4995     // There's no way to do these calculations without breaking abstraction and assuming that
4996     // integer register arguments are consecutive ints.  They are on ARM.
4997
4998     // To start, figure out what register contains the last byte of the first argument.
4999     LclVarDsc* firstFldVarDsc = &lvaTable[varDsc->lvFieldLclStart];
5000     unsigned lastFldRegOfLastByte = (firstFldVarDsc->lvFldOffset + firstFldVarDsc->lvExactSize - 1) / TARGET_POINTER_SIZE;;
5001
5002     // Now we're keeping track of the register that the last field ended in; see what registers
5003     // subsequent fields start in, and whether any are skipped.
5004     // (We assume here the invariant that the fields are sorted in offset order.)
5005     for (unsigned fldVarOffset = 1; fldVarOffset < varDsc->lvFieldCnt; fldVarOffset++)
5006     {
5007         unsigned fldVarNum = varDsc->lvFieldLclStart + fldVarOffset;
5008         LclVarDsc* fldVarDsc = &lvaTable[fldVarNum];
5009         unsigned fldRegOffset = fldVarDsc->lvFldOffset / TARGET_POINTER_SIZE;
5010         assert(fldRegOffset >= lastFldRegOfLastByte); // Assuming sorted fields.
5011         // This loop should enumerate the offsets of any registers skipped.
5012         // Find what reg contains the last byte:
5013         // And start at the first register after that.  If that isn't the first reg of the current
5014         for (unsigned skippedRegOffsets = lastFldRegOfLastByte + 1; skippedRegOffsets < fldRegOffset; skippedRegOffsets++)
5015         {
5016             // If the register number would not be an arg reg, we're done.
5017             if (firstArgRegNum + skippedRegOffsets >= MAX_REG_ARG) return;
5018             *pArgSkippedRegMask |= genRegMask(regNumber(firstArgRegNum + skippedRegOffsets));
5019         }
5020         lastFldRegOfLastByte = (fldVarDsc->lvFldOffset + fldVarDsc->lvExactSize - 1) / TARGET_POINTER_SIZE;
5021     }
5022 }
5023
5024 #endif // _TARGET_ARM_
5025
5026
5027 /*****************************************************************************
5028  *
5029  *  The companion to impFixupCallStructReturn.  Now that the importer is done
5030  *  and we no longer care as much about the declared return type, change to
5031  *  precomputed native return type (at least for architectures that don't
5032  *  always use return buffers for structs).
5033  *
5034  */
5035 void                Compiler::fgFixupStructReturn(GenTreePtr     callNode)
5036 {
5037     GenTreeCall* call = callNode->AsCall();
5038     bool callHasRetBuffArg = call->HasRetBufArg();
5039
5040     if (!callHasRetBuffArg && varTypeIsStruct(call))
5041     {
5042 #ifdef FEATURE_HFA
5043         if (call->gtCall.IsVarargs() || !IsHfa(call))
5044 #endif 
5045         {
5046             // Now that we are past the importer, re-type this node so the register predictor does
5047             // the right thing
5048             call->gtType = genActualType((var_types)call->gtCall.gtReturnType);
5049         }
5050     }
5051
5052 #ifdef FEATURE_HFA
5053     // Either we don't have a struct now or if struct, then it is HFA returned in regs.
5054     assert(!varTypeIsStruct(call) || (IsHfa(call) && !callHasRetBuffArg));
5055 #elif defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
5056     // Either we don't have a struct now or if struct, then it is a struct returned in regs or in return buffer.
5057     assert(!varTypeIsStruct(call) || call->HasMultiRegRetVal() || callHasRetBuffArg);
5058 #else 
5059     // No more struct returns
5060     assert(call->TypeGet() != TYP_STRUCT);
5061 #endif
5062
5063 #if !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
5064     // If it was a struct return, it has been transformed into a call
5065     // with a return buffer (that returns TYP_VOID) or into a return
5066     // of a primitive/enregisterable type
5067     assert(!callHasRetBuffArg || (call->TypeGet() == TYP_VOID));
5068 #endif 
5069 }
5070
5071
5072 /*****************************************************************************
5073  *
5074  *  A little helper used to rearrange nested commutative operations. The
5075  *  effect is that nested associative, commutative operations are transformed
5076  *  into a 'left-deep' tree, i.e. into something like this:
5077  *
5078  *      (((a op b) op c) op d) op...
5079  */
5080
5081 #if REARRANGE_ADDS
5082
5083 void                Compiler::fgMoveOpsLeft(GenTreePtr tree)
5084 {
5085     GenTreePtr op1;
5086     GenTreePtr op2;
5087     genTreeOps oper;
5088
5089     do
5090     {
5091         op1  = tree->gtOp.gtOp1;
5092         op2  = tree->gtOp.gtOp2;
5093         oper = tree->OperGet();
5094
5095         noway_assert(GenTree::OperIsCommutative(oper));
5096         noway_assert(oper == GT_ADD || oper == GT_XOR || oper == GT_OR ||
5097                      oper == GT_AND || oper == GT_MUL);
5098         noway_assert(!varTypeIsFloating(tree->TypeGet()) || !opts.genFPorder);
5099         noway_assert(oper == op2->gtOper);
5100
5101         // Commutativity doesn't hold if overflow checks are needed
5102
5103         if (tree->gtOverflowEx() || op2->gtOverflowEx())
5104             return;
5105
5106         if (gtIsActiveCSE_Candidate(op2))
5107         {
5108             // If we have marked op2 as a CSE candidate,
5109             // we can't perform a commutative reordering
5110             // because any value numbers that we computed for op2
5111             // will be incorrect after performing a commutative reordering
5112             //
5113             return;
5114         }
5115
5116         if (oper == GT_MUL && (op2->gtFlags & GTF_MUL_64RSLT))
5117             return;
5118
5119         // Check for GTF_ADDRMODE_NO_CSE flag on add/mul Binary Operators
5120         if (    ((oper == GT_ADD) || (oper == GT_MUL))
5121              && ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)               )
5122         {
5123             return;
5124         }
5125
5126         if ( (tree->gtFlags | op2->gtFlags) & GTF_BOOLEAN )
5127         {
5128             // We could deal with this, but we were always broken and just hit the assert
5129             // below regarding flags, which means it's not frequent, so will just bail out.
5130             // See #195514
5131             return;
5132         }
5133
5134         noway_assert(!tree->gtOverflowEx() && !op2->gtOverflowEx());
5135
5136         GenTreePtr      ad1 = op2->gtOp.gtOp1;
5137         GenTreePtr      ad2 = op2->gtOp.gtOp2;
5138
5139         // Compiler::optOptimizeBools() can create GT_OR of two GC pointers yeilding a GT_INT
5140         // We can not reorder such GT_OR trees
5141         //
5142         if (varTypeIsGC(ad1->TypeGet()) != varTypeIsGC(op2->TypeGet()))
5143             break;
5144
5145         /* Change "(x op (y op z))" to "(x op y) op z" */
5146         /* ie.    "(op1 op (ad1 op ad2))" to "(op1 op ad1) op ad2" */
5147
5148         GenTreePtr new_op1 = op2;
5149
5150         new_op1->gtOp.gtOp1     = op1;
5151         new_op1->gtOp.gtOp2     = ad1;
5152         
5153         /* Change the flags. */
5154
5155         // Make sure we arent throwing away any flags
5156         noway_assert((new_op1->gtFlags & ~(
5157             GTF_MAKE_CSE |
5158             GTF_DONT_CSE | // It is ok that new_op1->gtFlags contains GTF_DONT_CSE flag.
5159             GTF_REVERSE_OPS | // The reverse ops flag also can be set, it will be re-calculated 
5160             GTF_NODE_MASK|GTF_ALL_EFFECT|GTF_UNSIGNED)) == 0);
5161
5162         new_op1->gtFlags = (new_op1->gtFlags & (GTF_NODE_MASK | GTF_DONT_CSE)) | // Make sure we propagate GTF_DONT_CSE flag.
5163                            (op1->gtFlags & GTF_ALL_EFFECT)  |
5164                            (ad1->gtFlags & GTF_ALL_EFFECT);
5165
5166         /* Retype new_op1 if it has not/become a GC ptr. */
5167
5168         if      (varTypeIsGC(op1->TypeGet()))
5169         {
5170             noway_assert((varTypeIsGC(tree->TypeGet()) && op2->TypeGet() == TYP_I_IMPL && oper == GT_ADD) || // byref(ref + (int+int))
5171                          (varTypeIsI (tree->TypeGet()) && op2->TypeGet() == TYP_I_IMPL && oper == GT_OR)); // int(gcref | int(gcref|intval))
5172
5173             new_op1->gtType = tree->gtType;
5174         }
5175         else if (varTypeIsGC(ad2->TypeGet()))
5176         {
5177             // Neither ad1 nor op1 are GC. So new_op1 isnt either
5178             noway_assert(op1->gtType == TYP_I_IMPL && ad1->gtType == TYP_I_IMPL);
5179             new_op1->gtType = TYP_I_IMPL;
5180         }
5181
5182         // If new_op1 is a new expression. Assign it a new unique value number.
5183         // vnStore is null before the ValueNumber phase has run
5184         if (vnStore != nullptr)
5185         {
5186             // We can only keep the old value number on new_op1 if both op1 and ad2 
5187             // have the same non-NoVN value numbers. Since op is commutative, comparing 
5188             // only ad2 and op1 is enough.
5189             if ((op1->gtVNPair.GetLiberal() == ValueNumStore::NoVN) ||
5190                 (ad2->gtVNPair.GetLiberal() == ValueNumStore::NoVN) ||
5191                 (ad2->gtVNPair.GetLiberal() != op1->gtVNPair.GetLiberal()))
5192             {
5193                 new_op1->gtVNPair.SetBoth(vnStore->VNForExpr(new_op1->TypeGet()));
5194             }
5195         }
5196
5197         tree->gtOp.gtOp1 = new_op1;
5198         tree->gtOp.gtOp2 = ad2;
5199
5200         /* If 'new_op1' is now the same nested op, process it recursively */
5201
5202         if  ((ad1->gtOper == oper) && !ad1->gtOverflowEx())
5203             fgMoveOpsLeft(new_op1);
5204
5205         /* If   'ad2'   is now the same nested op, process it
5206          * Instead of recursion, we set up op1 and op2 for the next loop.
5207          */
5208
5209         op1 = new_op1;
5210         op2 = ad2;
5211     }
5212     while ((op2->gtOper == oper) && !op2->gtOverflowEx());
5213
5214     return;
5215 }
5216
5217 #endif
5218
5219 /*****************************************************************************/
5220
5221 void            Compiler::fgSetRngChkTarget(GenTreePtr  tree,
5222                                             bool        delay)
5223 {
5224     GenTreeBoundsChk* bndsChk = nullptr;
5225     SpecialCodeKind kind = SCK_RNGCHK_FAIL;
5226
5227 #ifdef FEATURE_SIMD
5228     if ((tree->gtOper == GT_ARR_BOUNDS_CHECK) || (tree->gtOper == GT_SIMD_CHK))
5229 #else // FEATURE_SIMD
5230     if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
5231 #endif // FEATURE_SIMD
5232     {
5233         bndsChk = tree->AsBoundsChk();
5234         kind = tree->gtBoundsChk.gtThrowKind;
5235     }
5236     else
5237     {
5238         noway_assert((tree->gtOper == GT_ARR_ELEM) || (tree->gtOper == GT_ARR_INDEX));
5239     }
5240
5241 #ifdef _TARGET_X86_
5242     unsigned callStkDepth = fgPtrArgCntCur;
5243 #else
5244     // only x86 pushes args
5245     const unsigned callStkDepth = 0;
5246 #endif
5247
5248     if  (opts.MinOpts())
5249     {
5250         delay = false;
5251
5252         // we need to initialize this field
5253         if (fgGlobalMorph && bndsChk != nullptr)
5254         {
5255             bndsChk->gtStkDepth = callStkDepth;
5256         }
5257     }
5258
5259     if (!opts.compDbgCode)
5260     {
5261         if (delay || compIsForInlining())
5262         {
5263             /*  We delay this until after loop-oriented range check
5264                 analysis. For now we merely store the current stack
5265                 level in the tree node.
5266              */
5267             if (bndsChk != nullptr)
5268             {
5269                 noway_assert(!bndsChk->gtIndRngFailBB || previousCompletedPhase >= PHASE_OPTIMIZE_LOOPS);
5270                 bndsChk->gtStkDepth = callStkDepth;
5271             }
5272         }
5273         else
5274         {
5275             /* Create/find the appropriate "range-fail" label */
5276
5277             // fgPtrArgCntCur is only valid for global morph or if we walk full stmt.
5278             noway_assert((bndsChk != nullptr) || fgGlobalMorph);
5279
5280             unsigned stkDepth = (bndsChk != nullptr) ? bndsChk->gtStkDepth
5281                                                   : callStkDepth;
5282
5283             BasicBlock * rngErrBlk = fgRngChkTarget(compCurBB, stkDepth, kind);
5284
5285             /* Add the label to the indirection node */
5286
5287             if (bndsChk != nullptr)
5288             {
5289                 bndsChk->gtIndRngFailBB = gtNewCodeRef(rngErrBlk);
5290             }
5291         }
5292     }
5293 }
5294
5295 /*****************************************************************************
5296  *
5297  *  Expand a GT_INDEX node and fully morph the child operands
5298  *
5299  *  The orginal GT_INDEX node is bashed into the GT_IND node that accesses
5300  *  the array element.  We expand the GT_INDEX node into a larger tree that
5301  *  evaluates the array base and index.  The simplest expansion is a GT_COMMA
5302  *  with a GT_ARR_BOUND_CHK and a GT_IND with a GTF_INX_RNGCHK flag.
5303  *  For complex array or index expressions one or more GT_COMMA assignments
5304  *  are inserted so that we only evaluate the array or index expressions once.
5305  *
5306  *  The fully expanded tree is then morphed.  This causes gtFoldExpr to
5307  *  perform local constant prop and reorder the constants in the tree and
5308  *  fold them.
5309  *
5310  *  We then parse the resulting array element expression in order to locate
5311  *  and label the constants and variables that occur in the tree.
5312  */
5313
5314 const int MAX_ARR_COMPLEXITY = 4;
5315 const int MAX_INDEX_COMPLEXITY = 4;
5316
5317 GenTreePtr          Compiler::fgMorphArrayIndex(GenTreePtr tree)
5318 {
5319     noway_assert(tree->gtOper == GT_INDEX);
5320     GenTreeIndex* asIndex = tree->AsIndex();
5321
5322     var_types  elemTyp  = tree->TypeGet();
5323     unsigned   elemSize = tree->gtIndex.gtIndElemSize;
5324     CORINFO_CLASS_HANDLE elemStructType = tree->gtIndex.gtStructElemClass;
5325
5326     noway_assert(elemTyp != TYP_STRUCT || elemStructType != nullptr);
5327
5328 #ifdef FEATURE_SIMD
5329     if (featureSIMD && varTypeIsStruct(elemTyp) && elemSize <= getSIMDVectorRegisterByteLength())
5330     {
5331         // If this is a SIMD type, this is the point at which we lose the type information,
5332         // so we need to set the correct type on the GT_IND.
5333         // (We don't care about the base type here, so we only check, but don't retain, the return value).
5334         unsigned simdElemSize = 0;
5335         if (getBaseTypeAndSizeOfSIMDType(elemStructType, &simdElemSize) != TYP_UNKNOWN)
5336         {
5337             assert(simdElemSize == elemSize);
5338             elemTyp = getSIMDTypeForSize(elemSize);
5339             // This is the new type of the node.
5340             tree->gtType = elemTyp;
5341             // Now set elemStructType to null so that we don't confuse value numbering.
5342             elemStructType = nullptr;
5343         }
5344     }
5345 #endif // FEATURE_SIMD
5346
5347     GenTreePtr arrRef   = asIndex->Arr();
5348     GenTreePtr index    = asIndex->Index();
5349
5350     // Set up the the array length's offset into lenOffs
5351     // And    the the first element's offset into elemOffs
5352     ssize_t  lenOffs;
5353     ssize_t  elemOffs;
5354     if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
5355     {
5356         lenOffs  = offsetof(CORINFO_String, stringLen);
5357         elemOffs = offsetof(CORINFO_String, chars);
5358         tree->gtFlags &= ~GTF_INX_STRING_LAYOUT;    // Clear this flag as it is used for GTF_IND_VOLATILE
5359     }
5360     else if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
5361     {
5362         lenOffs  = offsetof(CORINFO_RefArray, length);
5363         elemOffs = eeGetEEInfo()->offsetOfObjArrayData;
5364     }
5365     else // We have a standard array
5366     {
5367         lenOffs  = offsetof(CORINFO_Array, length);
5368         elemOffs = offsetof(CORINFO_Array, u1Elems);
5369     }
5370
5371     bool  chkd = ((tree->gtFlags & GTF_INX_RNGCHK) != 0);     // if false, range checking will be disabled
5372     bool  nCSE = ((tree->gtFlags & GTF_DONT_CSE  ) != 0);
5373
5374     GenTreePtr arrRefDefn = nullptr;    // non-NULL if we need to allocate a temp for the arrRef expression
5375     GenTreePtr indexDefn  = nullptr;    // non-NULL if we need to allocate a temp for the index expression
5376     GenTreePtr bndsChk    = nullptr;
5377
5378     // If we're doing range checking, introduce a GT_ARR_BOUNDS_CHECK node for the address.
5379     if (chkd)
5380     {
5381         GenTreePtr arrRef2 = nullptr;    // The second copy will be used in array address expression
5382         GenTreePtr index2  = nullptr;
5383
5384         // If the arrRef expression involves an assignment, a call or reads from global memory,
5385         // then we *must* allocate a temporary in which to "localize" those values,
5386         // to ensure that the same values are used in the bounds check and the actual
5387         // dereference.
5388         // Also we allocate the temporary when the arrRef is sufficiently complex/expensive.
5389         //
5390         if ((arrRef->gtFlags & (GTF_ASG|GTF_CALL|GTF_GLOB_REF)) || gtComplexityExceeds(&arrRef, MAX_ARR_COMPLEXITY))
5391         {
5392             unsigned arrRefTmpNum = lvaGrabTemp(true DEBUGARG("arr expr"));
5393             arrRefDefn = gtNewTempAssign(arrRefTmpNum, arrRef);
5394             arrRef     = gtNewLclvNode(arrRefTmpNum, arrRef->TypeGet());
5395             arrRef2    = gtNewLclvNode(arrRefTmpNum, arrRef->TypeGet());
5396         }
5397         else
5398         {
5399             arrRef2 = gtCloneExpr(arrRef);
5400             noway_assert(arrRef2 != nullptr);
5401         }
5402
5403         // If the index expression involves an assignment, a call or reads from global memory,
5404         // we *must* allocate a temporary in which to "localize" those values,
5405         // to ensure that the same values are used in the bounds check and the actual
5406         // dereference.
5407         // Also we allocate the temporary when the index is sufficiently complex/expensive.
5408         //
5409         if ((index->gtFlags & (GTF_ASG|GTF_CALL|GTF_GLOB_REF)) || gtComplexityExceeds(&index, MAX_ARR_COMPLEXITY))
5410         {
5411             unsigned indexTmpNum = lvaGrabTemp(true DEBUGARG("arr expr"));
5412             indexDefn = gtNewTempAssign(indexTmpNum, index);
5413             index     = gtNewLclvNode(indexTmpNum, index->TypeGet());
5414             index2    = gtNewLclvNode(indexTmpNum, index->TypeGet());
5415         }
5416         else
5417         {
5418             index2 = gtCloneExpr(index);
5419             noway_assert(index2 != nullptr);
5420         }
5421
5422         // Next introduce a GT_ARR_BOUNDS_CHECK node
5423         var_types bndsChkType = TYP_INT;  // By default, try to use 32-bit comparison for array bounds check.
5424
5425 #ifdef _TARGET_64BIT_
5426         // The CLI Spec allows an array to be indexed by either an int32 or a native int.  In the case
5427         // of a 64 bit architecture this means the array index can potentially be a TYP_LONG, so for this case, 
5428         // the comparison will have to be widen to 64 bits.
5429         if (index->TypeGet() == TYP_I_IMPL)
5430         {
5431             bndsChkType = TYP_I_IMPL;
5432         }
5433 #endif // _TARGET_64BIT_
5434
5435         GenTree* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(TYP_INT, arrRef, (int)lenOffs);
5436
5437         if (bndsChkType != TYP_INT)
5438         {
5439             arrLen = gtNewCastNode(bndsChkType, arrLen, bndsChkType);
5440         }
5441
5442         GenTreeBoundsChk* arrBndsChk    = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, index, SCK_RNGCHK_FAIL);
5443
5444         bndsChk = arrBndsChk;
5445
5446         // Make sure to increment ref-counts if already ref-counted.
5447         if (lvaLocalVarRefCounted)
5448         {
5449             lvaRecursiveIncRefCounts(index);
5450             lvaRecursiveIncRefCounts(arrRef);
5451         }
5452
5453         // Now we'll switch to using the second copies for arrRef and index
5454         // to compute the address expression
5455
5456         arrRef = arrRef2;
5457         index  = index2;
5458     }
5459
5460     // Create the "addr" which is "*(arrRef + ((index * elemSize) + elemOffs))"
5461
5462     GenTreePtr addr;
5463
5464     // Widen 'index' on 64-bit targets
5465 #ifdef _TARGET_64BIT_
5466     if (index->TypeGet() != TYP_I_IMPL)
5467     {
5468         if (index->OperGet() == GT_CNS_INT)
5469         {
5470             index->gtType = TYP_I_IMPL;
5471         }
5472         else
5473         {
5474             index = gtNewCastNode(TYP_I_IMPL, index, TYP_I_IMPL);
5475         }
5476     }
5477 #endif // _TARGET_64BIT_
5478
5479     /* Scale the index value if necessary */
5480     if  (elemSize > 1)
5481     {
5482         GenTreePtr size = gtNewIconNode(elemSize, TYP_I_IMPL);
5483
5484         // Fix 392756 WP7 Crossgen
5485         //
5486         // During codegen optGetArrayRefScaleAndIndex() makes the assumption that op2 of a GT_MUL node
5487         // is a constant and is not capable of handling CSE'ing the elemSize constant into a lclvar.
5488         // Hence to prevent the constant from becoming a CSE we mark it as NO_CSE.
5489         //
5490         size->gtFlags |= GTF_DONT_CSE;
5491
5492         /* Multiply by the array element size */
5493         addr = gtNewOperNode(GT_MUL, TYP_I_IMPL, index, size);
5494     }
5495     else
5496     {
5497         addr = index;
5498     }
5499
5500     /* Add the object ref to the element's offset */
5501
5502     addr = gtNewOperNode(GT_ADD, TYP_BYREF, arrRef, addr);
5503
5504     /* Add the first element's offset */
5505
5506     GenTreePtr cns = gtNewIconNode(elemOffs, TYP_I_IMPL);
5507
5508     addr = gtNewOperNode(GT_ADD, TYP_BYREF, addr, cns);
5509
5510 #if SMALL_TREE_NODES
5511     assert(tree->gtFlags & GTF_NODE_LARGE);
5512 #endif
5513
5514     // Change the orginal GT_INDEX node into a GT_IND node
5515     tree->SetOper(GT_IND);
5516
5517     // If the index node is a floating-point type, notify the compiler
5518     // we'll potentially use floating point registers at the time of codegen.
5519     if (varTypeIsFloating(tree->gtType))
5520     {
5521         this->compFloatingPointUsed = true;
5522     }
5523
5524     // We've now consumed the GTF_INX_RNGCHK, and the node
5525     // is no longer a GT_INDEX node.
5526     tree->gtFlags &= ~GTF_INX_RNGCHK;
5527
5528     tree->gtOp.gtOp1 = addr;
5529
5530     // This is an array index expression.
5531     tree->gtFlags |= GTF_IND_ARR_INDEX;
5532
5533     /* An indirection will cause a GPF if the address is null */
5534     tree->gtFlags |= GTF_EXCEPT;
5535
5536     if  (nCSE)
5537         tree->gtFlags |= GTF_DONT_CSE;
5538
5539     // Store information about it.
5540     GetArrayInfoMap()->Set(tree, ArrayInfo(elemTyp, elemSize, (int) elemOffs, elemStructType));
5541
5542     // Remember this 'indTree' that we just created, as we still need to attach the fieldSeq information to it.
5543
5544     GenTreePtr indTree = tree;
5545
5546     // Did we create a bndsChk tree?
5547     if  (bndsChk)
5548     {
5549         // Use a GT_COMMA node to prepend the array bound check
5550         //
5551         tree = gtNewOperNode(GT_COMMA, elemTyp, bndsChk, tree);
5552
5553         /* Mark the indirection node as needing a range check */
5554         fgSetRngChkTarget(bndsChk);
5555     }
5556
5557     if (indexDefn != nullptr)
5558     {
5559         // Use a GT_COMMA node to prepend the index assignment
5560         //
5561         tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), indexDefn, tree);
5562     }
5563     if (arrRefDefn != nullptr)
5564     {
5565         // Use a GT_COMMA node to prepend the arRef assignment
5566         //
5567         tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), arrRefDefn, tree);
5568     }
5569
5570     // Currently we morph the tree to perform some folding operations prior 
5571     // to attaching fieldSeq info and labeling constant array index contributions
5572     // 
5573     fgMorphTree(tree);
5574
5575     // Ideally we just want to proceed to attaching fieldSeq info and labeling the 
5576     // constant array index contributions, but the morphing operation may have changed 
5577     // the 'tree' into something that now unconditionally throws an exception.
5578     //
5579     // In such case the gtEffectiveVal could be a new tree or it's gtOper could be modified
5580     // or it could be left unchanged.  If it is unchanged then we should not return, 
5581     // instead we should proceed to attaching fieldSeq info, etc...
5582     // 
5583     GenTreePtr arrElem = tree->gtEffectiveVal();
5584
5585     if (fgIsCommaThrow(tree))
5586     {
5587         if ((arrElem != indTree) ||          // A new tree node may have been created
5588             (indTree->OperGet() != GT_IND))  // The GT_IND may have been changed to a GT_CNS_INT
5589         {
5590             return tree;     // Just return the Comma-Throw, don't try to attach the fieldSeq info, etc..
5591         }
5592     }
5593
5594     assert(!fgGlobalMorph || (arrElem->gtFlags & GTF_MORPHED));
5595
5596     addr = arrElem->gtOp.gtOp1;
5597
5598     assert(addr->TypeGet() == TYP_BYREF);
5599
5600     GenTreePtr cnsOff = nullptr;
5601     if (addr->OperGet() == GT_ADD)
5602     {
5603         if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
5604         {
5605             cnsOff = addr->gtOp.gtOp2;
5606             addr   = addr->gtOp.gtOp1;
5607         }
5608
5609         while ((addr->OperGet() == GT_ADD) || (addr->OperGet() == GT_SUB))
5610         {
5611             assert(addr->TypeGet() == TYP_BYREF);
5612             GenTreePtr index = addr->gtOp.gtOp2;
5613
5614             // Label any constant array index contributions with #ConstantIndex and any LclVars with GTF_VAR_ARR_INDEX
5615             index->LabelIndex(this);
5616
5617             addr  = addr->gtOp.gtOp1;
5618         }
5619         assert(addr->TypeGet() == TYP_REF);
5620     }
5621     else if (addr->OperGet() == GT_CNS_INT)
5622     {
5623          cnsOff = addr;
5624     }
5625
5626     FieldSeqNode* firstElemFseq = GetFieldSeqStore()->CreateSingleton(FieldSeqStore::FirstElemPseudoField);
5627
5628     if ((cnsOff != nullptr) && (cnsOff->gtIntCon.gtIconVal == elemOffs))
5629     {
5630         // Assign it the [#FirstElem] field sequence
5631         //
5632         cnsOff->gtIntCon.gtFieldSeq = firstElemFseq;
5633     }
5634     else  //  We have folded the first element's offset with the index expression
5635     {
5636         // Build the [#ConstantIndex, #FirstElem] field sequence
5637         //
5638         FieldSeqNode* constantIndexFseq = GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
5639         FieldSeqNode* fieldSeq          = GetFieldSeqStore()->Append(constantIndexFseq, firstElemFseq);
5640
5641         if (cnsOff == nullptr)   // It must have folded into a zero offset
5642         {
5643             // Record in the general zero-offset map.
5644             GetZeroOffsetFieldMap()->Set(addr, fieldSeq);
5645         }
5646         else
5647         {
5648             cnsOff->gtIntCon.gtFieldSeq = fieldSeq;
5649         }
5650     }
5651
5652     return tree;
5653 }
5654
5655 #ifdef _TARGET_X86_
5656 /*****************************************************************************
5657  *
5658  *  Wrap fixed stack arguments for varargs functions to go through varargs
5659  *  cookie to access them, except for the cookie itself.
5660  *
5661  * Non-x86 platforms are allowed to access all arguments directly
5662  * so we don't need this code.
5663  *
5664  */
5665 GenTreePtr          Compiler::fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs)
5666 {
5667     /* For the fixed stack arguments of a varargs function, we need to go
5668         through the varargs cookies to access them, except for the
5669         cookie itself */
5670
5671     LclVarDsc * varDsc = &lvaTable[lclNum];
5672
5673     if (varDsc->lvIsParam && !varDsc->lvIsRegArg &&
5674         lclNum != lvaVarargsHandleArg)
5675     {
5676         // Create a node representing the local pointing to the base of the args
5677         GenTreePtr ptrArg = gtNewOperNode(GT_SUB, TYP_I_IMPL,
5678                                             gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL),
5679                                             gtNewIconNode(varDsc->lvStkOffs 
5680                                                         - codeGen->intRegState.rsCalleeRegArgNum*sizeof(void*)
5681                                                         + lclOffs));
5682
5683         // Access the argument through the local
5684         GenTreePtr tree = gtNewOperNode(GT_IND, varType, ptrArg);
5685         tree->gtFlags |= GTF_IND_TGTANYWHERE;
5686
5687         if (varDsc->lvAddrExposed)
5688         {
5689             tree->gtFlags |= GTF_GLOB_REF;
5690         }
5691
5692         return fgMorphTree(tree);
5693     }
5694
5695     return NULL;
5696 }
5697 #endif
5698
5699 /*****************************************************************************
5700  *
5701  *  Transform the given GT_LCL_VAR tree for code generation.
5702  */
5703
5704 GenTreePtr          Compiler::fgMorphLocalVar(GenTreePtr tree)
5705 {
5706     noway_assert(tree->gtOper == GT_LCL_VAR);
5707
5708     unsigned    lclNum  = tree->gtLclVarCommon.gtLclNum;
5709     var_types   varType = lvaGetRealType(lclNum);
5710     LclVarDsc * varDsc = &lvaTable[lclNum];
5711
5712     if (varDsc->lvAddrExposed)
5713     {
5714         tree->gtFlags |= GTF_GLOB_REF;
5715     }
5716
5717 #ifdef _TARGET_X86_
5718     if (info.compIsVarArgs)
5719     {
5720         GenTreePtr newTree = fgMorphStackArgForVarArgs(lclNum, varType, 0);
5721         if (newTree != NULL)
5722             return newTree;
5723     }
5724 #endif // _TARGET_X86_
5725
5726     /* If not during the global morphing phase bail */
5727
5728     if (!fgGlobalMorph)
5729         return tree;
5730
5731     bool varAddr = (tree->gtFlags & GTF_DONT_CSE) != 0;
5732
5733     noway_assert(!(tree->gtFlags & GTF_VAR_DEF) || varAddr); // GTF_VAR_DEF should always imply varAddr
5734
5735     if (!varAddr                          &&
5736         varTypeIsSmall(varDsc->TypeGet()) &&
5737         varDsc->lvNormalizeOnLoad())
5738     {
5739 #if LOCAL_ASSERTION_PROP
5740         /* Assertion prop can tell us to omit adding a cast here */
5741         if (optLocalAssertionProp &&
5742             optAssertionIsSubrange(tree, varType, apFull) != NO_ASSERTION_INDEX)
5743         {
5744             return tree;
5745         }
5746 #endif
5747         /* Small-typed arguments and aliased locals are normalized on load.
5748            Other small-typed locals are normalized on store.
5749            Also, under the debugger as the debugger could write to the variable.
5750            If this is one of the former, insert a narrowing cast on the load.
5751                    ie. Convert: var-short --> cast-short(var-int) */
5752
5753         tree->gtType = TYP_INT;
5754         fgMorphTreeDone(tree);
5755         tree = gtNewCastNode(TYP_INT, tree, varType);
5756         fgMorphTreeDone(tree);
5757         return tree;
5758     }
5759
5760     return tree;
5761 }
5762
5763
5764 /*****************************************************************************
5765   Grab a temp for big offset morphing.
5766   This method will grab a new temp if no temp of this "type" has been created.
5767   Or it will return the same cached one if it has been created.
5768 */
5769 unsigned            Compiler::fgGetBigOffsetMorphingTemp(var_types type)
5770 {
5771     unsigned lclNum = fgBigOffsetMorphingTemps[type];
5772
5773     if (lclNum == BAD_VAR_NUM) {
5774         // We haven't created a temp for this kind of type. Create one now.
5775         lclNum = lvaGrabTemp(false DEBUGARG("Big Offset Morphing"));
5776         fgBigOffsetMorphingTemps[type] = lclNum;
5777     }
5778     else {
5779         // We better get the right type.
5780         noway_assert(lvaTable[lclNum].TypeGet() == type);
5781     }
5782
5783     noway_assert(lclNum != BAD_VAR_NUM);
5784     return lclNum;
5785 }
5786
5787
5788 /*****************************************************************************
5789  *
5790  *  Transform the given GT_FIELD tree for code generation.
5791  */
5792
5793 GenTreePtr          Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
5794  {
5795      assert(tree->gtOper == GT_FIELD);
5796
5797      noway_assert(tree->gtFlags & GTF_GLOB_REF);
5798
5799      CORINFO_FIELD_HANDLE  symHnd    = tree->gtField.gtFldHnd;
5800      unsigned              fldOffset = tree->gtField.gtFldOffset;
5801      GenTreePtr            objRef    = tree->gtField.gtFldObj;
5802      bool                  fieldMayOverlap = false;
5803      if (tree->gtField.gtFldMayOverlap)
5804      {
5805           fieldMayOverlap = true;
5806           // Reset the flag because we may reuse the node.
5807           tree->gtField.gtFldMayOverlap = false;
5808      }
5809
5810 #ifdef FEATURE_SIMD
5811      // if this field belongs to simd struct, tranlate it to simd instrinsic.
5812      if (mac == nullptr || mac->m_kind != MACK_Addr)
5813      {
5814          GenTreePtr newTree = fgMorphFieldToSIMDIntrinsicGet(tree);
5815          if (newTree != tree)
5816          {
5817              newTree = fgMorphSmpOp(newTree);
5818              return newTree;
5819          }
5820      }
5821      else if (objRef != nullptr && objRef->OperGet() == GT_ADDR && objRef->OperIsSIMD())
5822      {
5823          // We have a field of an SIMD intrinsic in an address-taken context.
5824          // We need to copy the SIMD result to a temp, and take the field of that.
5825          GenTree* copy = fgCopySIMDNode(objRef->gtOp.gtOp1->AsSIMD());
5826          objRef->gtOp.gtOp1 = copy;
5827      }
5828 #endif
5829      
5830      /* Is this an instance data member? */
5831
5832      if  (objRef)
5833      {
5834         GenTreePtr     addr;
5835
5836         if (tree->gtFlags & GTF_IND_TLS_REF)
5837             NO_WAY("instance field can not be a TLS ref.");
5838
5839         /* We'll create the expression "*(objRef + mem_offs)" */
5840
5841         noway_assert(varTypeIsGC(objRef->TypeGet()) ||
5842                            objRef->TypeGet() == TYP_I_IMPL);
5843
5844         // An optimization for Contextful classes:
5845         // we unwrap the proxy when we have a 'this reference'
5846         if (info.compIsContextful &&
5847             info.compUnwrapContextful &&
5848             impIsThis(objRef))
5849         {
5850             objRef = fgUnwrapProxy(objRef);
5851         }
5852
5853         /*
5854             Now we have a tree like this:
5855
5856                                   +--------------------+
5857                                   |      GT_FIELD      |   tree
5858                                   +----------+---------+
5859                                              |
5860                               +--------------+-------------+
5861                               |   tree->gtField.gtFldObj   |
5862                               +--------------+-------------+
5863
5864
5865             We want to make it like this (when fldOffset is <= MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT):
5866
5867                                   +--------------------+
5868                                   |   GT_IND/GT_OBJ    |   tree
5869                                   +---------+----------+
5870                                             |
5871                                             |
5872                                   +---------+----------+
5873                                   |       GT_ADD       |   addr
5874                                   +---------+----------+
5875                                             |
5876                                           /   \
5877                                         /       \
5878                                       /           \
5879                          +-------------------+  +----------------------+
5880                          |       objRef      |  |     fldOffset        |
5881                          |                   |  | (when fldOffset !=0) |
5882                          +-------------------+  +----------------------+
5883
5884
5885             or this (when fldOffset is > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT):
5886
5887
5888                                   +--------------------+
5889                                   |   GT_IND/GT_OBJ    |   tree
5890                                   +----------+---------+
5891                                              |
5892                                   +----------+---------+
5893                                   |       GT_COMMA     |  comma2
5894                                   +----------+---------+
5895                                              |
5896                                             / \
5897                                           /     \
5898                                         /         \
5899                                       /             \
5900                  +---------+----------+               +---------+----------+
5901            comma |      GT_COMMA      |               |  "+" (i.e. GT_ADD) |   addr
5902                  +---------+----------+               +---------+----------+
5903                            |                                     |
5904                          /   \                                  /  \
5905                        /       \                              /      \
5906                      /           \                          /          \
5907          +-----+-----+             +-----+-----+      +---------+   +-----------+
5908      asg |  GT_ASG   |         ind |   GT_IND  |      |  tmpLcl |   | fldOffset |
5909          +-----+-----+             +-----+-----+      +---------+   +-----------+
5910                |                         |
5911               / \                        |
5912             /     \                      |
5913           /         \                    |
5914    +-----+-----+   +-----+-----+   +-----------+
5915    |   tmpLcl  |   |   objRef  |   |   tmpLcl  |
5916    +-----------+   +-----------+   +-----------+
5917
5918
5919         */
5920
5921         var_types             objRefType = objRef->TypeGet();
5922
5923         GenTreePtr            comma      = NULL;
5924
5925         bool addedExplicitNullCheck = false;
5926
5927         // NULL mac means we encounter the GT_FIELD first.  This denotes a dereference of the field,
5928         // and thus is equivalent to a MACK_Ind with zero offset.
5929         MorphAddrContext defMAC(MACK_Ind);
5930         if (mac == NULL) mac = &defMAC;
5931
5932         // This flag is set to enable the "conservative" style of explicit null-check insertion.
5933         // This means that we insert an explicit null check whenever we create byref by adding a
5934         // constant offset to a ref, in a MACK_Addr context (meaning that the byref is not immediately
5935         // dereferenced).  The alternative is "aggressive", which would not insert such checks (for
5936         // small offsets); in this plan, we would transfer some null-checking responsibility to
5937         // callee's of methods taking byref parameters.  They would have to add explicit null checks
5938         // when creating derived byrefs from argument byrefs by adding constants to argument byrefs, in
5939         // contexts where the resulting derived byref is not immediately dereferenced (or if the offset is too
5940         // large).  To make the "aggressive" scheme work, however, we'd also have to add explicit derived-from-null
5941         // checks for byref parameters to "external" methods implemented in C++, and in P/Invoke stubs.
5942         /// This is left here to point out how to implement it.
5943 #define CONSERVATIVE_NULL_CHECK_BYREF_CREATION 1
5944
5945         // If the objRef is a GT_ADDR node, it, itself, never requires null checking.  The expression
5946         // whose address is being taken is either a local or static variable, whose address is necessarily
5947         // non-null, or else it is a field dereference, which will do its own bounds checking if necessary.
5948         if (objRef->gtOper != GT_ADDR
5949             && ((mac->m_kind == MACK_Addr || mac->m_kind == MACK_Ind)
5950                 && (!mac->m_allConstantOffsets
5951                     || fgIsBigOffset(mac->m_totalOffset + fldOffset)
5952 #if CONSERVATIVE_NULL_CHECK_BYREF_CREATION
5953                     || (mac->m_kind == MACK_Addr && (mac->m_totalOffset + fldOffset > 0))
5954 #else
5955                     || (objRef->gtType == TYP_BYREF && mac->m_kind == MACK_Addr && (mac->m_totalOffset + fldOffset > 0))
5956 #endif
5957                     )))
5958         {
5959 #ifdef DEBUG
5960             if (verbose)
5961             {
5962                 printf("Before explicit null check morphing:\n");
5963                 gtDispTree(tree);
5964             }
5965 #endif
5966
5967             //
5968             // Create the "comma" subtree
5969             //
5970             GenTreePtr     asg = NULL;
5971             GenTreePtr     nullchk;
5972
5973             unsigned lclNum;
5974
5975             if (objRef->gtOper != GT_LCL_VAR)
5976             {
5977                 lclNum = fgGetBigOffsetMorphingTemp(genActualType(objRef->TypeGet()));
5978
5979                 // Create the "asg" node
5980                 asg    = gtNewTempAssign(lclNum, objRef);
5981             }
5982             else
5983             {
5984                 lclNum = objRef->gtLclVarCommon.gtLclNum;
5985             }
5986
5987             // Create the "nullchk" node
5988             nullchk = gtNewOperNode(GT_NULLCHECK,
5989                                     TYP_BYTE,  // Make it TYP_BYTE so we only deference it for 1 byte.
5990                                     gtNewLclvNode(lclNum, objRefType));
5991             nullchk->gtFlags |= GTF_DONT_CSE;     // Don't try to create a CSE for these TYP_BYTE indirections
5992
5993             /* An indirection will cause a GPF if the address is null */
5994             nullchk->gtFlags |= GTF_EXCEPT;
5995
5996             if (asg)
5997             {
5998                 // Create the "comma" node.
5999                 comma  = gtNewOperNode(GT_COMMA,
6000                                        TYP_VOID, // We don't want to return anything from this "comma" node.
6001                                                  // Set the type to TYP_VOID, so we can select "cmp" instruction
6002                                                  // instead of "mov" instruction later on.
6003                                        asg,
6004                                        nullchk);
6005             }
6006             else
6007             {
6008                 comma = nullchk;
6009             }
6010
6011             addr = gtNewLclvNode(lclNum, objRefType);     // Use "tmpLcl" to create "addr" node.
6012
6013             addedExplicitNullCheck = true;
6014         }
6015         else if  (fldOffset == 0)
6016         {
6017             // Generate the "addr" node.
6018             addr = objRef;
6019             FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6020             GetZeroOffsetFieldMap()->Set(addr, fieldSeq);
6021         }
6022         else
6023         {
6024             addr = objRef;
6025         }
6026
6027 #ifdef FEATURE_READYTORUN_COMPILER
6028         if (tree->gtField.gtFieldLookup.addr != nullptr)
6029         {
6030             GenTreePtr baseOffset = gtNewIconEmbHndNode(tree->gtField.gtFieldLookup.addr, nullptr, GTF_ICON_FIELD_HDL);
6031
6032             if (tree->gtField.gtFieldLookup.accessType == IAT_PVALUE)
6033                 baseOffset = gtNewOperNode(GT_IND, TYP_I_IMPL, baseOffset);
6034
6035             addr = gtNewOperNode(GT_ADD,
6036                                  (var_types)(objRefType ==  TYP_I_IMPL ? TYP_I_IMPL
6037                                                             : TYP_BYREF),
6038                                  addr,
6039                                  baseOffset
6040                                 );
6041         }
6042 #endif
6043         if  (fldOffset != 0)
6044         {
6045             // Generate the "addr" node.
6046             /* Add the member offset to the object's address */
6047             FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6048             addr = gtNewOperNode(GT_ADD,
6049                                  (var_types)(objRefType == TYP_I_IMPL ? TYP_I_IMPL
6050                                                             : TYP_BYREF),
6051                                  addr,
6052                                  gtNewIconHandleNode(fldOffset,
6053                                                      GTF_ICON_FIELD_OFF,
6054                                                      fieldSeq));
6055         }
6056
6057         // Now let's set the "tree" as a GT_IND tree.
6058
6059         tree->SetOper(GT_IND);
6060         tree->gtOp.gtOp1 = addr;
6061
6062         if (fgAddrCouldBeNull(addr))
6063         {
6064             // This indirection can cause a GPF if the address could be null.
6065             tree->gtFlags |= GTF_EXCEPT;
6066         }
6067
6068         if (addedExplicitNullCheck)
6069         {
6070             //
6071             // Create "comma2" node and link it to "tree".
6072             //
6073             GenTreePtr comma2;
6074             comma2 = gtNewOperNode(GT_COMMA,
6075                                    addr->TypeGet(), // The type of "comma2" node is the same as the type of "addr" node.
6076                                    comma,
6077                                    addr);
6078             tree->gtOp.gtOp1 = comma2;
6079         }
6080
6081 #ifdef DEBUG
6082         if (verbose)
6083         {
6084             if (addedExplicitNullCheck) {
6085                 printf("After adding explicit null check:\n");
6086                 gtDispTree(tree);
6087             }
6088         }
6089 #endif
6090
6091     }
6092     else     /* This is a static data member */
6093     {
6094         if (tree->gtFlags & GTF_IND_TLS_REF)
6095         {
6096             // Thread Local Storage static field reference
6097             //
6098             // Field ref is a TLS 'Thread-Local-Storage' reference
6099             //
6100             // Build this tree:  IND(*) #
6101             //                    |
6102             //                   ADD(I_IMPL)
6103             //                   / \
6104             //                  /  CNS(fldOffset)
6105             //                 /
6106             //                /
6107             //               /
6108             //             IND(I_IMPL) == [Base of this DLL's TLS]
6109             //              |
6110             //             ADD(I_IMPL)
6111             //             / \
6112             //            /   CNS(IdValue*4) or MUL
6113             //           /                      / \
6114             //          IND(I_IMPL)            /  CNS(4)
6115             //           |                    /
6116             //          CNS(TLS_HDL,0x2C)    IND
6117             //                                |
6118             //                               CNS(pIdAddr)
6119             //
6120             // # Denotes the orginal node
6121             //
6122             void **    pIdAddr   = NULL;
6123             unsigned    IdValue  = info.compCompHnd->getFieldThreadLocalStoreID(symHnd, (void**) &pIdAddr);
6124
6125             //
6126             // If we can we access the TLS DLL index ID value directly
6127             // then pIdAddr will be NULL and
6128             //      IdValue will be the actual TLS DLL index ID
6129             //
6130             GenTreePtr dllRef = NULL;
6131             if (pIdAddr == NULL)
6132             {
6133                 if (IdValue != 0)
6134                     dllRef = gtNewIconNode(IdValue*4, TYP_I_IMPL);
6135             }
6136             else
6137             {
6138                 dllRef = gtNewIconHandleNode((size_t)pIdAddr, GTF_ICON_STATIC_HDL);
6139                 dllRef = gtNewOperNode(GT_IND, TYP_I_IMPL, dllRef);
6140                 dllRef->gtFlags |= GTF_IND_INVARIANT;
6141
6142                 /* Multiply by 4 */
6143
6144                 dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(4, TYP_I_IMPL));
6145             }
6146
6147             #define WIN32_TLS_SLOTS (0x2C) // Offset from fs:[0] where the pointer to the slots resides
6148
6149             // Mark this ICON as a TLS_HDL, codegen will use FS:[cns]
6150
6151             GenTreePtr tlsRef = gtNewIconHandleNode(WIN32_TLS_SLOTS, GTF_ICON_TLS_HDL);
6152
6153             tlsRef = gtNewOperNode(GT_IND, TYP_I_IMPL, tlsRef);
6154
6155             if (dllRef != NULL)
6156             {
6157                 /* Add the dllRef */
6158                 tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef);
6159             }
6160
6161             /* indirect to have tlsRef point at the base of the DLLs Thread Local Storage */
6162             tlsRef = gtNewOperNode(GT_IND, TYP_I_IMPL, tlsRef);
6163
6164             if (fldOffset != 0)
6165             {
6166                 FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6167                 GenTreePtr fldOffsetNode = new(this, GT_CNS_INT) GenTreeIntCon(TYP_INT, fldOffset, fieldSeq);
6168
6169                 /* Add the TLS static field offset to the address */
6170
6171                 tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, fldOffsetNode);
6172             }
6173
6174             // Final indirect to get to actual value of TLS static field
6175
6176             tree->SetOper(GT_IND);
6177             tree->gtOp.gtOp1 = tlsRef;
6178
6179             noway_assert(tree->gtFlags & GTF_IND_TLS_REF);
6180         }
6181         else
6182         {
6183             // Normal static field reference
6184
6185             //
6186             // If we can we access the static's address directly
6187             // then pFldAddr will be NULL and
6188             //      fldAddr will be the actual address of the static field
6189             //
6190             void **  pFldAddr = NULL;
6191             void * fldAddr = info.compCompHnd->getFieldAddress(symHnd, (void**) &pFldAddr);
6192
6193             if (pFldAddr == NULL)
6194             {
6195 #ifdef _TARGET_64BIT_
6196                 if (IMAGE_REL_BASED_REL32 != eeGetRelocTypeHint(fldAddr))
6197                 {
6198                     // The address is not directly addressible, so force it into a
6199                     // constant, so we handle it properly
6200
6201                     GenTreePtr addr = gtNewIconHandleNode((size_t)fldAddr, GTF_ICON_STATIC_HDL);
6202                     addr->gtType = TYP_I_IMPL;
6203                     FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6204                     addr->gtIntCon.gtFieldSeq = fieldSeq;
6205
6206                     tree->SetOper(GT_IND);
6207                     tree->gtOp.gtOp1         = addr;
6208
6209                     return fgMorphSmpOp(tree);
6210                 }
6211                 else
6212 #endif // _TARGET_64BIT_
6213                 {
6214                     // Only volatile could be set, and it maps over
6215                     noway_assert((tree->gtFlags & ~(GTF_FLD_VOLATILE | GTF_COMMON_MASK)) == 0);
6216                     noway_assert(GTF_FLD_VOLATILE == GTF_IND_VOLATILE);
6217                     tree->SetOper(GT_CLS_VAR);
6218                     tree->gtClsVar.gtClsVarHnd = symHnd;
6219                     FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6220                     tree->gtClsVar.gtFieldSeq = fieldSeq;
6221                 }
6222
6223                 return tree;
6224             }
6225             else
6226             {
6227                 GenTreePtr addr  = gtNewIconHandleNode((size_t)pFldAddr, GTF_ICON_STATIC_HDL);
6228
6229                 // There are two cases here, either the static is RVA based,
6230                 // in which case the type of the FIELD node is not a GC type
6231                 // and the handle to the RVA is a TYP_I_IMPL.  Or the FIELD node is
6232                 // a GC type and the handle to it is a TYP_BYREF in the GC heap
6233                 // because handles to statics now go into the large object heap
6234
6235                 var_types  handleTyp = (var_types) (varTypeIsGC(tree->TypeGet()) ? TYP_BYREF
6236                                                     : TYP_I_IMPL);
6237                 GenTreePtr op1       = gtNewOperNode(GT_IND, handleTyp, addr);
6238                 op1->gtFlags        |= GTF_IND_INVARIANT;
6239
6240                 tree->SetOper(GT_IND);
6241                 tree->gtOp.gtOp1 = op1;
6242             }
6243         }
6244     }
6245     noway_assert(tree->gtOper == GT_IND);
6246
6247     GenTreePtr res = fgMorphSmpOp(tree);
6248
6249     if (fldOffset == 0 && res->OperGet() == GT_IND)
6250     {
6251         GenTreePtr addr = res->gtOp.gtOp1;
6252         // Since we don't make a constant zero to attach the field sequence to, associate it with the "addr" node.
6253         FieldSeqNode* fieldSeq = fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
6254         fgAddFieldSeqForZeroOffset(addr, fieldSeq);
6255     }
6256
6257     return res;
6258
6259 }
6260
6261
6262 //------------------------------------------------------------------------------
6263 // fgMorphCallInline: attempt to inline a call
6264 //
6265 // Arguments:
6266 //    call         - call expression to inline, inline candidate
6267 //    inlineResult - result tracking and reporting
6268 //
6269 // Notes:
6270 //    Attempts to inline the call.
6271 //
6272 //    If successful, callee's IR is inserted in place of the call, and
6273 //    is marked with an InlineContext.
6274 //
6275 //    If unsuccessful, the transformations done in anticpation of a
6276 //    possible inline are undone, and the candidate flag on the call
6277 //    is cleared.
6278
6279 void        Compiler::fgMorphCallInline(GenTreeCall* call, InlineResult* inlineResult)
6280 {
6281     // The call must be a candiate for inlining.
6282     assert((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0);
6283
6284     // Attempt the inline
6285     fgMorphCallInlineHelper(call, inlineResult);
6286
6287     // We should have made up our minds one way or another....
6288     assert(inlineResult->IsDecided());
6289
6290     // If we failed to inline, we have a bit of work to do to cleanup
6291     if (inlineResult->IsFailure())
6292     {
6293
6294 #ifdef DEBUG
6295
6296         // Before we do any cleanup, create a failing InlineContext to
6297         // capture details of the inlining attempt.
6298         m_inlineStrategy->NewFailure(fgMorphStmt, inlineResult);
6299
6300 #endif
6301
6302         // It was an inline candidate, but we haven't expanded it.
6303         if (call->gtCall.gtReturnType != TYP_VOID)
6304         {
6305             // Detach the GT_CALL tree from the original statement by
6306             // hanging a "nothing" node to it. Later the "nothing" node will be removed
6307             // and the original GT_CALL tree will be picked up by the GT_RET_EXPR node.
6308
6309             noway_assert(fgMorphStmt->gtStmt.gtStmtExpr == call);
6310             fgMorphStmt->gtStmt.gtStmtExpr = gtNewNothingNode();
6311         }
6312
6313         // Clear the Inline Candidate flag so we can ensure later we tried
6314         // inlining all candidates.
6315         //
6316         call->gtFlags &= ~GTF_CALL_INLINE_CANDIDATE;
6317     }
6318 }
6319
6320 /*****************************************************************************
6321  *  Helper to attempt to inline a call
6322  *  Sets success/failure in inline result
6323  *  If success, modifies current method's IR with inlinee's IR
6324  *  If failed, undoes any speculative modifications to current method
6325  */
6326
6327 void Compiler::fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result)
6328 {
6329     // Don't expect any surprises here.
6330     assert(result->IsCandidate());
6331     
6332     if (lvaCount >= MAX_LV_NUM_COUNT_FOR_INLINING)
6333     {
6334         // For now, attributing this to call site, though it's really
6335         // more of a budget issue (lvaCount currently includes all
6336         // caller and prospective callee locals). We still might be
6337         // able to inline other callees into this caller, or inline
6338         // this callee in other callers.
6339         result->NoteFatal(InlineObservation::CALLSITE_TOO_MANY_LOCALS);
6340         return;
6341     }
6342
6343     if (call->IsVirtual())
6344     {
6345         result->NoteFatal(InlineObservation::CALLSITE_IS_VIRTUAL);
6346         return;
6347     }
6348
6349     // impMarkInlineCandidate() is expected not to mark tail prefixed calls
6350     // and recursive tail calls as inline candidates.
6351     noway_assert(!call->IsTailPrefixedCall());
6352     noway_assert(!call->IsImplicitTailCall() || !gtIsRecursiveCall(call));
6353
6354     /* If the caller's stack frame is marked, then we can't do any inlining. Period.
6355        Although we have checked this in impCanInline, it is possible that later IL instructions
6356        might cause compNeedSecurityCheck to be set. Therefore we need to check it here again.
6357     */
6358
6359     if (opts.compNeedSecurityCheck)
6360     {
6361         result->NoteFatal(InlineObservation::CALLER_NEEDS_SECURITY_CHECK);
6362         return;
6363     }
6364     
6365     //
6366     // Calling inlinee's compiler to inline the method.
6367     //
6368
6369     unsigned    startVars = lvaCount;
6370
6371 #ifdef DEBUG
6372     if (verbose)
6373     {
6374        printf("Expanding INLINE_CANDIDATE in statement ");
6375        printTreeID(fgMorphStmt);
6376        printf(" in BB%02u:\n", compCurBB->bbNum);
6377        gtDispTree(fgMorphStmt);
6378        
6379        // printf("startVars=%d.\n", startVars);
6380     }
6381 #endif
6382
6383     //
6384     // Invoke the compiler to inline the call.
6385     //
6386     
6387     fgInvokeInlineeCompiler(call, result);
6388
6389     if (result->IsFailure()) 
6390     {
6391        // Undo some changes made in anticipation of inlining...
6392
6393        // Zero out the used locals
6394        memset(lvaTable + startVars, 0, (lvaCount  - startVars) * sizeof(*lvaTable));
6395        for (unsigned i = startVars; i < lvaCount; i++)
6396        {
6397           new (&lvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
6398        }
6399
6400        lvaCount = startVars;
6401
6402 #ifdef DEBUG
6403        if  (verbose)
6404        {
6405           // printf("Inlining failed. Restore lvaCount to %d.\n", lvaCount);
6406        }
6407 #endif
6408
6409        return;
6410     }
6411
6412     // Success!
6413
6414 #ifdef DEBUG
6415     if  (verbose)
6416     {
6417        // printf("After inlining lvaCount=%d.\n", lvaCount);
6418     }
6419 #endif
6420 }
6421
6422 /*****************************************************************************
6423  *
6424  * Performs checks to see if this tail call can be optimized as epilog+jmp.
6425  */
6426 bool                Compiler::fgCanFastTailCall(GenTreeCall* callee)
6427 {
6428 #if FEATURE_FASTTAILCALL
6429     // Reached here means that return types of caller and callee are tail call compatible.
6430     // In case of structs that can be returned in a register, compRetNativeType is set to the actual return type.
6431     //
6432     // In an implicit tail call case callSig may not be available but it is guaranteed to be available
6433     // for explicit tail call cases.  The reason implicit tail case callSig may not be available is that
6434     // a call node might be marked as an in-line candidate and could fail to be in-lined. In which case
6435     // fgInline() will replace return value place holder with call node using gtCloneExpr() which is
6436     // currently not copying/setting callSig.
6437 #ifdef DEBUG
6438     if (callee->IsTailPrefixedCall())
6439     {
6440         assert(impTailCallRetTypeCompatible(info.compRetNativeType, info.compMethodInfo->args.retTypeClass, 
6441                                             (var_types)callee->gtReturnType, callee->callSig->retTypeClass));
6442     }
6443 #endif
6444
6445     // Note on vararg methods:
6446     // If the caller is vararg method, we don't know the number of arguments passed by caller's caller.
6447     // But we can be sure that in-coming arg area of vararg caller would be sufficient to hold its 
6448     // fixed args. Therefore, we can allow a vararg method to fast tail call other methods as long as
6449     // out-going area required for callee is bounded by caller's fixed argument space.
6450     // 
6451     // Note that callee being a vararg method is not a problem since we can account the params being passed.
6452
6453     // Count of caller args including implicit and hidden (i.e. thisPtr, RetBuf, GenericContext, VarargCookie)
6454     unsigned nCallerArgs = info.compArgsCount;
6455
6456     // Count the callee args including implicit and hidden.
6457     // Note that GenericContext and VarargCookie are added by importer while
6458     // importing the call to gtCallArgs list along with explicit user args.
6459     unsigned nCalleeArgs = 0;        
6460     if (callee->gtCallObjp)  // thisPtr
6461     {
6462         nCalleeArgs++;
6463     }
6464
6465     if (callee->HasRetBufArg())  // RetBuf
6466     {
6467         nCalleeArgs++;
6468
6469         // If callee has RetBuf param, caller too must have it.
6470         // Otherwise go the slow route.
6471         if (info.compRetBuffArg == BAD_VAR_NUM)
6472         {
6473             return false;
6474         }
6475     }
6476
6477     // Count user args while tracking whether any of them is a multi-byte params
6478     // that cannot be passed in a register. Note that we don't need to count
6479     // non-standard and secret params passed in registers (e.g. R10, R11) since
6480     // these won't contribute to out-going arg size.
6481     bool hasMultiByteArgs = false;
6482     for (GenTreePtr args = callee->gtCallArgs; (args != nullptr) && !hasMultiByteArgs; args = args->gtOp.gtOp2)
6483     {
6484         nCalleeArgs++;
6485
6486         assert(args->IsList());
6487         GenTreePtr argx = args->gtOp.gtOp1;
6488
6489         if (varTypeIsStruct(argx))
6490         {
6491             // Actual arg may be a child of a GT_COMMA. Skip over comma opers.
6492             while (argx->gtOper == GT_COMMA)
6493             {
6494                 argx = argx->gtOp.gtOp2;
6495             }
6496
6497             // Get the size of the struct and see if it is register passable.
6498             if (argx->OperGet() == GT_OBJ)
6499             {
6500 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
6501
6502                 unsigned typeSize = 0;
6503                 hasMultiByteArgs = !VarTypeIsMultiByteAndCanEnreg(argx->TypeGet(), argx->gtObj.gtClass, &typeSize, false);
6504
6505 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARM64_)
6506                 // On System V/arm64 the args could be a 2 eightbyte struct that is passed in two registers.
6507                 // Account for the second eightbyte in the nCalleeArgs.
6508                 // https://github.com/dotnet/coreclr/issues/2666
6509                 // TODO-CQ-Amd64-Unix/arm64:  Structs of size between 9 to 16 bytes are conservatively estimated
6510                 //                            as two args, since they need two registers whereas nCallerArgs is
6511                 //                            counting such an arg as one. This would mean we will not be optimizing
6512                 //                            certain calls though technically possible.
6513
6514                 if (typeSize > TARGET_POINTER_SIZE)
6515                 {
6516                     unsigned extraArgRegsToAdd = (typeSize / TARGET_POINTER_SIZE);
6517                     nCalleeArgs += extraArgRegsToAdd;
6518                 }
6519 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING || _TARGET_ARM64_
6520
6521 #else
6522                 assert(!"Target platform ABI rules regarding passing struct type args in registers");
6523                 unreached();
6524 #endif //_TARGET_AMD64_ || _TARGET_ARM64_
6525
6526             }
6527             else
6528             {
6529                 hasMultiByteArgs = true;
6530             }
6531         }
6532     }
6533
6534     // Go the slow route, if it has multi-byte params
6535     if (hasMultiByteArgs)
6536     {
6537         return false;
6538     }
6539
6540     // If we reached here means that callee has only those argument types which can be passed in
6541     // a register and if passed on stack will occupy exactly one stack slot in out-going arg area.
6542     // If we are passing args on stack for callee and it has more args passed on stack than
6543     // caller, then fast tail call cannot be performed.
6544     //
6545     // Note that the GC'ness of on stack args need not match since the arg setup area is marked
6546     // as non-interruptible for fast tail calls.
6547     if ((nCalleeArgs > MAX_REG_ARG) && (nCallerArgs < nCalleeArgs))
6548     {
6549         return false;
6550     }
6551
6552     return true;
6553 #else
6554     return false;
6555 #endif
6556 }
6557
6558
6559 /*****************************************************************************
6560  *
6561  *  Transform the given GT_CALL tree for tail call code generation.
6562  */
6563 void                Compiler::fgMorphTailCall(GenTreeCall* call)
6564 {
6565     // x86 classic codegen doesn't require any morphing
6566 #if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
6567     NYI_X86("Tail call morphing");
6568 #elif defined(_TARGET_ARM_)
6569     // For the helper-assisted tail calls, we need to push all the arguments
6570     // into a single list, and then add a few extra at the beginning
6571
6572     // Check for PInvoke call types that we don't handle in codegen yet.
6573     assert(!call->IsUnmanaged());
6574     assert(call->IsVirtual() ||
6575            (call->gtCallType != CT_INDIRECT) ||
6576            (call->gtCallCookie == NULL));
6577
6578     // First move the this pointer (if any) onto the regular arg list
6579     GenTreePtr thisPtr = NULL;
6580     if (call->gtCallObjp)
6581     {
6582         GenTreePtr objp = call->gtCallObjp;
6583         call->gtCallObjp = NULL;
6584
6585         if ((call->gtFlags & GTF_CALL_NULLCHECK) ||
6586             call->IsVirtualVtable())
6587         {
6588             thisPtr = gtClone(objp, true);
6589             var_types  vt = objp->TypeGet();
6590             if (thisPtr == NULL)
6591             {
6592                 // Too complex, so use a temp
6593                 unsigned lclNum = lvaGrabTemp(true DEBUGARG("tail call thisptr"));
6594                 GenTreePtr asg  = gtNewTempAssign(lclNum, objp);
6595                 if (!call->IsVirtualVtable())
6596                 {
6597                     // Add an indirection to get the nullcheck
6598                     GenTreePtr tmp = gtNewLclvNode(lclNum, vt);
6599                     GenTreePtr ind = gtNewOperNode(GT_IND, TYP_INT, tmp);
6600                     asg  = gtNewOperNode(GT_COMMA, TYP_VOID, asg, ind);
6601                 }
6602                 objp = gtNewOperNode(GT_COMMA, vt, asg, gtNewLclvNode(lclNum, vt));
6603                 thisPtr = gtNewLclvNode(lclNum, vt);
6604             }
6605             else if (!call->IsVirtualVtable())
6606             {
6607                 GenTreePtr ind = gtNewOperNode(GT_IND, TYP_INT, thisPtr);
6608                 objp = gtNewOperNode(GT_COMMA, vt, ind, objp);
6609                 thisPtr = gtClone(thisPtr, true);
6610             }
6611
6612             call->gtFlags &= ~GTF_CALL_NULLCHECK;
6613         }
6614
6615         GenTreeArgList** pList = &call->gtCallArgs;
6616 #if RETBUFARG_PRECEDES_THIS
6617         if (call->HasRetBufArg()) {
6618            pList = &(*pList)->Rest();
6619         }
6620 #endif // RETBUFARG_PRECEDES_THIS
6621         *pList = gtNewListNode(objp, *pList);
6622     }
6623
6624     // Add the extra VSD parameter if needed
6625     CorInfoHelperTailCallSpecialHandling flags = CorInfoHelperTailCallSpecialHandling(0);
6626     if (call->IsVirtualStub())
6627     {
6628         flags = CORINFO_TAILCALL_STUB_DISPATCH_ARG;
6629
6630         GenTreePtr arg;
6631         if (call->gtCallType == CT_INDIRECT) {
6632             arg = gtClone(call->gtCallAddr, true);
6633             noway_assert(arg != NULL);
6634         }
6635         else {
6636             noway_assert(call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT);
6637             ssize_t addr = ssize_t(call->gtStubCallStubAddr);
6638             arg = gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR);
6639
6640             // Change the call type, so we can add the extra indirection here, rather than in codegen
6641             call->gtCallAddr = gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR);
6642             call->gtStubCallStubAddr = NULL;
6643             call->gtCallType = CT_INDIRECT;
6644         }
6645         // Add the extra indirection to generate the real target
6646         call->gtCallAddr = gtNewOperNode(GT_IND, TYP_I_IMPL, call->gtCallAddr);
6647         call->gtFlags |= GTF_EXCEPT;
6648
6649         // And push the stub address onto the list of arguments
6650         call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
6651     }
6652     else if (call->IsVirtualVtable())
6653     {
6654         // TODO-ARM-NYI: for x64 handle CORINFO_TAILCALL_THIS_IN_SECRET_REGISTER
6655
6656         noway_assert(thisPtr != NULL);
6657
6658         GenTreePtr add  = gtNewOperNode(GT_ADD, TYP_I_IMPL, thisPtr, gtNewIconNode(VPTR_OFFS, TYP_I_IMPL));
6659         GenTreePtr vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
6660         vtbl->gtFlags |= GTF_EXCEPT;
6661
6662         unsigned   vtabOffsOfIndirection;
6663         unsigned   vtabOffsAfterIndirection;
6664         info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection);
6665
6666         /* Get the appropriate vtable chunk */
6667
6668         add  = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsOfIndirection, TYP_I_IMPL));
6669         vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
6670
6671         /* Now the appropriate vtable slot */
6672
6673         add  = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsAfterIndirection, TYP_I_IMPL));
6674         vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
6675
6676         // Switch this to a plain indirect call
6677         call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK;
6678         assert(!call->IsVirtual());
6679         call->gtCallType = CT_INDIRECT;
6680
6681         call->gtCallAddr = vtbl;
6682         call->gtCallCookie = NULL;
6683         call->gtFlags |= GTF_EXCEPT;
6684     }
6685
6686     // Now inject a placeholder for the real call target that codegen
6687     // will generate
6688     GenTreePtr arg = new (this, GT_NOP) GenTreeOp(GT_NOP, TYP_I_IMPL);
6689     codeGen->genMarkTreeInReg(arg, REG_TAILCALL_ADDR);
6690     call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
6691
6692     // Lastly inject the pointer for the copy routine
6693     noway_assert(call->callSig != NULL);
6694     void * pfnCopyArgs = info.compCompHnd->getTailCallCopyArgsThunk(call->callSig, flags);
6695     arg = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR);
6696     call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
6697
6698     // It is now a varargs tail call
6699     call->gtCallMoreFlags = GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL;
6700     call->gtFlags &= ~GTF_CALL_POP_ARGS;
6701
6702 #elif defined(_TARGET_AMD64_)
6703     // For the helper-assisted tail calls, we need to push all the arguments
6704     // into a single list, and then add a few extra at the beginning.
6705     //
6706     // TailCallHelper(void *copyRoutine, void *callTarget, ....) - i.e We need to add
6707     // copyRoutine and callTarget extra params at the beginning.  But callTarget is
6708     // determined by Lower phase.  Therefore, we add a place holder arg for callTarget
6709     // here which will be later replaced with callTarget in tail call lowering.
6710
6711     // Check for PInvoke call types that we don't handle in codegen yet.
6712     assert(!call->IsUnmanaged());
6713     assert(call->IsVirtual() ||
6714            (call->gtCallType != CT_INDIRECT) ||
6715            (call->gtCallCookie == NULL));
6716     
6717     // Don't support tail calling helper methods
6718     assert(call->gtCallType != CT_HELPER);
6719
6720     // We come this route only for tail prefixed calls that cannot be dispatched as
6721     // fast tail calls
6722     assert(!call->IsImplicitTailCall());
6723     assert(!fgCanFastTailCall(call));
6724
6725      // First move the this pointer (if any) onto the regular arg list    
6726     if (call->gtCallObjp)
6727     {
6728         GenTreePtr thisPtr = nullptr;
6729         GenTreePtr objp = call->gtCallObjp;
6730         call->gtCallObjp = nullptr;
6731
6732         if (call->NeedsNullCheck())
6733         {            
6734             // clone "this" if "this" has no side effects.
6735             if (!(objp->gtFlags & GTF_SIDE_EFFECT))
6736             {                
6737                 thisPtr = gtClone(objp, true);
6738             }
6739             
6740             var_types vt = objp->TypeGet();
6741             if (thisPtr == nullptr)
6742             {
6743                 // create a temp if either "this" has side effects or "this" is too complex to clone.
6744                 
6745                 // tmp = "this"            
6746                 unsigned lclNum = lvaGrabTemp(true DEBUGARG("tail call thisptr"));
6747                 GenTreePtr asg  = gtNewTempAssign(lclNum, objp);
6748                 
6749                 // COMMA(tmp = "this", deref(tmp))
6750                 GenTreePtr tmp = gtNewLclvNode(lclNum, vt);
6751                 GenTreePtr ind = gtNewOperNode(GT_IND, TYP_INT, tmp);
6752                 asg  = gtNewOperNode(GT_COMMA, TYP_VOID, asg, ind);
6753
6754                 // COMMA(COMMA(tmp = "this", deref(tmp)), tmp) 
6755                 thisPtr = gtNewOperNode(GT_COMMA, vt, asg, gtNewLclvNode(lclNum, vt));
6756             } 
6757             else
6758             {
6759                 // thisPtr = COMMA(deref("this"), "this")
6760                 GenTreePtr ind = gtNewOperNode(GT_IND, TYP_INT, thisPtr);
6761                 thisPtr = gtNewOperNode(GT_COMMA, vt, ind, gtClone(objp, true));
6762             }
6763
6764             call->gtFlags &= ~GTF_CALL_NULLCHECK;
6765         }
6766         else
6767         {
6768             thisPtr = objp;
6769         }
6770
6771         GenTreeArgList** pList = &call->gtCallArgs;
6772 #if RETBUFARG_PRECEDES_THIS
6773         if (call->HasRetBufArg()) {
6774            pList = &(*pList)->Rest();
6775         }
6776 #endif // RETBUFARG_PRECEDES_THIS
6777
6778         // During rationalization tmp="this" and null check will
6779         // materialize as embedded stmts in right execution order.
6780         assert(thisPtr != nullptr);
6781         *pList = gtNewListNode(thisPtr, *pList);
6782     }
6783
6784     // Add the extra VSD parameter to arg list in case of VSD calls.
6785     // Tail call arg copying thunk will move this extra VSD parameter
6786     // to R11 before tail calling VSD stub. See CreateTailCallCopyArgsThunk()
6787     // in Stublinkerx86.cpp for more details.
6788     CorInfoHelperTailCallSpecialHandling flags = CorInfoHelperTailCallSpecialHandling(0);
6789     if (call->IsVirtualStub())
6790     {
6791         GenTreePtr stubAddrArg;
6792
6793         flags = CORINFO_TAILCALL_STUB_DISPATCH_ARG;
6794
6795         if (call->gtCallType == CT_INDIRECT)
6796         {
6797             stubAddrArg = gtClone(call->gtCallAddr, true);
6798             noway_assert(stubAddrArg != nullptr);
6799         }
6800         else
6801         {
6802             noway_assert((call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0);
6803
6804             ssize_t addr = ssize_t(call->gtStubCallStubAddr);
6805             stubAddrArg = gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR);
6806         }
6807
6808         // Push the stub address onto the list of arguments
6809         call->gtCallArgs = gtNewListNode(stubAddrArg, call->gtCallArgs);
6810     }
6811
6812     // Now inject a placeholder for the real call target that Lower phase will generate.
6813     GenTreePtr arg = gtNewIconNode(0, TYP_I_IMPL);
6814     call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
6815
6816     // Inject the pointer for the copy routine to be used for struct copying
6817     noway_assert(call->callSig != nullptr);
6818     void * pfnCopyArgs = info.compCompHnd->getTailCallCopyArgsThunk(call->callSig, flags);
6819     arg = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR);
6820     call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
6821
6822     // It is now a varargs tail call dispatched via helper.
6823     call->gtCallMoreFlags |= GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
6824     call->gtFlags &= ~GTF_CALL_POP_ARGS;
6825
6826 #endif  //_TARGET_AMD64_
6827
6828 }
6829
6830 //------------------------------------------------------------------------------
6831 // fgMorphRecursiveFastTailCallIntoLoop : Transform a recursive fast tail call into a loop.
6832 //
6833 //
6834 // Arguments:
6835 //    block  - basic block ending with a recursive fast tail call
6836 //    recursiveTailCall - recursive tail call to transform
6837 //
6838 // Notes:
6839 //    The legality of the transformation is ensured by the checks in endsWithTailCallConvertibleToLoop.
6840
6841 void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall)
6842 {
6843     assert(recursiveTailCall->IsTailCallConvertibleToLoop());
6844     GenTreePtr last = fgGetLastTopLevelStmt(block);
6845     assert(recursiveTailCall == last->gtStmt.gtStmtExpr);
6846
6847     // Transform recursive tail call into a loop.
6848
6849     GenTreePtr earlyArgInsertionPoint = last;
6850     IL_OFFSETX callILOffset = last->gtStmt.gtStmtILoffsx;
6851
6852     // Hoist arg setup statement for the 'this' argument.
6853     GenTreePtr thisArg = recursiveTailCall->gtCallObjp;
6854     if (thisArg && !thisArg->IsNothingNode() && !thisArg->IsArgPlaceHolderNode())
6855     {
6856         GenTreePtr thisArgStmt = gtNewStmt(thisArg, callILOffset);
6857         fgInsertStmtBefore(block, earlyArgInsertionPoint, thisArgStmt);
6858
6859     }
6860
6861     // All arguments whose trees may involve caller parameter local variables need to be assigned to temps first;
6862     // then the temps need to be assigned to the method parameters. This is done so that the caller
6863     // parameters are not re-assigned before call arguments depending on them  are evaluated.
6864     // tmpAssignmentInsertionPoint and paramAssignmentInsertionPoint keep track of
6865     // where the next temp or parameter assignment should be inserted.
6866
6867     // In the example below the first call argument (arg1 - 1) needs to be assigned to a temp first
6868     // while the second call argument (const 1) doesn't.
6869     // Basic block before tail recursion elimination:
6870     //  ***** BB04, stmt 1 (top level)
6871     //  [000037] ------------             *  stmtExpr  void  (top level) (IL 0x00A...0x013)
6872     //  [000033] --C - G------ - \--*  call      void   RecursiveMethod
6873     //  [000030] ------------ | / --*  const     int - 1
6874     //  [000031] ------------arg0 in rcx + --*  +int
6875     //  [000029] ------------ | \--*  lclVar    int    V00 arg1
6876     //  [000032] ------------arg1 in rdx    \--*  const     int    1
6877     //
6878     //
6879     //  Basic block after tail recursion elimination :
6880     //  ***** BB04, stmt 1 (top level)
6881     //  [000051] ------------             *  stmtExpr  void  (top level) (IL 0x00A... ? ? ? )
6882     //  [000030] ------------ | / --*  const     int - 1
6883     //  [000031] ------------ | / --*  +int
6884     //  [000029] ------------ | | \--*  lclVar    int    V00 arg1
6885     //  [000050] - A----------             \--* = int
6886     //  [000049] D------N----                \--*  lclVar    int    V02 tmp0
6887     //
6888     //  ***** BB04, stmt 2 (top level)
6889     //  [000055] ------------             *  stmtExpr  void  (top level) (IL 0x00A... ? ? ? )
6890     //  [000052] ------------ | / --*  lclVar    int    V02 tmp0
6891     //  [000054] - A----------             \--* = int
6892     //  [000053] D------N----                \--*  lclVar    int    V00 arg0
6893
6894     //  ***** BB04, stmt 3 (top level)
6895     //  [000058] ------------             *  stmtExpr  void  (top level) (IL 0x00A... ? ? ? )
6896     //  [000032] ------------ | / --*  const     int    1
6897     //  [000057] - A----------             \--* = int
6898     //  [000056] D------N----                \--*  lclVar    int    V01 arg1
6899
6900     GenTreePtr tmpAssignmentInsertionPoint = last;
6901     GenTreePtr paramAssignmentInsertionPoint = last;
6902
6903     // Process early args. They may contain both setup statements for late args and actual args.
6904     // Early args don't include 'this' arg. We need to account for that so that the call to gtArgEntryByArgNum
6905     // below has the correct second argument.
6906     int earlyArgIndex = (thisArg == nullptr) ? 0 : 1;
6907     for (GenTreeArgList* earlyArgs = recursiveTailCall->gtCallArgs;
6908          earlyArgs != nullptr;
6909          (earlyArgIndex++, earlyArgs = earlyArgs->Rest()))
6910     {
6911         GenTreePtr earlyArg = earlyArgs->Current();
6912         if (!earlyArg->IsNothingNode() && !earlyArg->IsArgPlaceHolderNode())
6913         {
6914             if ((earlyArg->gtFlags & GTF_LATE_ARG) != 0)
6915             {
6916                 // This is a setup node so we need to hoist it.
6917                 GenTreePtr earlyArgStmt = gtNewStmt(earlyArg, callILOffset);
6918                 fgInsertStmtBefore(block, earlyArgInsertionPoint, earlyArgStmt);
6919             }
6920             else
6921             {
6922                 // This is an actual argument that needs to be assigned to the corresponding caller parameter.
6923                 fgArgTabEntryPtr curArgTabEntry = gtArgEntryByArgNum(recursiveTailCall, earlyArgIndex);
6924                 GenTreePtr paramAssignStmt = fgAssignRecursiveCallArgToCallerParam(earlyArg, curArgTabEntry, block, callILOffset,
6925                                                                                     tmpAssignmentInsertionPoint, paramAssignmentInsertionPoint);
6926                 if ((tmpAssignmentInsertionPoint == last) && (paramAssignStmt != nullptr))
6927                 {
6928                     // All temp assignments will happen before the first param assignment.
6929                     tmpAssignmentInsertionPoint = paramAssignStmt;
6930                 }
6931             }
6932         }
6933     }
6934
6935     // Process late args.
6936     int lateArgIndex = 0;
6937     for (GenTreeArgList* lateArgs = recursiveTailCall->gtCallLateArgs;
6938          lateArgs != nullptr;
6939          (lateArgIndex++, lateArgs = lateArgs->Rest()))
6940     {
6941         // A late argument is an actual argument that needs to be assigned to the corresponding caller's parameter.
6942         GenTreePtr lateArg = lateArgs->Current();
6943         fgArgTabEntryPtr curArgTabEntry = gtArgEntryByLateArgIndex(recursiveTailCall, lateArgIndex);
6944         GenTreePtr paramAssignStmt = fgAssignRecursiveCallArgToCallerParam(lateArg, curArgTabEntry, block, callILOffset,
6945                                                                            tmpAssignmentInsertionPoint, paramAssignmentInsertionPoint);
6946
6947         if ((tmpAssignmentInsertionPoint == last) && (paramAssignStmt != nullptr))
6948         {
6949             // All temp assignments will happen before the first param assignment.
6950             tmpAssignmentInsertionPoint = paramAssignStmt;
6951         }
6952     }
6953
6954     // If the method has starg.s 0 or ldarga.s 0 a special local (lvaArg0Var) is created so that
6955     // compThisArg stays immutable. Normally it's assigned in fgFirstBBScratch block. Since that
6956     // block won't be in the loop (it's assumed to have no predecessors), we need to update the special local here.
6957     if (!info.compIsStatic && (lvaArg0Var != info.compThisArg))
6958     {
6959         var_types  thisType = lvaTable[info.compThisArg].TypeGet();
6960         GenTreePtr arg0 = gtNewLclvNode(lvaArg0Var, thisType);
6961         GenTreePtr arg0Assignment = gtNewAssignNode(arg0, gtNewLclvNode(info.compThisArg, thisType));
6962         GenTreePtr arg0AssignmentStmt = gtNewStmt(arg0Assignment, callILOffset);
6963         fgInsertStmtBefore(block, paramAssignmentInsertionPoint, arg0AssignmentStmt);
6964     }
6965
6966     // Remove the call
6967     fgRemoveStmt(block, last);
6968
6969     // Set the loop edge.
6970     block->bbJumpKind = BBJ_ALWAYS;
6971     block->bbJumpDest = fgFirstBBisScratch() ? fgFirstBB->bbNext : fgFirstBB;
6972     fgAddRefPred(block->bbJumpDest, block);
6973     block->bbFlags &= ~BBF_HAS_JMP;
6974 }
6975
6976 //------------------------------------------------------------------------------
6977 // fgAssignRecursiveCallArgToCallerParam : Assign argument to a recursive call to the corresponding caller parameter.
6978 //
6979 //
6980 // Arguments:
6981 //    arg  -  argument to assign
6982 //    argTabEntry  -  argument table entry corresponding to arg
6983 //    block  --- basic block the call is in
6984 //    callILOffset  -  IL offset of the call
6985 //    tmpAssignmentInsertionPoint  -  tree before which temp assignment should be inserted (if necessary)
6986 //    paramAssignmentInsertionPoint  -  tree before which parameter assignment should be inserted
6987 //
6988 // Return Value:
6989 //    parameter assignment statement if one was inserted; nullptr otherwise.
6990
6991 GenTreePtr Compiler::fgAssignRecursiveCallArgToCallerParam(GenTreePtr arg,
6992                                                            fgArgTabEntryPtr argTabEntry,
6993                                                            BasicBlock *block,
6994                                                            IL_OFFSETX callILOffset,
6995                                                            GenTreePtr tmpAssignmentInsertionPoint,
6996                                                            GenTreePtr paramAssignmentInsertionPoint)
6997 {
6998     // Call arguments should be assigned to temps first and then the temps should be assigned to parameters because
6999     // some argument trees may reference parameters directly.
7000
7001     GenTreePtr argInTemp = nullptr;
7002     unsigned originalArgNum = argTabEntry->argNum;
7003     bool needToAssignParameter = true;
7004
7005     // TODO-CQ: enable calls with struct arguments passed in registers.
7006     noway_assert(!varTypeIsStruct(arg->TypeGet()));
7007
7008     if ((argTabEntry->isTmp) || arg->IsCnsIntOrI() || arg->IsCnsFltOrDbl())
7009     {
7010         // The argument is already assigned to a temp or is a const.
7011         argInTemp = arg;
7012     }
7013     else if (arg->OperGet() == GT_LCL_VAR)
7014     {
7015         unsigned lclNum = arg->AsLclVar()->gtLclNum;
7016         LclVarDsc * varDsc = &lvaTable[lclNum];
7017         if (!varDsc->lvIsParam)
7018         {
7019             // The argument is a non-parameter local so it doesn't need to be assigned to a temp.
7020             argInTemp = arg;
7021         }
7022         else if (lclNum == originalArgNum)
7023         {
7024             // The argument is the same parameter local that we were about to assign so
7025             // we can skip the assignment.
7026             needToAssignParameter = false;
7027         }
7028     }
7029
7030     // TODO: We don't need temp assignments if we can prove that the argument tree doesn't involve
7031     // any caller parameters. Some common cases are handled above but we may be able to eliminate
7032     // more temp assignments.
7033
7034     GenTreePtr paramAssignStmt = nullptr;
7035     if (needToAssignParameter)
7036     {
7037         if (argInTemp == nullptr)
7038         {
7039             // The argument is not assigned to a temp. We need to create a new temp and insert an assignment.
7040             // TODO: we can avoid a temp assignment if we can prove that the argument tree
7041             // doesn't involve any caller parameters. 
7042             unsigned tmpNum = lvaGrabTemp(true DEBUGARG("arg temp"));
7043             GenTreePtr  tempSrc = arg;
7044             GenTreePtr  tempDest = gtNewLclvNode(tmpNum, tempSrc->gtType);
7045             GenTreePtr tmpAssignNode = gtNewAssignNode(tempDest, tempSrc);
7046             GenTreePtr tmpAssignStmt = gtNewStmt(tmpAssignNode, callILOffset);
7047             fgInsertStmtBefore(block, tmpAssignmentInsertionPoint, tmpAssignStmt);
7048             argInTemp = gtNewLclvNode(tmpNum, tempSrc->gtType);
7049         }
7050
7051         // Now assign the temp to the parameter.
7052         LclVarDsc *paramDsc = lvaTable + originalArgNum;
7053         assert(paramDsc->lvIsParam);
7054         GenTreePtr  paramDest = gtNewLclvNode(originalArgNum, paramDsc->lvType);
7055         GenTreePtr paramAssignNode = gtNewAssignNode(paramDest, argInTemp);
7056         paramAssignStmt = gtNewStmt(paramAssignNode, callILOffset);
7057
7058         fgInsertStmtBefore(block, paramAssignmentInsertionPoint, paramAssignStmt);
7059     }
7060     return paramAssignStmt;
7061 }
7062
7063 /*****************************************************************************
7064  *
7065  *  Transform the given GT_CALL tree for code generation.
7066  */
7067
7068 GenTreePtr          Compiler::fgMorphCall(GenTreeCall* call)
7069 {
7070     if (call->CanTailCall())
7071     {
7072         // It should either be an explicit (i.e. tail prefixed) or an implicit tail call
7073         assert(call->IsTailPrefixedCall() ^ call->IsImplicitTailCall());
7074
7075         // It cannot be an inline candidate
7076         assert(!call->IsInlineCandidate());
7077
7078         const char * szFailReason = nullptr;
7079         bool hasStructParam = false;
7080         if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
7081         {
7082             szFailReason = "Might turn into an intrinsic";
7083         }
7084
7085         if (opts.compNeedSecurityCheck)
7086         {
7087             szFailReason = "Needs security check";
7088         }
7089         else if (compLocallocUsed)
7090         {
7091             szFailReason = "Localloc used";
7092         }
7093 #ifdef _TARGET_AMD64_
7094         // Needed for Jit64 compat.  
7095         // In future, enabling tail calls from methods that need GS cookie check
7096         // would require codegen side work to emit GS cookie check before a tail
7097         // call.
7098         else if (getNeedsGSSecurityCookie())
7099         {
7100             szFailReason = "GS Security cookie check";
7101         }
7102 #endif
7103 #ifdef DEBUG
7104         // DDB 99324: Just disable tailcall under compGcChecks stress mode.
7105         else if (opts.compGcChecks)
7106         {
7107             szFailReason = "GcChecks";
7108         }
7109 #endif
7110 #if FEATURE_TAILCALL_OPT
7111         else
7112         {
7113             // We are still not sure whether it can be a tail call. Because, when converting
7114             // a call to an implicit tail call, we must check that there are no locals with
7115             // their address taken.  If this is the case, we have to assume that the address
7116             // has been leaked and the current stack frame must live until after the final
7117             // call.
7118
7119             // Verify that none of vars has lvHasLdAddrOp or lvAddrExposed bit set. Note 
7120             // that lvHasLdAddrOp is much more conservative.  We cannot just base it on
7121             // lvAddrExposed alone since it is not guaranteed to be set on all VarDscs
7122             // during morph stage. The reason for also checking lvAddrExposed is that in case
7123             // of vararg methods user args are marked as addr exposed but not lvHasLdAddrOp.
7124             // The combination of lvHasLdAddrOp and lvAddrExposed though conservative allows us
7125             // never to be incorrect.
7126             //
7127             // TODO-Throughput: have a compiler level flag to indicate whether method has vars whose
7128             // address is taken. Such a flag could be set whenever lvHasLdAddrOp or LvAddrExposed
7129             // is set. This avoids the need for iterating through all lcl vars of the current 
7130             // method.  Right now throughout the code base we are not consistently using 'set' 
7131             // method to set lvHasLdAddrOp and lvAddrExposed flags.
7132             unsigned varNum;
7133             LclVarDsc *varDsc;
7134             bool hasAddrExposedVars = false;
7135             bool hasStructPromotedParam = false;
7136             bool hasPinnedVars = false;
7137
7138             for (varNum = 0, varDsc = lvaTable; varNum < lvaCount; varNum++, varDsc++)
7139             {
7140                 // If the method is marked as an explicit tail call we will skip the
7141                 // following three hazard checks.
7142                 // We still must check for any struct parameters and set 'hasStructParam'
7143                 // so that we won't transform the recursive tail call into a loop.
7144                 // 
7145                 if (call->IsImplicitTailCall())
7146                 {
7147                     if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
7148                     {
7149                         hasAddrExposedVars = true;
7150                         break;
7151                     }
7152                     if (varDsc->lvPromoted && varDsc->lvIsParam)
7153                     {
7154                         hasStructPromotedParam = true;
7155                         break;
7156                     }
7157                     if (varDsc->lvPinned)
7158                     {
7159                         // A tail call removes the method from the stack, which means the pinning
7160                         // goes away for the callee.  We can't allow that.
7161                         hasPinnedVars = true;
7162                         break;
7163                     }
7164                 }
7165                 if (varTypeIsStruct(varDsc->TypeGet()) && varDsc->lvIsParam)
7166                 {
7167                     hasStructParam = true;
7168                     // This prevents transforming a recursive tail call into a loop
7169                     // but doesn't prevent tail call optimization so we need to
7170                     // look at the rest of parameters.
7171                     continue;
7172                 }
7173             }
7174
7175             if (hasAddrExposedVars)
7176             {
7177                 szFailReason = "Local address taken";
7178             }
7179             if (hasStructPromotedParam)
7180             {
7181                 szFailReason = "Has Struct Promoted Param";
7182             }
7183             if (hasPinnedVars)
7184             {
7185                 szFailReason = "Has Pinned Vars";
7186             }
7187         }
7188 #endif // FEATURE_TAILCALL_OPT
7189
7190         fgFixupStructReturn(call);
7191
7192         var_types   callType = call->TypeGet();
7193
7194         // We have to ensure to pass the incoming retValBuf as the
7195         // outgoing one. Using a temp will not do as this function will
7196         // not regain control to do the copy. 
7197
7198         if (info.compRetBuffArg != BAD_VAR_NUM)
7199         {
7200             noway_assert(callType == TYP_VOID);
7201             GenTreePtr retValBuf = call->gtCallArgs->gtOp.gtOp1;
7202             if (retValBuf->gtOper != GT_LCL_VAR ||
7203                 retValBuf->gtLclVarCommon.gtLclNum != info.compRetBuffArg)
7204             {
7205                 szFailReason = "Need to copy return buffer";
7206             }
7207         }
7208
7209         // If this is an opportunistic tail call and cannot be dispatched as
7210         // fast tail call, go the non-tail call route.  This is done for perf
7211         // reason.
7212         //
7213         // Avoid the cost of determining whether can be dispatched as fast tail
7214         // call if we already know that tail call cannot be honored for other
7215         // reasons.
7216         bool canFastTailCall = false;
7217         if (szFailReason == nullptr)
7218         {
7219             canFastTailCall = fgCanFastTailCall(call);
7220             if (!canFastTailCall)
7221             {
7222                 // Implicit or opportunistic tail calls are always dispatched via fast tail call
7223                 // mechanism and never via tail call helper for perf.
7224                 if (call->IsImplicitTailCall())
7225                 {
7226                     szFailReason = "Opportunistic tail call cannot be dispatched as epilog+jmp";
7227                 }
7228 #ifndef LEGACY_BACKEND
7229                 else if (!call->IsVirtualStub() && call->HasNonStandardArgs())
7230                 {
7231                     // If we are here, it means that the call is an explicitly ".tail" prefixed and cannot be
7232                     // dispatched as a fast tail call.
7233
7234                     // Methods with non-standard args will have indirection cell or cookie param passed
7235                     // in callee trash register (e.g. R11). Tail call helper doesn't preserve it before
7236                     // tail calling the target method and hence ".tail" prefix on such calls needs to be
7237                     // ignored.
7238                     //
7239                     // Exception to the above rule: although Virtual Stub Dispatch (VSD) calls though require
7240                     // extra stub param (e.g. in R11 on Amd64), they can still be called via tail call helper. 
7241                     // This is done by by adding stubAddr as an additional arg before the original list of 
7242                     // args. For more details see fgMorphTailCall() and CreateTailCallCopyArgsThunk()
7243                     // in Stublinkerx86.cpp.
7244                     szFailReason = "Method with non-standard args passed in callee trash register cannot be tail called via helper";
7245                 }
7246 #ifdef _TARGET_ARM64_
7247                 else
7248                 {
7249                     // NYI - TAILCALL_RECURSIVE/TAILCALL_HELPER.
7250                     // So, bail out if we can't make fast tail call.
7251                     szFailReason = "Non-qualified fast tail call";
7252                 }
7253 #endif
7254 #endif //LEGACY_BACKEND
7255             }
7256         }
7257
7258         // Clear these flags before calling fgMorphCall() to avoid recursion.
7259         bool isTailPrefixed = call->IsTailPrefixedCall();
7260         call->gtCallMoreFlags &= ~GTF_CALL_M_EXPLICIT_TAILCALL;
7261
7262 #if FEATURE_TAILCALL_OPT
7263         call->gtCallMoreFlags &= ~GTF_CALL_M_IMPLICIT_TAILCALL;
7264 #endif
7265         
7266 #ifdef FEATURE_PAL
7267         if (!canFastTailCall && szFailReason == nullptr)
7268         {
7269             szFailReason = "Non fast tail calls disabled for PAL based systems.";
7270         }
7271 #endif // FEATURE_PAL
7272
7273         if (szFailReason != nullptr)
7274         {
7275 #ifdef DEBUG
7276             if (verbose) {
7277                 printf("\nRejecting tail call late for call ");
7278                 printTreeID(call);
7279                 printf(": %s\n", szFailReason);
7280             }
7281 #endif
7282
7283             // for non user funcs, we have no handles to report
7284             info.compCompHnd->reportTailCallDecision(nullptr,
7285                 (call->gtCallType == CT_USER_FUNC) ? call->gtCallMethHnd : nullptr,
7286                 isTailPrefixed, TAILCALL_FAIL, szFailReason);
7287
7288             goto NO_TAIL_CALL;
7289         }
7290
7291 #if !FEATURE_TAILCALL_OPT_SHARED_RETURN
7292         // We enable shared-ret tail call optimization for recursive calls even if
7293         // FEATURE_TAILCALL_OPT_SHARED_RETURN is not defined.
7294         if (gtIsRecursiveCall(call))
7295 #endif
7296         {
7297             // Many tailcalls will have call and ret in the same block, and thus be BBJ_RETURN,
7298             // but if the call falls through to a ret, and we are doing a tailcall, change it here.
7299             if (compCurBB->bbJumpKind != BBJ_RETURN)
7300                 compCurBB->bbJumpKind = BBJ_RETURN;
7301
7302         }
7303
7304         // Set this flag before calling fgMorphCall() to prevent inlining this call.
7305         call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL;
7306
7307         bool fastTailCallToLoop = false;
7308 #if FEATURE_TAILCALL_OPT
7309         // TODO-CQ: enable the transformation when the method has a struct parameter that can be passed in a register
7310         // or return type is a struct that can be passed in a register.
7311         //
7312         // TODO-CQ: if the method being compiled requires generic context reported in gc-info (either through
7313         // hidden generic context param or through keep alive thisptr), then while transforming a recursive
7314         // call to such a method requires that the generic context stored on stack slot be updated.  Right now,
7315         // fgMorphRecursiveFastTailCallIntoLoop() is not handling update of generic context while transforming
7316         // a recursive call into a loop.  Another option is to modify gtIsRecursiveCall() to check that the
7317         // generic type parameters of both caller and callee generic method are the same.
7318         if (opts.compTailCallLoopOpt &&
7319             canFastTailCall &&
7320             gtIsRecursiveCall(call) &&
7321             !lvaReportParamTypeArg() &&
7322             !lvaKeepAliveAndReportThis() &&
7323             !call->IsVirtual() &&
7324             !hasStructParam &&
7325             !varTypeIsStruct(call->TypeGet()))
7326         {
7327             call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL_TO_LOOP;
7328             fastTailCallToLoop = true;
7329         }
7330 #endif
7331
7332         // Do some target-specific transformations (before we process the args, etc.)
7333         // This is needed only for tail prefixed calls that cannot be dispatched as
7334         // fast calls.
7335         if (!canFastTailCall)
7336         {
7337             fgMorphTailCall(call);
7338         }
7339
7340         // Implementation note : If we optimize tailcall to do a direct jump
7341         // to the target function (after stomping on the return address, etc),
7342         // without using CORINFO_HELP_TAILCALL, we have to make certain that
7343         // we don't starve the hijacking logic (by stomping on the hijacked
7344         // return address etc).
7345
7346         // At this point, we are committed to do the tailcall.
7347         compTailCallUsed = true;
7348
7349         CorInfoTailCall tailCallResult;
7350
7351         if (fastTailCallToLoop)
7352         {
7353             tailCallResult = TAILCALL_RECURSIVE;
7354         }
7355         else if (canFastTailCall)
7356         {
7357             tailCallResult = TAILCALL_OPTIMIZED;
7358         }
7359         else
7360         {
7361             tailCallResult = TAILCALL_HELPER;
7362         }
7363
7364         // for non user funcs, we have no handles to report
7365         info.compCompHnd->reportTailCallDecision(nullptr,
7366                                                  (call->gtCallType == CT_USER_FUNC) ? call->gtCallMethHnd : nullptr,
7367                                                  isTailPrefixed, 
7368                                                  tailCallResult,
7369                                                  nullptr);
7370
7371         // As we will actually call CORINFO_HELP_TAILCALL, set the callTyp to TYP_VOID.
7372         // to avoid doing any extra work for the return value.
7373         call->gtType = TYP_VOID;
7374
7375 #ifdef DEBUG
7376         if (verbose)
7377         {
7378             printf("\nGTF_CALL_M_TAILCALL bit set for call ");
7379             printTreeID(call);
7380             printf("\n");
7381             if (fastTailCallToLoop)
7382             {
7383                 printf("\nGTF_CALL_M_TAILCALL_TO_LOOP bit set for call ");
7384                 printTreeID(call);
7385                 printf("\n");
7386             }
7387         }
7388 #endif
7389
7390         
7391         GenTreePtr stmtExpr = fgMorphStmt->gtStmt.gtStmtExpr; 
7392         
7393 #ifdef DEBUG
7394         // Tail call needs to be in one of the following IR forms
7395         //    Either a call stmt or
7396         //    GT_RETURN(GT_CALL(..)) or 
7397         //    var = call
7398         noway_assert((stmtExpr->gtOper == GT_CALL && stmtExpr == call) ||   
7399                      (stmtExpr->gtOper == GT_RETURN && (stmtExpr->gtOp.gtOp1 == call || stmtExpr->gtOp.gtOp1->gtOp.gtOp1 == call)) || 
7400                      (stmtExpr->gtOper == GT_ASG && stmtExpr->gtOp.gtOp2 == call));  
7401 #endif
7402
7403         // For void calls, we would have created a GT_CALL in the stmt list.
7404         // For non-void calls, we would have created a GT_RETURN(GT_CAST(GT_CALL)).
7405         // For calls returning structs, we would have a void call, followed by a void return.
7406         // For debuggable code, it would be an assignment of the call to a temp
7407         // We want to get rid of any of this extra trees, and just leave
7408         // the call.
7409         GenTreePtr nextMorphStmt = fgMorphStmt->gtNext;
7410
7411 #ifdef _TARGET_AMD64_
7412         // Legacy Jit64 Compat:
7413         // There could be any number of GT_NOPs between tail call and GT_RETURN.
7414         // That is tail call pattern could be one of the following:
7415         //  1) tail.call, nop*, ret 
7416         //  2) tail.call, nop*, pop, nop*, ret  
7417         //  3) var=tail.call, nop*, ret(var) 
7418         //  4) var=tail.call, nop*, pop, ret
7419         //
7420         // See impIsTailCallILPattern() for details on tail call IL patterns
7421         // that are supported.
7422         if ((stmtExpr->gtOper == GT_CALL) || (stmtExpr->gtOper == GT_ASG))
7423         {
7424             // First delete all GT_NOPs after the call
7425             GenTreePtr morphStmtToRemove = nullptr;
7426             while (nextMorphStmt != nullptr)
7427             {
7428                 GenTreePtr nextStmtExpr = nextMorphStmt->gtStmt.gtStmtExpr;
7429                 if (!nextStmtExpr->IsNothingNode())
7430                 {
7431                     break;
7432                 }
7433
7434                 morphStmtToRemove = nextMorphStmt;
7435                 nextMorphStmt = morphStmtToRemove->gtNext;
7436                 fgRemoveStmt(compCurBB, morphStmtToRemove);
7437             }
7438
7439             // Check to see if there is a pop.
7440             // Since tail call is honored, we can get rid of the stmt corresponding to pop.
7441             if (nextMorphStmt != nullptr && nextMorphStmt->gtStmt.gtStmtExpr->gtOper != GT_RETURN)
7442             {                
7443                 // Note that pop opcode may or may not result in a new stmt (for details see
7444                 // impImportBlockCode()). Hence, it is not possible to assert about the IR
7445                 // form generated by pop but pop tree must be side-effect free so that we can
7446                 // delete it safely.
7447                 GenTreePtr popStmt = nextMorphStmt;
7448                 nextMorphStmt = nextMorphStmt->gtNext;
7449
7450                 noway_assert((popStmt->gtStmt.gtStmtExpr->gtFlags & GTF_ALL_EFFECT) == 0);
7451                 fgRemoveStmt(compCurBB, popStmt);
7452             }
7453
7454             // Next delete any GT_NOP nodes after pop
7455             while (nextMorphStmt != nullptr)
7456             {
7457                 GenTreePtr nextStmtExpr = nextMorphStmt->gtStmt.gtStmtExpr;
7458                 if (!nextStmtExpr->IsNothingNode())
7459                 {
7460                     break;
7461                 }
7462
7463                 morphStmtToRemove = nextMorphStmt;
7464                 nextMorphStmt = morphStmtToRemove->gtNext;
7465                 fgRemoveStmt(compCurBB, morphStmtToRemove);
7466             }
7467         }
7468 #endif // _TARGET_AMD64_
7469
7470         // Delete GT_RETURN  if any
7471         if (nextMorphStmt != nullptr)
7472         {
7473             GenTreePtr retExpr = nextMorphStmt->gtStmt.gtStmtExpr;
7474             noway_assert(retExpr->gtOper == GT_RETURN);
7475
7476             // If var=call, then the next stmt must be a GT_RETURN(TYP_VOID) or GT_RETURN(var).
7477             // This can occur if impSpillStackEnsure() has introduced an assignment to a temp.
7478             if (stmtExpr->gtOper == GT_ASG && info.compRetType != TYP_VOID)
7479             {                
7480                 noway_assert(stmtExpr->gtGetOp1()->OperIsLocal());
7481                 noway_assert(stmtExpr->gtGetOp1()->AsLclVarCommon()->gtLclNum == retExpr->gtGetOp1()->AsLclVarCommon()->gtLclNum);
7482             }
7483
7484             fgRemoveStmt(compCurBB, nextMorphStmt);
7485         }
7486
7487         fgMorphStmt->gtStmt.gtStmtExpr = call;
7488
7489         // Tail call via helper: The VM can't use return address hijacking if we're
7490         // not going to return and the helper doesn't have enough info to safely poll,
7491         // so we poll before the tail call, if the block isn't already safe.  Since
7492         // tail call via helper is a slow mechanism it doen't matter whether we emit
7493         // GC poll.  This is done to be in parity with Jit64. Also this avoids GC info
7494         // size increase if all most all methods are expected to be tail calls (e.g. F#).
7495         //
7496         // Note that we can avoid emitting GC-poll if we know that the current BB is
7497         // dominated by a Gc-SafePoint block.  But we don't have dominator info at this
7498         // point.  One option is to just add a place holder node for GC-poll (e.g. GT_GCPOLL)
7499         // here and remove it in lowering if the block is dominated by a GC-SafePoint.  For
7500         // now it not clear whether optimizing slow tail calls is worth the effort.  As a 
7501         // low cost check, we check whether the first and current basic blocks are 
7502         // GC-SafePoints.
7503         //
7504         // Fast Tail call as epilog+jmp - No need to insert GC-poll. Instead, fgSetBlockOrder()
7505         // is going to mark the method as fully interruptible if the block containing this tail
7506         // call is reachable without executing any call.
7507         if (canFastTailCall ||   
7508             (fgFirstBB->bbFlags & BBF_GC_SAFE_POINT) ||
7509             (compCurBB->bbFlags & BBF_GC_SAFE_POINT) || 
7510             !fgCreateGCPoll(GCPOLL_INLINE, compCurBB))
7511         {
7512             // We didn't insert a poll block, so we need to morph the call now
7513             // (Normally it will get morphed when we get to the split poll block)
7514             GenTreePtr temp = fgMorphCall(call);
7515             noway_assert(temp == call);
7516         }
7517
7518         // Tail call via helper: we just call CORINFO_HELP_TAILCALL, and it jumps to
7519         // the target. So we don't need an epilog - just like CORINFO_HELP_THROW.
7520         //
7521         // Fast tail call: in case of fast tail calls, we need a jmp epilog and
7522         // hence mark it as BBJ_RETURN with BBF_JMP flag set.
7523         noway_assert(compCurBB->bbJumpKind == BBJ_RETURN);
7524
7525         if (canFastTailCall)
7526         {
7527             compCurBB->bbFlags |= BBF_HAS_JMP;
7528         }
7529         else
7530         {
7531             compCurBB->bbJumpKind = BBJ_THROW;
7532         }
7533
7534         // For non-void calls, we return a place holder which will be
7535         // used by the parent GT_RETURN node of this call. 
7536
7537         GenTree* result = call;
7538         if (callType != TYP_VOID && info.compRetType != TYP_VOID)
7539         {
7540 #ifdef FEATURE_HFA
7541             // Return a dummy node, as the return is already removed.
7542             if (callType == TYP_STRUCT)
7543             {
7544                 // This is a HFA, use float 0.
7545                 callType = TYP_FLOAT;
7546             }
7547 #elif defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
7548             // Return a dummy node, as the return is already removed.
7549             if (varTypeIsStruct(callType))
7550             {
7551                 // This is a register-returned struct. Return a 0.
7552                 // The actual return registers are hacked in lower and the register allocator.
7553                 callType = TYP_INT;
7554             }
7555 #endif
7556 #ifdef FEATURE_SIMD
7557             // Return a dummy node, as the return is already removed.
7558             if (varTypeIsSIMD(callType))
7559             {
7560                 callType = TYP_DOUBLE;
7561             }
7562 #endif
7563             result = gtNewZeroConNode(genActualType(callType));
7564             result = fgMorphTree(result);
7565         }
7566
7567         return result;
7568     }
7569
7570 NO_TAIL_CALL:
7571
7572     if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0        &&
7573         (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR)
7574 #ifdef FEATURE_READYTORUN_COMPILER
7575         || call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR)
7576 #endif
7577         ) &&
7578         (call == fgMorphStmt->gtStmt.gtStmtExpr))
7579     {
7580         // This is call to CORINFO_HELP_VIRTUAL_FUNC_PTR with ignored result.
7581         // Transform it into a null check.
7582
7583         GenTreePtr thisPtr = call->gtCallArgs->gtOp.gtOp1;
7584
7585         GenTreePtr nullCheck = gtNewOperNode(GT_IND, TYP_I_IMPL, thisPtr);
7586         nullCheck->gtFlags |= GTF_EXCEPT;
7587
7588         return fgMorphTree(nullCheck);
7589     }
7590
7591     noway_assert(call->gtOper == GT_CALL);
7592
7593     //
7594     // Only count calls once (only in the global morph phase)
7595     //
7596     if (fgGlobalMorph)
7597     {
7598         if (call->gtCallType == CT_INDIRECT)
7599         {
7600             optCallCount++;
7601             optIndirectCallCount++;
7602         }
7603         else if (call->gtCallType == CT_USER_FUNC)
7604         {
7605             optCallCount++;
7606             if (call->IsVirtual())
7607                 optIndirectCallCount++;
7608         }
7609     }
7610
7611     // Couldn't inline - remember that this BB contains method calls
7612
7613     // If this is a 'regular' call, mark the basic block as
7614     // having a call (for computing full interruptibility).
7615     //
7616     // Amd64 note: If this is a fast tail call then don't count it as a call
7617     // since we don't insert GC-polls but instead make the method fully GC
7618     // interruptible.
7619 #ifdef _TARGET_AMD64_
7620     if (!call->IsFastTailCall())
7621 #endif
7622     {
7623         if (call->gtCallType == CT_INDIRECT)
7624         {
7625             compCurBB->bbFlags |= BBF_GC_SAFE_POINT;
7626         }
7627         else if (call->gtCallType == CT_USER_FUNC)
7628         {
7629             if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
7630                 compCurBB->bbFlags |= BBF_GC_SAFE_POINT;
7631         }
7632         // otherwise we have a CT_HELPER
7633     }
7634
7635     // Morph Type.op_Equality and Type.op_Inequality
7636     // We need to do this before the arguments are morphed
7637     if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC))
7638     {
7639         CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
7640
7641         genTreeOps simpleOp = GT_CALL;
7642         if (methodID == CORINFO_INTRINSIC_TypeEQ)
7643             simpleOp = GT_EQ;
7644         else if (methodID == CORINFO_INTRINSIC_TypeNEQ)
7645             simpleOp = GT_NE;
7646
7647         if (simpleOp == GT_EQ || simpleOp == GT_NE)
7648         {
7649             noway_assert(call->TypeGet() == TYP_INT);
7650
7651             // Check for GetClassFromHandle(handle) and obj.GetType() both of which will only return RuntimeType objects.
7652             // Then if either operand is one of these two calls we can simplify op_Equality/op_Inequality to GT_NE/GT_NE:
7653             // One important invariance that should never change is that type equivalency is always equivalent to object
7654             // identity equality for runtime type objects in reflection. This is also reflected in RuntimeTypeHandle::TypeEquals.
7655             // If this invariance would ever be broken, we need to remove the optimization below.
7656
7657             GenTreePtr op1 = call->gtCallArgs->gtOp.gtOp1;
7658             GenTreePtr op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
7659
7660             if (gtCanOptimizeTypeEquality(op1) || gtCanOptimizeTypeEquality(op2))
7661             {
7662                 GenTreePtr compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
7663
7664                 // fgMorphSmpOp will further optimize the following patterns:
7665                 //  1. typeof(...) == typeof(...)
7666                 //  2. typeof(...) == obj.GetType()
7667                 return fgMorphTree(compare);
7668             }
7669         }
7670     }
7671
7672     // Make sure that return buffers containing GC pointers that aren't too large are pointers into the stack.
7673     GenTreePtr origDest = nullptr; // Will only become non-null if we do the transformation (and thus require copy-back).
7674     unsigned retValTmpNum = BAD_VAR_NUM;
7675     CORINFO_CLASS_HANDLE structHnd = nullptr;
7676     if (call->HasRetBufArg() &&
7677         call->gtCallLateArgs == nullptr)  // Don't do this if we're re-morphing (which will make late args non-null).
7678     {
7679         // We're enforcing the invariant that return buffers pointers (at least for
7680         // struct return types containing GC pointers) are never pointers into the heap.
7681         // The large majority of cases are address of local variables, which are OK.
7682         // Otherwise, allocate a local of the given struct type, pass its address,
7683         // then assign from that into the proper destination.  (We don't need to do this
7684         // if we're passing the caller's ret buff arg to the callee, since the caller's caller
7685         // will maintain the same invariant.)
7686
7687         GenTreePtr dest = call->gtCallArgs->gtOp.gtOp1;
7688         assert(dest->OperGet() != GT_ARGPLACE); // If it was, we'd be in a remorph, which we've already excluded above.
7689         if (dest->gtType == TYP_BYREF
7690             && !(dest->OperGet() == GT_ADDR && dest->gtOp.gtOp1->OperGet() == GT_LCL_VAR))
7691         {
7692             // We'll exempt helper calls from this, assuming that the helper implementation
7693             // follows the old convention, and does whatever barrier is required.
7694             if (call->gtCallType != CT_HELPER)
7695             {
7696                 structHnd = call->gtRetClsHnd;
7697                 if (info.compCompHnd->isStructRequiringStackAllocRetBuf(structHnd)
7698                     && !((dest->OperGet() == GT_LCL_VAR || dest->OperGet() == GT_REG_VAR)
7699                          && dest->gtLclVar.gtLclNum == info.compRetBuffArg))
7700                 {
7701                     origDest = dest;
7702
7703                     retValTmpNum = lvaGrabTemp(true DEBUGARG("substitute local for ret buff arg"));
7704                     lvaSetStruct(retValTmpNum, structHnd, true);
7705                     dest = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(retValTmpNum, TYP_STRUCT));
7706                 }
7707             }
7708         }
7709
7710         call->gtCallArgs->gtOp.gtOp1 = dest;
7711     }
7712
7713     /* Process the "normal" argument list */
7714     call = fgMorphArgs(call);
7715
7716     // Optimize get_ManagedThreadId(get_CurrentThread)
7717     noway_assert(call->gtOper == GT_CALL);
7718
7719     // Morph stelem.ref helper call to store a null value, into a store into an array without the helper.
7720     // This needs to be done after the arguments are morphed to ensure constant propagation has already taken place.
7721     if ((call->gtCallType == CT_HELPER) && (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ARRADDR_ST)))
7722     {       
7723         GenTreePtr value = gtArgEntryByArgNum(call, 2)->node;
7724
7725         if (value->OperGet() == GT_CNS_INT && value->AsIntConCommon()->IconValue() == 0)
7726         {
7727             GenTreePtr arr = gtArgEntryByArgNum(call, 0)->node;
7728             GenTreePtr index = gtArgEntryByArgNum(call, 1)->node;
7729
7730             arr = gtClone(arr, true);
7731             if (arr != nullptr)
7732             {
7733                 index = gtClone(index, true);
7734                 if (index != nullptr)
7735                 {
7736                     value = gtClone(value);
7737                     noway_assert(value != nullptr);
7738
7739                     GenTreePtr nullCheckedArr = impCheckForNullPointer(arr);
7740                     GenTreePtr arrIndexNode = gtNewIndexRef(TYP_REF, nullCheckedArr, index);
7741                     GenTreePtr arrStore = gtNewAssignNode(arrIndexNode, value);
7742                     arrStore->gtFlags |= GTF_ASG;
7743
7744                     return fgMorphTree(arrStore);
7745                 }                
7746             }
7747         }
7748     }
7749
7750     if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) &&
7751            info.compCompHnd->getIntrinsicID(call->gtCallMethHnd) == CORINFO_INTRINSIC_GetManagedThreadId)
7752     {
7753         noway_assert(origDest == NULL);
7754         noway_assert(call->gtCallLateArgs->gtOp.gtOp1 != NULL);
7755
7756         GenTreePtr innerCall = call->gtCallLateArgs->gtOp.gtOp1;
7757
7758         if (innerCall->gtOper == GT_CALL &&
7759             (innerCall->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) &&
7760             info.compCompHnd->getIntrinsicID(innerCall->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_GetCurrentManagedThread)
7761         {
7762             // substitute expression with call to helper
7763             GenTreePtr newCall = gtNewHelperCallNode(CORINFO_HELP_GETCURRENTMANAGEDTHREADID, TYP_INT, 0);
7764             JITDUMP("get_ManagedThreadId(get_CurrentThread) folding performed\n");
7765             return fgMorphTree(newCall);
7766         }
7767     }
7768
7769     if (origDest != NULL)
7770     {
7771         GenTreePtr retValVarAddr = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(retValTmpNum, TYP_STRUCT));
7772         // If the origDest expression was an assignment to a variable, it might be to an otherwise-unused
7773         // var, which would allow the whole assignment to be optimized away to a NOP.  So in that case, make the
7774         // origDest into a comma that uses the var.  Note that the var doesn't have to be a temp for this to
7775         // be correct.
7776         if (origDest->OperGet() == GT_ASG)
7777         {
7778             if (origDest->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
7779             {
7780                 GenTreePtr var = origDest->gtOp.gtOp1;
7781                 origDest = gtNewOperNode(GT_COMMA, var->TypeGet(), origDest,
7782                                          gtNewLclvNode(var->gtLclVar.gtLclNum, var->TypeGet()));
7783             }
7784         }
7785         GenTreePtr copyBlk = gtNewCpObjNode(origDest, retValVarAddr, structHnd, false);
7786         copyBlk = fgMorphTree(copyBlk);
7787         GenTree* result = gtNewOperNode(GT_COMMA, TYP_VOID, call, copyBlk);
7788 #ifdef DEBUG
7789         result->gtFlags |= GTF_MORPHED;
7790 #endif
7791         return result;
7792     }
7793
7794
7795     return call;
7796 }
7797
7798 /*****************************************************************************
7799  *
7800  *  Transform the given GTK_CONST tree for code generation.
7801  */
7802
7803 GenTreePtr          Compiler::fgMorphConst(GenTreePtr tree)
7804 {
7805     noway_assert(tree->OperKind() & GTK_CONST);
7806
7807     /* Clear any exception flags or other unnecessary flags
7808      * that may have been set before folding this node to a constant */
7809
7810     tree->gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS);
7811
7812     if  (tree->OperGet() != GT_CNS_STR)
7813         return tree;
7814
7815     // TODO-CQ: Do this for compCurBB->isRunRarely(). Doing that currently will
7816     // guarantee slow performance for that block. Instead cache the return value
7817     // of CORINFO_HELP_STRCNS and go to cache first giving reasonable perf.
7818
7819     if (compCurBB->bbJumpKind == BBJ_THROW)
7820     {
7821         CorInfoHelpFunc helper = info.compCompHnd->getLazyStringLiteralHelper(tree->gtStrCon.gtScpHnd);
7822         if (helper != CORINFO_HELP_UNDEF)
7823         {
7824             // For un-important blocks, we want to construct the string lazily
7825
7826             GenTreeArgList *args;
7827             if (helper == CORINFO_HELP_STRCNS_CURRENT_MODULE)
7828             {
7829                 args = gtNewArgList(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT));
7830             }
7831             else
7832             {
7833                 args = gtNewArgList(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT),
7834                     gtNewIconEmbScpHndNode(tree->gtStrCon.gtScpHnd));
7835             }
7836
7837
7838             tree = gtNewHelperCallNode(helper, TYP_REF, 0, args);
7839             return fgMorphTree(tree);
7840         }
7841     }
7842
7843     assert(tree->gtStrCon.gtScpHnd == info.compScopeHnd || !IsUninitialized(tree->gtStrCon.gtScpHnd));
7844
7845     LPVOID pValue;
7846     InfoAccessType iat = info.compCompHnd->constructStringLiteral(tree->gtStrCon.gtScpHnd,
7847                                                          tree->gtStrCon.gtSconCPX,
7848                                                          &pValue);
7849
7850     tree = gtNewStringLiteralNode(iat, pValue);
7851
7852     return fgMorphTree(tree);
7853 }
7854
7855 /*****************************************************************************
7856  *
7857  *  Transform the given GTK_LEAF tree for code generation.
7858  */
7859
7860 GenTreePtr          Compiler::fgMorphLeaf(GenTreePtr tree)
7861 {
7862     noway_assert(tree->OperKind() & GTK_LEAF);
7863
7864     if (tree->gtOper == GT_LCL_VAR)
7865     {
7866         return fgMorphLocalVar(tree);
7867     }
7868 #ifdef _TARGET_X86_
7869     else if (tree->gtOper == GT_LCL_FLD)
7870     {
7871         if (info.compIsVarArgs)
7872         {
7873             GenTreePtr newTree = fgMorphStackArgForVarArgs(tree->gtLclFld.gtLclNum, tree->gtType, tree->gtLclFld.gtLclOffs);
7874             if (newTree != NULL)
7875                 return newTree;
7876         }
7877     }
7878 #endif // _TARGET_X86_
7879     else if (tree->gtOper == GT_FTN_ADDR)
7880     {
7881         CORINFO_CONST_LOOKUP addrInfo;
7882
7883 #ifdef FEATURE_READYTORUN_COMPILER
7884         if (tree->gtFptrVal.gtEntryPoint.addr != nullptr)
7885         {
7886             addrInfo = tree->gtFptrVal.gtEntryPoint;
7887         }
7888         else
7889 #endif
7890         {
7891             info.compCompHnd->getFunctionFixedEntryPoint(tree->gtFptrVal.gtFptrMethod, &addrInfo);
7892         }
7893
7894         // Refer to gtNewIconHandleNode() as the template for constructing a constant handle
7895         //
7896         tree->SetOper(GT_CNS_INT);
7897         tree->gtIntConCommon.SetIconValue(ssize_t(addrInfo.handle));
7898         tree->gtFlags |= GTF_ICON_FTN_ADDR;
7899
7900         switch (addrInfo.accessType)
7901         {
7902         case IAT_PPVALUE:
7903             tree           = gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
7904             tree->gtFlags |= GTF_IND_INVARIANT;
7905
7906             __fallthrough;
7907
7908         case IAT_PVALUE:
7909             tree           = gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
7910             break;
7911
7912         case IAT_VALUE:
7913             tree = gtNewOperNode(GT_NOP, tree->TypeGet(), tree); // prevents constant folding
7914             break;
7915
7916         default:
7917             noway_assert(!"Unknown addrInfo.accessType");
7918         }
7919
7920         return fgMorphTree(tree);
7921     }
7922
7923     return tree;
7924 }
7925
7926
7927 void Compiler::fgAssignSetVarDef(GenTreePtr tree)
7928 {
7929     GenTreeLclVarCommon* lclVarCmnTree;
7930     bool isEntire = false;
7931     if (tree->DefinesLocal(this, &lclVarCmnTree, &isEntire))
7932     {
7933         if (isEntire)
7934         {
7935             lclVarCmnTree->gtFlags |= GTF_VAR_DEF;
7936         }
7937         else
7938         {
7939             // We consider partial definitions to be modeled as uses followed by definitions.
7940             // This captures the idea that precedings defs are not necessarily made redundant
7941             // by this definition.
7942             lclVarCmnTree->gtFlags |= (GTF_VAR_DEF | GTF_VAR_USEASG);
7943         }
7944     }
7945 }
7946
7947 GenTreePtr Compiler::fgMorphOneAsgBlockOp(GenTreePtr tree)
7948 {
7949     genTreeOps     oper = tree->gtOper;
7950
7951     // Only xxBlk opcodes are possible
7952     noway_assert(tree->OperIsBlkOp());
7953
7954     GenTreePtr  dest      = tree->gtOp.gtOp1->gtOp.gtOp1;   // Dest address
7955     GenTreePtr  src       = tree->gtOp.gtOp1->gtOp.gtOp2;   // Src
7956     GenTreePtr  blkShape  = tree->gtOp.gtOp2;               // [size/clsHnd]
7957     bool        volatil   = tree->AsBlkOp()->IsVolatile();
7958     GenTreePtr  result;
7959     GenTreePtr  lclVarTree;
7960
7961     // The dest must be an address
7962     noway_assert(genActualType(dest->gtType) == TYP_I_IMPL  ||
7963            dest->gtType  == TYP_BYREF);
7964
7965     // For COPYBLK the src must be an address
7966     noway_assert(!tree->OperIsCopyBlkOp() ||
7967                  (genActualType( src->gtType) == TYP_I_IMPL ||
7968                   src->gtType  == TYP_BYREF));
7969
7970     // For INITBLK the src must be a TYP_INT
7971     noway_assert(oper != GT_INITBLK ||
7972            (genActualType( src->gtType) == TYP_INT));
7973
7974     // The size must be an integer type
7975     noway_assert(varTypeIsIntegral(blkShape->gtType));
7976
7977     CORINFO_CLASS_HANDLE  clsHnd;
7978     size_t                size;
7979     var_types             type    = TYP_UNDEF;
7980
7981     if (blkShape->gtOper != GT_CNS_INT)
7982         goto GENERAL_BLKOP;
7983
7984 #ifdef FEATURE_SIMD
7985     // importer introduces cpblk nodes with src = GT_ADDR(GT_SIMD) 
7986     // The SIMD type in question could be Vector2f which is 8-bytes in size.
7987     // The below check is to make sure that we don't turn that copyblk
7988     // into a assignment, since rationalizer logic will transform the
7989     // copyblk apropriately. Otherwise, the transormation made in this 
7990     // routine will prevent rationalizer logic and we might end up with 
7991     // GT_ADDR(GT_SIMD) node post rationalization, leading to a noway assert
7992     // in codegen.
7993     if (src->OperGet() == GT_ADDR && src->gtGetOp1()->OperGet() == GT_SIMD)
7994         goto GENERAL_BLKOP;
7995 #endif 
7996
7997     if (!blkShape->IsIconHandle())
7998     {
7999         clsHnd = 0;
8000         size   = blkShape->gtIntCon.gtIconVal;
8001
8002         /* A four byte BLK_COPY can be treated as an integer asignment */
8003         if (size == 4)
8004             type = TYP_INT;
8005 #ifdef _TARGET_64BIT_
8006         if (size == 8)
8007             type = TYP_LONG;
8008 #endif
8009     }
8010     else
8011     {
8012         clsHnd = (CORINFO_CLASS_HANDLE) blkShape->gtIntCon.gtIconVal;
8013         size   = roundUp(info.compCompHnd->getClassSize(clsHnd), sizeof(void*));
8014
8015         // Since we round up, we are not handling the case where we have a
8016         // non-dword sized struct with GC pointers.
8017         // The EE currently does not allow this, but we may change.  Lets assert it
8018         // just to be safe.
8019         noway_assert(info.compCompHnd->getClassSize(clsHnd) == size);
8020
8021         if (size == REGSIZE_BYTES)
8022         {
8023             BYTE gcPtr;
8024             info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
8025             type = getJitGCType(gcPtr);
8026         }
8027     }
8028
8029     //
8030     //  See if we can do a simple transformation:
8031     //
8032     //          GT_ASG <TYP_size>
8033     //          /   \
8034     //      GT_IND GT_IND or CNS_INT
8035     //         |      |
8036     //       [dest] [src]
8037     //
8038
8039     switch (size)
8040     {
8041     case 1:
8042         type = TYP_BYTE;
8043         goto ONE_SIMPLE_ASG;
8044     case 2:
8045         type = TYP_SHORT;
8046         goto ONE_SIMPLE_ASG;
8047
8048 #ifdef _TARGET_64BIT_
8049     case 4:
8050         type = TYP_INT;
8051         goto ONE_SIMPLE_ASG;
8052 #endif // _TARGET_64BIT_
8053
8054     case REGSIZE_BYTES:
8055         noway_assert(type != TYP_UNDEF);
8056
8057 ONE_SIMPLE_ASG:
8058
8059         noway_assert(size <= REGSIZE_BYTES);
8060
8061         // For INITBLK, a non constant source is not going to allow us to fiddle
8062         // with the bits to create a single assigment.
8063
8064         if ((oper == GT_INITBLK) && (src->gtOper != GT_CNS_INT))
8065         {
8066             goto GENERAL_BLKOP;
8067         }
8068
8069         if (impIsAddressInLocal(dest, &lclVarTree))
8070         {
8071 #if LOCAL_ASSERTION_PROP
8072             // Kill everything about dest
8073             if (optLocalAssertionProp)
8074             {
8075                 if (optAssertionCount > 0)
8076                 {
8077                     fgKillDependentAssertions(lclVarTree->gtLclVarCommon.gtLclNum DEBUGARG(tree));
8078                 }
8079             }
8080 #endif // LOCAL_ASSERTION_PROP
8081
8082             unsigned lclNum = lclVarTree->gtLclVarCommon.gtLclNum;
8083             // A previous incarnation of this code also required the local not to be
8084             // address-exposed(=taken).  That seems orthogonal to the decision of whether
8085             // to do field-wise assignments: being address-exposed will cause it to be
8086             // "dependently" promoted, so it will be in the right memory location.  One possible
8087             // further reason for avoiding field-wise stores is that the struct might have alignment-induced
8088             // holes, whose contents could be meaningful in unsafe code.  If we decide that's a valid
8089             // concern, then we could compromise, and say that address-exposed + fields do not completely cover the memory
8090             // of the struct prevent field-wise assignments.  Same situation exists for the "src" decision.
8091             if (varTypeIsStruct(lclVarTree) &&
8092                 (lvaTable[lclNum].lvPromoted || lclVarIsSIMDType(lclNum)))
8093             {
8094
8095                 // Let fgMorphInitBlock handle it.  (Since we'll need to do field-var-wise assignments.)
8096                 goto GENERAL_BLKOP;
8097             }
8098             else
8099             if (!varTypeIsFloating(lclVarTree->TypeGet())           &&
8100                 size == genTypeSize(var_types(lvaTable[lclNum].lvType)))
8101             {
8102                 // Use the dest local var directly.
8103                 dest = lclVarTree;
8104                 type = lvaTable[lclNum].lvType;  // Make the type used in the GT_IND node match
8105
8106                 // If the block operation had been a write to a local var of a small int type,
8107                 // of the exact size of the small int type, and the var is NormalizeOnStore,
8108                 // we would have labeled it GTF_VAR_USEASG, because the block operation wouldn't
8109                 // have done that normalization.  If we're now making it into an assignment,
8110                 // the NormalizeOnStore will work, and it can be a full def.
8111                 if (lvaTable[lclNum].lvNormalizeOnStore())
8112                 {
8113                     dest->gtFlags &= (~GTF_VAR_USEASG);
8114                 }
8115
8116                 goto _DoneDest;
8117             }
8118             else
8119             {
8120                 // Could be a non-promoted struct, or a floating point type local, or
8121                 // an int subject to a partial write.  Don't enregister.
8122                 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
8123                 // Fall through to indirect the dest node.
8124             }
8125             // Mark the local var tree as a definition point of the local.
8126             lclVarTree->gtFlags |= GTF_VAR_DEF;
8127             if (size < lvaTable[lclNum].lvExactSize) // If it's not a full-width assignment....
8128                 lclVarTree->gtFlags |= GTF_VAR_USEASG;
8129         }
8130
8131         // Check to ensure we are not creating a reducible *(& ... )
8132         if (dest->gtOper == GT_ADDR)
8133         {
8134             GenTreePtr addrOp = dest->gtOp.gtOp1;
8135             // Ignore reinterpret casts between int/gc
8136             if ((addrOp->TypeGet() == type) ||
8137                 (varTypeIsIntegralOrI(addrOp) && (genTypeSize(addrOp->TypeGet()) == size)))
8138             {
8139                 dest = addrOp;
8140                 type = addrOp->TypeGet();
8141                 goto _DoneDest;
8142             }
8143         }
8144
8145         /* Indirect the dest node */
8146
8147         dest = gtNewOperNode(GT_IND, type, dest);
8148
8149         /* As long as we don't have more information about the destination we
8150            have to assume it could live anywhere (not just in the GC heap). Mark
8151            the GT_IND node so that we use the correct write barrier helper in case
8152            the field is a GC ref.
8153         */
8154
8155         dest->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
8156
8157 _DoneDest:;
8158
8159         if (volatil)
8160             dest->gtFlags |= GTF_DONT_CSE;
8161
8162         if (tree->OperIsCopyBlkOp())
8163         {
8164             if (impIsAddressInLocal(src, &lclVarTree))
8165             {
8166                 unsigned lclNum = lclVarTree->gtLclVarCommon.gtLclNum;
8167                 if (varTypeIsStruct(lclVarTree) &&
8168                     (lvaTable[lclNum].lvPromoted || lclVarIsSIMDType(lclNum)))
8169                 {
8170                     // Let fgMorphCopyBlock handle it.
8171                     goto GENERAL_BLKOP;
8172                 }
8173                 else
8174                 if (!varTypeIsFloating(lclVarTree->TypeGet())           &&
8175                     size == genTypeSize(genActualType(lclVarTree->TypeGet())))
8176                 {
8177                     /* Use the src local var directly */
8178                     src = lclVarTree;
8179                     goto _DoneSrc;
8180                 }
8181                 else
8182                 {
8183 #ifndef LEGACY_BACKEND
8184
8185                     // The source argument of the copyblk can potentially 
8186                     // be accessed only through indir(addr(lclVar))
8187                     // or indir(lclVarAddr) in rational form and liveness 
8188                     // won't account for these uses. That said,
8189                     // we have to mark this local as address exposed so
8190                     // we don't delete it as a dead store later on.
8191                     unsigned lclVarNum = lclVarTree->gtLclVarCommon.gtLclNum;
8192                     lvaTable[lclVarNum].lvAddrExposed = true;
8193                     lvaSetVarDoNotEnregister(lclVarNum DEBUGARG(DNER_AddrExposed));
8194
8195 #else // LEGACY_BACKEND
8196                     lvaSetVarDoNotEnregister(lclVarTree->gtLclVarCommon.gtLclNum DEBUGARG(DNER_LocalField));
8197 #endif // LEGACY_BACKEND
8198
8199                     // Fall through to indirect the src node.
8200                 }
8201             }
8202
8203             /* Indirect the src node */
8204
8205             src  = gtNewOperNode(GT_IND, type, src);
8206             src->gtFlags     |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
8207
8208 _DoneSrc:;
8209
8210             if (volatil)
8211                 src->gtFlags |= GTF_DONT_CSE;
8212         }
8213         else // (oper == GT_INITBLK)
8214         {
8215             if (size > 1)
8216             {
8217                 size_t cns = src->gtIntCon.gtIconVal;
8218                 cns  = cns & 0xFF;
8219                 cns |= cns << 8;
8220                 if (size >= 4)
8221                 {
8222                     cns |= cns << 16;
8223 #ifdef _TARGET_64BIT_
8224                     if (size == 8)
8225                     {
8226                         cns |= cns << 32;
8227                     }
8228 #endif // _TARGET_64BIT_
8229
8230                     src->gtType = type;   // Make the type used in the GT_IND node match for TYP_REF
8231
8232                     // if we are using an GT_INITBLK on a GC type the value being assigned has to be zero (null)
8233                     assert(!varTypeIsGC(type) || (cns == 0));
8234                 }
8235
8236                 src->gtIntCon.gtIconVal = cns;
8237             }
8238         }
8239
8240         /* Create the assignment node */
8241
8242         result = gtNewAssignNode(dest, src);
8243         result->gtType = type;
8244
8245         return result;
8246     }
8247
8248 GENERAL_BLKOP:
8249
8250     return nullptr;
8251 }
8252
8253 //------------------------------------------------------------------------
8254 // fgMorphInitBlock: Perform the Morphing of a GT_INITBLK node
8255 //
8256 // Arguments:
8257 //    tree - a tree node with a gtOper of GT_INITBLK
8258 //           the child nodes for tree have already been Morphed
8259 //
8260 // Return Value:
8261 //    We can return the orginal GT_INITBLK unmodified (least desirable, but always correct)
8262 //    We can return a single assignment, when fgMorphOneAsgBlockOp transforms it (most desirable)
8263 //    If we have performed struct promotion of the Dest() then we will try to
8264 //    perform a field by field assignment for each of the promoted struct fields
8265 //
8266 // Notes:
8267 //    If we leave it as a GT_INITBLK we will call lvaSetVarDoNotEnregister() with a reason of DNER_BlockOp
8268 //    if the Dest() is a a struct that has a "CustomLayout" and "ConstainsHoles" then we 
8269 //    can not use a field by field assignment and must the orginal GT_INITBLK unmodified.
8270
8271 GenTreePtr          Compiler::fgMorphInitBlock(GenTreePtr tree)
8272 {
8273     noway_assert(tree->gtOper == GT_INITBLK);
8274
8275     JITDUMP("\nfgMorphInitBlock:");
8276
8277     GenTreePtr oneAsgTree = fgMorphOneAsgBlockOp(tree);
8278     if (oneAsgTree)
8279     {
8280         JITDUMP(" using oneAsgTree.\n");
8281         tree = oneAsgTree;
8282     }
8283     else
8284     {
8285         GenTreeInitBlk* initBlkOp = tree->AsInitBlk();
8286
8287         GenTreePtr    destAddr  = initBlkOp->Dest();
8288         GenTreePtr    initVal   = initBlkOp->InitVal();
8289         GenTreePtr    blockSize = initBlkOp->Size();
8290
8291         // The dest must be an address
8292         noway_assert(genActualType(destAddr->gtType) == TYP_I_IMPL  ||
8293                destAddr->gtType  == TYP_BYREF);
8294
8295         // The size must be an integer type
8296         assert(varTypeIsIntegral(blockSize->gtType));
8297
8298         unsigned      blockWidth        = 0;
8299         bool          blockWidthIsConst = false;
8300
8301         if (blockSize->IsCnsIntOrI())
8302         {
8303             blockWidthIsConst = true;
8304             blockWidth = unsigned(blockSize->gtIntConCommon.IconValue());
8305         }
8306
8307         GenTreeLclVarCommon* lclVarTree = nullptr;
8308
8309         FieldSeqNode* destFldSeq    = nullptr;
8310         unsigned      destLclNum    = BAD_VAR_NUM;
8311         LclVarDsc *   destLclVar    = nullptr;
8312         bool          destDoFldAsg  = false;
8313
8314         if (destAddr->IsLocalAddrExpr(this, &lclVarTree, &destFldSeq))
8315         {
8316             destLclNum = lclVarTree->gtLclNum;
8317             destLclVar = &lvaTable[destLclNum];
8318
8319 #if LOCAL_ASSERTION_PROP
8320             // Kill everything about destLclNum (and its field locals)
8321             if (optLocalAssertionProp)
8322             {
8323                 if (optAssertionCount > 0)
8324                 {
8325                     fgKillDependentAssertions(destLclNum DEBUGARG(tree));
8326                 }
8327             }
8328 #endif // LOCAL_ASSERTION_PROP
8329
8330             if (destLclVar->lvPromoted && blockWidthIsConst)
8331             {
8332                 noway_assert(varTypeIsStruct(destLclVar));
8333                 noway_assert(!opts.MinOpts());
8334                 if (destLclVar->lvAddrExposed & destLclVar->lvContainsHoles)
8335                 {
8336                      JITDUMP(" dest is address exposed");
8337                 }
8338                 else
8339                 {
8340                     if (blockWidth == destLclVar->lvExactSize)
8341                     {
8342                         JITDUMP(" (destDoFldAsg=true)");
8343                         // We may decide later that a copyblk is required when this struct has holes
8344                         destDoFldAsg = true;
8345                     }
8346                     else 
8347                     {
8348                         JITDUMP(" with mismatched size");
8349                     }
8350                 }
8351             }
8352         }
8353
8354         // Can we use field by field assignment for the dest?
8355         if (destDoFldAsg && destLclVar->lvCustomLayout && destLclVar->lvContainsHoles)
8356         {
8357             JITDUMP(" dest contains holes");
8358             destDoFldAsg = false;
8359         }
8360
8361         JITDUMP(destDoFldAsg ? " using field by field initialization.\n"
8362                              : " this requires an InitBlock.\n");
8363
8364         if (!destDoFldAsg && (destLclVar != nullptr))
8365         {
8366             // If destLclVar is not a reg-sized non-field-addressed struct, set it as DoNotEnregister.
8367             if (!destLclVar->lvRegStruct)
8368             {
8369                 // Mark it as DoNotEnregister.
8370                 lvaSetVarDoNotEnregister(destLclNum DEBUGARG(DNER_BlockOp));
8371             }
8372         }
8373
8374         // Mark the dest struct as DoNotEnreg 
8375         // when they are LclVar structs and we are using a CopyBlock 
8376         // or the struct is not promoted 
8377         //
8378         if (!destDoFldAsg)
8379         {
8380 #if CPU_USES_BLOCK_MOVE
8381             compBlkOpUsed = true;
8382 #endif
8383             goto _Done;
8384         }
8385
8386         // The initVal must be a constant of TYP_INT
8387         noway_assert(initVal->OperGet() == GT_CNS_INT);
8388         noway_assert(genActualType(initVal->gtType) == TYP_INT);
8389
8390         // The dest must be of a struct type.
8391         noway_assert(varTypeIsStruct(destLclVar));
8392
8393         //
8394         // Now, convert InitBlock to individual assignments
8395         //
8396
8397         tree = nullptr;
8398
8399         GenTreePtr asg;
8400         GenTreePtr dest;
8401         GenTreePtr srcCopy;
8402         unsigned   fieldLclNum;
8403         unsigned   fieldCnt = destLclVar->lvFieldCnt;
8404
8405         for (unsigned i=0; i<fieldCnt; ++i)
8406         {
8407             fieldLclNum = destLclVar->lvFieldLclStart + i;
8408             dest = gtNewLclvNode(fieldLclNum, lvaTable[fieldLclNum].TypeGet());
8409
8410             noway_assert(destAddr->gtOp.gtOp1->gtOper == GT_LCL_VAR);
8411             // If it had been labeled a "USEASG", assignments to the the individual promoted fields are not.
8412             dest->gtFlags |= destAddr->gtOp.gtOp1->gtFlags & ~(GTF_NODE_MASK | GTF_VAR_USEASG);
8413
8414             srcCopy = gtCloneExpr(initVal);
8415             noway_assert(srcCopy != nullptr);
8416
8417             // need type of oper to be same as tree
8418             if (dest->gtType == TYP_LONG)
8419             {
8420                 srcCopy->ChangeOperConst(GT_CNS_NATIVELONG);
8421                 // copy and extend the value
8422                 srcCopy->gtIntConCommon.SetLngValue(initVal->gtIntConCommon.IconValue());
8423                 /* Change the types of srcCopy to TYP_LONG */
8424                 srcCopy->gtType = TYP_LONG;
8425             }
8426             else if (varTypeIsFloating(dest->gtType))
8427             {
8428                 srcCopy->ChangeOperConst(GT_CNS_DBL);
8429                 // setup the bit pattern
8430                 memset(&srcCopy->gtDblCon.gtDconVal, (int)initVal->gtIntCon.gtIconVal, sizeof(srcCopy->gtDblCon.gtDconVal));
8431                 /* Change the types of srcCopy to TYP_DOUBLE */
8432                 srcCopy->gtType = TYP_DOUBLE;
8433             }
8434             else
8435             {
8436                 noway_assert(srcCopy->gtOper == GT_CNS_INT);
8437                 noway_assert(srcCopy->TypeGet() == TYP_INT);
8438                 // setup the bit pattern
8439                 memset(&srcCopy->gtIntCon.gtIconVal, (int)initVal->gtIntCon.gtIconVal, sizeof(srcCopy->gtIntCon.gtIconVal));
8440             }
8441
8442             srcCopy->gtType = dest->TypeGet();
8443
8444             asg = gtNewAssignNode(dest, srcCopy);
8445
8446 #if LOCAL_ASSERTION_PROP
8447             if (optLocalAssertionProp)
8448             {
8449                 optAssertionGen(asg);
8450             }
8451 #endif // LOCAL_ASSERTION_PROP
8452
8453             if (tree)
8454             {
8455                 tree = gtNewOperNode(GT_COMMA,
8456                                      TYP_VOID,
8457                                      tree,
8458                                      asg);
8459             }
8460             else
8461             {
8462                 tree = asg;
8463             }
8464         }
8465     }
8466
8467 #ifdef DEBUG
8468     tree->gtFlags |= GTF_MORPHED;
8469
8470     if (verbose)
8471     {
8472         printf("fgMorphInitBlock (after):\n");
8473         gtDispTree(tree);
8474     }
8475 #endif
8476
8477 _Done:
8478     return tree;
8479 }
8480
8481 //------------------------------------------------------------------------
8482 // fgMorphCopyBlock: Perform the Morphing of a GT_COPYBLK and GT_COPYOBJ nodes
8483 //
8484 // Arguments:
8485 //    tree - a tree node with a gtOper of GT_COPYBLK or GT_COPYOBJ
8486 //           the child nodes for tree have already been Morphed
8487 //
8488 // Return Value:
8489 //    We can return the orginal GT_COPYBLK or GT_COPYOBJ unmodified (least desirable, but always correct)
8490 //    We can return a single assignment, when fgMorphOneAsgBlockOp transforms it (most desirable)
8491 //    If we have performed struct promotion of the Source() or the Dest() then we will try to
8492 //    perform a field by field assignment for each of the promoted struct fields
8493 //
8494 // Notes:
8495 //    If we leave it as a GT_COPYBLK or GT_COPYOBJ we will call lvaSetVarDoNotEnregister() on both Source() and Dest()
8496 //    When performing a field by field assignment we can have one of Source() or Dest treated as a blob of bytes
8497 //    and in such cases we will call lvaSetVarDoNotEnregister() on the one treated as a blob of bytes.
8498 //    if the Source() or Dest() is a a struct that has a "CustomLayout" and "ConstainsHoles" then we 
8499 //    can not use a field by field assignment and must the orginal GT_COPYBLK unmodified.
8500
8501 GenTreePtr          Compiler::fgMorphCopyBlock(GenTreePtr tree)
8502 {
8503     noway_assert(tree->OperIsCopyBlkOp());
8504
8505     JITDUMP("\nfgMorphCopyBlock:");
8506
8507     bool isLateArg = (tree->gtFlags & GTF_LATE_ARG) != 0;
8508
8509     GenTreePtr oneAsgTree = fgMorphOneAsgBlockOp(tree);
8510
8511     if (oneAsgTree)
8512     {
8513         JITDUMP(" using oneAsgTree.\n");
8514         tree = oneAsgTree;
8515     }
8516     else
8517     {
8518         GenTreePtr    destAddr; 
8519         GenTreePtr    srcAddr;
8520         GenTreePtr    blockSize;
8521         bool          isCopyObj;
8522
8523         if (tree->OperGet() == GT_COPYBLK)
8524         {
8525             GenTreeCpBlk* copyBlkOp = tree->AsCpBlk();
8526
8527             isCopyObj = false;
8528             destAddr  = copyBlkOp->Dest();
8529             srcAddr   = copyBlkOp->Source();
8530             blockSize = copyBlkOp->Size();
8531         }
8532         else
8533         {
8534             GenTreeCpObj* copyObjOp = tree->AsCpObj();
8535
8536             isCopyObj = true;
8537             destAddr  = copyObjOp->Dest();
8538             srcAddr   = copyObjOp->Source();
8539             blockSize = copyObjOp->ClsTok();
8540         }
8541
8542         noway_assert(destAddr->TypeGet() == TYP_BYREF || destAddr->TypeGet() == TYP_I_IMPL);
8543         noway_assert(srcAddr->TypeGet()  == TYP_BYREF || srcAddr->TypeGet()  == TYP_I_IMPL);
8544
8545         unsigned    blockWidth        = 0;
8546         bool        blockWidthIsConst = false;
8547
8548         if (blockSize->IsCnsIntOrI())
8549         {
8550             blockWidthIsConst = true;
8551             if (blockSize->IsIconHandle(GTF_ICON_CLASS_HDL))
8552             {
8553                 CORINFO_CLASS_HANDLE clsHnd = (CORINFO_CLASS_HANDLE) blockSize->gtIntConCommon.IconValue();
8554                 blockWidth = info.compCompHnd->getClassSize(clsHnd);
8555             }
8556             else
8557             {
8558                 blockWidth = unsigned(blockSize->gtIntConCommon.IconValue());
8559             }
8560         }
8561   
8562         GenTreeLclVarCommon* lclVarTree = nullptr;
8563
8564         FieldSeqNode*  destFldSeq    = nullptr;
8565         unsigned       destLclNum    = BAD_VAR_NUM;
8566         LclVarDsc*     destLclVar    = nullptr;
8567         bool           destDoFldAsg  = false;
8568         bool           destOnStack   = false;
8569
8570         if (destAddr->IsLocalAddrExpr(this, &lclVarTree, &destFldSeq))
8571         {
8572             destOnStack = true;
8573             destLclNum = lclVarTree->gtLclNum;
8574             destLclVar = &lvaTable[destLclNum];
8575
8576 #if LOCAL_ASSERTION_PROP
8577             // Kill everything about destLclNum (and its field locals)
8578             if (optLocalAssertionProp)
8579             {
8580                 if (optAssertionCount > 0)
8581                 {
8582                     fgKillDependentAssertions(destLclNum DEBUGARG(tree));
8583                 }
8584             }
8585 #endif // LOCAL_ASSERTION_PROP
8586
8587             if (destLclVar->lvPromoted && blockWidthIsConst)
8588             {
8589                 noway_assert(varTypeIsStruct(destLclVar));
8590                 noway_assert(!opts.MinOpts());
8591
8592                 if (blockWidth == destLclVar->lvExactSize)
8593                 {
8594                     JITDUMP(" (destDoFldAsg=true)");
8595                     // We may decide later that a copyblk is required when this struct has holes
8596                     destDoFldAsg = true;
8597                 }
8598                 else 
8599                 {
8600                     JITDUMP(" with mismatched dest size");
8601                 }
8602             }
8603         }
8604
8605         FieldSeqNode*  srcFldSeq    = nullptr;
8606         unsigned       srcLclNum    = BAD_VAR_NUM;
8607         LclVarDsc*     srcLclVar    = nullptr;
8608         bool           srcDoFldAsg  = false;
8609
8610         if (srcAddr->IsLocalAddrExpr(this, &lclVarTree, &srcFldSeq))
8611         {
8612             srcLclNum = lclVarTree->gtLclNum;
8613             srcLclVar = &lvaTable[srcLclNum];
8614
8615             if (srcLclVar->lvPromoted && blockWidthIsConst)
8616             {
8617                 noway_assert(varTypeIsStruct(srcLclVar));
8618                 noway_assert(!opts.MinOpts());
8619
8620                 if (blockWidth == srcLclVar->lvExactSize)
8621                 {
8622                     JITDUMP(" (srcDoFldAsg=true)");
8623                     // We may decide later that a copyblk is required when this struct has holes
8624                     srcDoFldAsg = true;
8625                 }
8626                 else 
8627                 {
8628                     JITDUMP(" with mismatched src size");
8629                 }
8630             }
8631         }
8632
8633         // Check to see if we are required to do a copy block because the struct contains holes
8634         // and either the src or dest is externally visible
8635         //
8636         bool  requiresCopyBlock = false;
8637         bool  srcSingleLclVarAsg = false;
8638
8639         // If either src or dest is a reg-sized non-field-addressed struct, keep the copyBlock.
8640         if ((destLclVar != nullptr && destLclVar->lvRegStruct) ||
8641             (srcLclVar  != nullptr && srcLclVar->lvRegStruct))
8642         {
8643             requiresCopyBlock = true;
8644         }
8645
8646         // Can we use field by field assignment for the dest?
8647         if (destDoFldAsg && destLclVar->lvCustomLayout && destLclVar->lvContainsHoles)
8648         {
8649             JITDUMP(" dest contains custom layout and contains holes");
8650             // C++ style CopyBlock with holes
8651             requiresCopyBlock = true;
8652         }
8653
8654         // Can we use field by field assignment for the src?
8655         if (srcDoFldAsg && srcLclVar->lvCustomLayout && srcLclVar->lvContainsHoles)
8656         {
8657             JITDUMP(" src contains custom layout and contains holes");
8658             // C++ style CopyBlock with holes
8659             requiresCopyBlock = true;
8660         }
8661
8662         if (tree->OperGet() == GT_COPYBLK && tree->AsCpBlk()->gtBlkOpGcUnsafe)
8663         {
8664             requiresCopyBlock = true;
8665         }
8666
8667         // If we passed the above checks, then we will check these two
8668         if (!requiresCopyBlock)
8669         {
8670             // Are both dest and src promoted structs? 
8671             if (destDoFldAsg && srcDoFldAsg)
8672             {
8673                 // Both structs should be of the same type, if not we will use a copy block
8674                 if (lvaTable[destLclNum].lvVerTypeInfo.GetClassHandle() != lvaTable[srcLclNum].lvVerTypeInfo.GetClassHandle())
8675                 {
8676                     requiresCopyBlock = true;  // Mismatched types, leave as a CopyBlock
8677                     JITDUMP(" with mismatched types");
8678                 }
8679             }
8680             // Are neither dest or src promoted structs? 
8681             else if (!destDoFldAsg && !srcDoFldAsg)  
8682             {
8683                 requiresCopyBlock = true;   // Leave as a CopyBlock
8684                 JITDUMP(" with no promoted structs");
8685             }
8686             else if (destDoFldAsg)
8687             {
8688                 // Match the following kinds of trees:
8689                 //  fgMorphTree BB01, stmt 9 (before)
8690                 //   [000052] ------------        const     int    8
8691                 //   [000053] -A--G-------     copyBlk   void  
8692                 //   [000051] ------------           addr      byref 
8693                 //   [000050] ------------              lclVar    long   V07 loc5         
8694                 //   [000054] --------R---        <list>    void  
8695                 //   [000049] ------------           addr      byref 
8696                 //   [000048] ------------              lclVar    struct(P) V06 loc4         
8697                 //                                              long   V06.h (offs=0x00) -> V17 tmp9
8698                 // Yields this transformation
8699                 //  fgMorphCopyBlock (after):
8700                 //   [000050] ------------        lclVar    long   V07 loc5            
8701                 //   [000085] -A----------     =         long  
8702                 //   [000083] D------N----        lclVar    long   V17 tmp9         
8703                 //
8704                 if (blockWidthIsConst             && 
8705                     (destLclVar->lvFieldCnt == 1) && 
8706                     (srcLclVar != nullptr)        && 
8707                     (blockWidth == genTypeSize(srcLclVar->TypeGet())))
8708                 {
8709                     // Reject the following tree:
8710                     //  - seen on x86chk    jit\jit64\hfa\main\hfa_sf3E_r.exe
8711                     //
8712                     //  fgMorphTree BB01, stmt 6 (before)
8713                     //   [000038] -------------        const     int    4
8714                     //   [000039] -A--G--------     copyBlk   void 
8715                     //   [000037] -------------           addr      byref 
8716                     //   [000036] -------------              lclVar    int    V05 loc3    
8717                     //   [000040] --------R----        <list>    void  
8718                     //   [000035] -------------           addr      byref 
8719                     //   [000034] -------------              lclVar    struct(P) V04 loc2        
8720                     //                                          float  V04.f1 (offs=0x00) -> V13 tmp6         
8721                     // As this would framsform into 
8722                     //   float V13 = int V05
8723                     //
8724                     unsigned fieldLclNum = lvaTable[destLclNum].lvFieldLclStart;
8725                     var_types destType = lvaTable[fieldLclNum].TypeGet();
8726                     if (srcLclVar->TypeGet() == destType)
8727                     {
8728                         srcSingleLclVarAsg = true;
8729                     }
8730                 }
8731             }
8732         }
8733
8734         // If we require a copy block the set both of the field assign bools to false
8735         if (requiresCopyBlock)
8736         {
8737             // If a copy block is required then we won't do field by field assignments
8738             destDoFldAsg = false;
8739             srcDoFldAsg = false;
8740         }
8741
8742         JITDUMP(requiresCopyBlock ? " this requires a CopyBlock.\n" 
8743                                   : " using field by field assignments.\n");      
8744
8745         // Mark the dest/src structs as DoNotEnreg 
8746         // when they are not reg-sized non-field-addressed structs and we are using a CopyBlock 
8747         // or the struct is not promoted 
8748         //    
8749         if (!destDoFldAsg && (destLclVar != nullptr))
8750         {
8751             if (!destLclVar->lvRegStruct)
8752             {
8753                 // Mark it as DoNotEnregister.
8754                 lvaSetVarDoNotEnregister(destLclNum DEBUGARG(DNER_BlockOp));
8755             }
8756         }
8757
8758         if (!srcDoFldAsg && (srcLclVar != nullptr) && !srcSingleLclVarAsg)
8759         {
8760             if (!srcLclVar->lvRegStruct)
8761             {
8762                 lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(DNER_BlockOp));
8763             }
8764         }
8765
8766         if (requiresCopyBlock)
8767         {
8768 #if CPU_USES_BLOCK_MOVE
8769             compBlkOpUsed = true;
8770 #endif
8771             // Note that the unrolling of CopyBlk is only implemented on some platforms
8772             // Currently that includes x64 and Arm64 but not x64 or Arm32
8773 #ifdef CPBLK_UNROLL_LIMIT
8774             // If we have a CopyObj with a dest on the stack
8775             // we will convert it into an GC Unsafe CopyBlk that is non-interruptible
8776             // when its size is small enouch to be completely unrolled (i.e. between [16..64] bytes)
8777             //
8778             if (isCopyObj && destOnStack && blockWidthIsConst && 
8779                 (blockWidth >= (2*TARGET_POINTER_SIZE)) && (blockWidth <= CPBLK_UNROLL_LIMIT))
8780             {
8781                 tree->SetOper(GT_COPYBLK);
8782                 tree->AsCpBlk()->gtBlkOpGcUnsafe = true;    // Mark as a GC unsage copy block
8783                 blockSize->gtIntConCommon.SetIconValue(ssize_t(blockWidth));
8784                 blockSize->gtFlags &= ~GTF_ICON_HDL_MASK;   // Clear the GTF_ICON_CLASS_HDL flags
8785             }
8786 #endif
8787             // Liveness doesn't consider copyblk arguments of simple types as being
8788             // a use or def, so explicitly mark these variables as address-exposed.
8789             if (srcLclNum != BAD_VAR_NUM && !varTypeIsStruct(srcLclVar))
8790             {
8791                 JITDUMP("Non-struct copyBlk src V%02d is addr exposed\n", srcLclNum);
8792                 lvaTable[srcLclNum].lvAddrExposed = true;
8793             }
8794
8795             if (destLclNum != BAD_VAR_NUM && !varTypeIsStruct(destLclVar))
8796             {
8797                 JITDUMP("Non-struct copyBlk dest V%02d is addr exposed\n", destLclNum);
8798                 lvaTable[destLclNum].lvAddrExposed = true;
8799             }
8800
8801             goto _Done;
8802         }
8803
8804         //
8805         // Otherwise we convert this CopyBlock into individual field by field assignments
8806         //
8807         tree = nullptr;
8808
8809         GenTreePtr asg;
8810         GenTreePtr dest;
8811         GenTreePtr src;
8812         GenTreePtr addrSpill = nullptr;
8813         unsigned   addrSpillTemp = BAD_VAR_NUM;
8814         bool       addrSpillIsStackDest = false;   // true if 'addrSpill' represents the address in our local stack frame 
8815
8816         unsigned    fieldCnt     = DUMMY_INIT(0);
8817
8818         if (destDoFldAsg && srcDoFldAsg)
8819         {
8820             // To do fieldwise assignments for both sides, they'd better be the same struct type!
8821             // All of these conditions were checked above...
8822             assert(destLclNum != BAD_VAR_NUM && srcLclNum != BAD_VAR_NUM);
8823             assert(lvaTable[destLclNum].lvVerTypeInfo.GetClassHandle() == lvaTable[srcLclNum].lvVerTypeInfo.GetClassHandle());
8824             assert(destLclVar != nullptr && srcLclVar != nullptr && destLclVar->lvFieldCnt == srcLclVar->lvFieldCnt);
8825
8826             fieldCnt = destLclVar->lvFieldCnt;
8827             goto _AssignFields; // No need to spill the address to the temp. Go ahead to morph it into field assignments.
8828         }
8829         else if (destDoFldAsg)
8830         {
8831             fieldCnt = destLclVar->lvFieldCnt;
8832         }
8833         else
8834         {
8835             assert(srcDoFldAsg);
8836             fieldCnt = srcLclVar->lvFieldCnt;
8837         }
8838
8839         if (destDoFldAsg)
8840         {
8841             noway_assert(!srcDoFldAsg);
8842             if (gtClone(srcAddr))
8843             {
8844                 // srcAddr is simple expression. No need to spill.
8845                 noway_assert((srcAddr->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) == 0);
8846             }
8847             else
8848             {
8849                 // srcAddr is complex expression. Clone and spill it (unless the destination is
8850                 // a struct local that only has one field, in which case we'd only use the
8851                 // address value once...)
8852                 if (destLclVar->lvFieldCnt > 1)
8853                 {
8854                     addrSpill = gtCloneExpr(srcAddr);     // addrSpill represents the 'srcAddr'
8855                     noway_assert(addrSpill != nullptr);
8856                 }
8857             }
8858         }
8859
8860         if (srcDoFldAsg)
8861         {
8862             noway_assert(!destDoFldAsg);
8863
8864             // If we're doing field-wise stores, to an address within a local, and we copy
8865             // the address into "addrSpill", do *not* declare the original local var node in the
8866             // field address as GTF_VAR_DEF and GTF_VAR_USEASG; we will declare each of the
8867             // field-wise assignments as an "indirect" assignment to the local.
8868             // ("lclVarTree" is a subtree of "destAddr"; make sure we remove the flags before
8869             // we clone it.)
8870             if (lclVarTree != nullptr)
8871             {
8872                 lclVarTree->gtFlags &= ~(GTF_VAR_DEF | GTF_VAR_USEASG);
8873             }
8874
8875             if (gtClone(destAddr))
8876             {
8877                 // destAddr is simple expression. No need to spill
8878                 noway_assert((destAddr->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) == 0);
8879             }
8880             else
8881             {
8882                 // destAddr is complex expression. Clone and spill it (unless
8883                 // the source is a struct local that only has one field, in which case we'd only
8884                 // use the address value once...)
8885                 if (srcLclVar->lvFieldCnt > 1)
8886                 {
8887                     addrSpill = gtCloneExpr(destAddr);    // addrSpill represents the 'destAddr'
8888                     noway_assert(addrSpill != nullptr);
8889                 }
8890
8891                 // TODO-CQ: this should be based on a more general
8892                 // "BaseAddress" method, that handles fields of structs, before or after
8893                 // morphing.
8894                 if (addrSpill != nullptr && addrSpill->OperGet() == GT_ADDR)
8895                 {
8896                     if (addrSpill->gtOp.gtOp1->IsLocal())
8897                     {
8898                         // We will *not* consider this to define the local, but rather have each individual field assign
8899                         // be a definition.
8900                         addrSpill->gtOp.gtOp1->gtFlags &= ~(GTF_LIVENESS_MASK);
8901                         assert(lvaTable[addrSpill->gtOp.gtOp1->gtLclVarCommon.gtLclNum].lvLclBlockOpAddr == 1);                     
8902                         addrSpillIsStackDest = true;  // addrSpill represents the address of LclVar[varNum] in our local stack frame 
8903                     }
8904                 }
8905             }
8906         }
8907
8908         if (addrSpill != nullptr)
8909         {
8910             // Spill the (complex) address to a BYREF temp.
8911             // Note, at most one address may need to be spilled.
8912             addrSpillTemp = lvaGrabTemp(true DEBUGARG("BlockOp address local"));
8913
8914             lvaTable[addrSpillTemp].lvType = TYP_BYREF;
8915
8916             if (addrSpillIsStackDest)
8917             {
8918                 lvaTable[addrSpillTemp].lvStackByref = true;
8919             }
8920
8921             tree = gtNewAssignNode(gtNewLclvNode(addrSpillTemp, TYP_BYREF),
8922                                    addrSpill);
8923
8924 #ifndef LEGACY_BACKEND
8925             // If we are assigning the address of a LclVar here 
8926             // liveness does not account for this kind of address taken use. 
8927             // 
8928             // We have to mark this local as address exposed so
8929             // that we don't delete the definition for this LclVar 
8930             // as a dead store later on.
8931             //
8932             if (addrSpill->OperGet() == GT_ADDR)
8933             {
8934                 GenTreePtr addrOp = addrSpill->gtOp.gtOp1;
8935                 if (addrOp->IsLocal())
8936                 {
8937                     unsigned lclVarNum = addrOp->gtLclVarCommon.gtLclNum;
8938                     lvaTable[lclVarNum].lvAddrExposed = true;
8939                     lvaSetVarDoNotEnregister(lclVarNum DEBUGARG(DNER_AddrExposed));
8940                 }
8941             }
8942 #endif // !LEGACY_BACKEND
8943         }
8944
8945     _AssignFields:
8946
8947         for (unsigned i=0; i<fieldCnt; ++i)
8948         {
8949             FieldSeqNode* curFieldSeq = nullptr;
8950             if (destDoFldAsg)
8951             {
8952                 noway_assert(destLclNum != BAD_VAR_NUM);
8953                 unsigned fieldLclNum = lvaTable[destLclNum].lvFieldLclStart + i;
8954                 dest = gtNewLclvNode(fieldLclNum, lvaTable[fieldLclNum].TypeGet());
8955
8956                 noway_assert(destAddr->gtOp.gtOp1->gtOper == GT_LCL_VAR);
8957                 // If it had been labeled a "USEASG", assignments to the the individual promoted fields are not.
8958                 dest->gtFlags |= destAddr->gtOp.gtOp1->gtFlags & ~(GTF_NODE_MASK | GTF_VAR_USEASG);
8959             }
8960             else
8961             {
8962                 noway_assert(srcDoFldAsg);
8963                 noway_assert(srcLclNum != BAD_VAR_NUM);
8964                 unsigned fieldLclNum = lvaTable[srcLclNum].lvFieldLclStart + i;
8965
8966                 if (addrSpill)
8967                 {
8968                     assert(addrSpillTemp != BAD_VAR_NUM);
8969                     dest = gtNewLclvNode(addrSpillTemp, TYP_BYREF);
8970                 }
8971                 else
8972                 {
8973                     dest = gtCloneExpr(destAddr);
8974                     noway_assert(dest != nullptr);
8975
8976                     // Is the address of a local?
8977                     GenTreeLclVarCommon* lclVarTree = nullptr;
8978                     bool  isEntire = false;
8979                     bool* pIsEntire = (blockWidthIsConst ? &isEntire : nullptr);
8980                     if (dest->DefinesLocalAddr(this, blockWidth, &lclVarTree, pIsEntire))
8981                     {
8982                         lclVarTree->gtFlags |= GTF_VAR_DEF;
8983                         if (!isEntire)
8984                             lclVarTree->gtFlags |= GTF_VAR_USEASG;
8985                     }
8986                 }
8987
8988                 GenTreePtr fieldOffsetNode = gtNewIconNode(lvaTable[fieldLclNum].lvFldOffset, TYP_I_IMPL);
8989                 // Have to set the field sequence -- which means we need the field handle.
8990                 CORINFO_CLASS_HANDLE classHnd = lvaTable[srcLclNum].lvVerTypeInfo.GetClassHandle();
8991                 CORINFO_FIELD_HANDLE fieldHnd = info.compCompHnd->getFieldInClass(classHnd, lvaTable[fieldLclNum].lvFldOrdinal);
8992                 curFieldSeq = GetFieldSeqStore()->CreateSingleton(fieldHnd);
8993                 fieldOffsetNode->gtIntCon.gtFieldSeq = curFieldSeq;
8994
8995                 dest = gtNewOperNode(GT_ADD, TYP_BYREF,
8996                                      dest,
8997                                      fieldOffsetNode);
8998
8999                 dest = gtNewOperNode(GT_IND, lvaTable[fieldLclNum].TypeGet(), dest);
9000
9001                 // !!! The destination could be on stack. !!!
9002                 // This flag will let us choose the correct write barrier.
9003                 dest->gtFlags |= GTF_IND_TGTANYWHERE;
9004             }
9005
9006
9007             if (srcDoFldAsg)
9008             {
9009                 noway_assert(srcLclNum != BAD_VAR_NUM);
9010                 unsigned fieldLclNum = lvaTable[srcLclNum].lvFieldLclStart + i;
9011                 src = gtNewLclvNode(fieldLclNum, lvaTable[fieldLclNum].TypeGet());
9012
9013                 noway_assert(srcAddr->gtOp.gtOp1->gtOper == GT_LCL_VAR);
9014                 src->gtFlags |= srcAddr->gtOp.gtOp1->gtFlags & ~GTF_NODE_MASK;
9015             }
9016             else
9017             {
9018                 noway_assert(destDoFldAsg);
9019                 noway_assert(destLclNum != BAD_VAR_NUM);
9020                 unsigned fieldLclNum = lvaTable[destLclNum].lvFieldLclStart + i;
9021
9022                 if (srcSingleLclVarAsg)
9023                 {
9024                     noway_assert(fieldCnt == 1);
9025                     noway_assert(srcLclVar != nullptr);  
9026                     noway_assert(addrSpill == nullptr);
9027
9028                     src = gtNewLclvNode(srcLclNum, srcLclVar->TypeGet());
9029                 }
9030                 else
9031                 {
9032                     if (addrSpill)
9033                     {
9034                         assert(addrSpillTemp != BAD_VAR_NUM);
9035                         src = gtNewLclvNode(addrSpillTemp, TYP_BYREF);
9036                     }
9037                     else
9038                     {
9039                         src = gtCloneExpr(srcAddr);
9040                         noway_assert(src != nullptr);
9041                     }
9042
9043                     CORINFO_CLASS_HANDLE classHnd = lvaTable[destLclNum].lvVerTypeInfo.GetClassHandle();
9044                     CORINFO_FIELD_HANDLE fieldHnd = info.compCompHnd->getFieldInClass(classHnd, lvaTable[fieldLclNum].lvFldOrdinal);
9045                     curFieldSeq = GetFieldSeqStore()->CreateSingleton(fieldHnd);
9046
9047                     src = gtNewOperNode(GT_ADD, TYP_BYREF,
9048                                         src,
9049                                         new(this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL,
9050                                                                             lvaTable[fieldLclNum].lvFldOffset,
9051                                                                             curFieldSeq));
9052
9053                     src = gtNewOperNode(GT_IND, lvaTable[fieldLclNum].TypeGet(), src);
9054                 }
9055             }
9056
9057             noway_assert(dest->TypeGet() == src->TypeGet());
9058
9059             asg = gtNewAssignNode(dest, src);
9060
9061             // If we spilled the address, and we didn't do individual field assignments to promoted fields,
9062             // and it was of a local, record the assignment as an indirect update of a local.
9063             if (addrSpill && !destDoFldAsg && destLclNum != BAD_VAR_NUM)
9064             {
9065                 curFieldSeq = GetFieldSeqStore()->Append(destFldSeq, curFieldSeq);
9066                 bool isEntire = (genTypeSize(var_types(lvaTable[destLclNum].lvType))
9067                                  == genTypeSize(dest->TypeGet()));
9068                 IndirectAssignmentAnnotation* pIndirAnnot =
9069                     new (this, CMK_Unknown) IndirectAssignmentAnnotation(destLclNum, curFieldSeq, isEntire);
9070                 GetIndirAssignMap()->Set(asg, pIndirAnnot);
9071             }
9072
9073 #if LOCAL_ASSERTION_PROP
9074             if (optLocalAssertionProp)
9075             {
9076                 optAssertionGen(asg);
9077             }
9078 #endif // LOCAL_ASSERTION_PROP
9079
9080             if (tree)
9081             {
9082                 tree = gtNewOperNode(GT_COMMA,
9083                                      TYP_VOID,
9084                                      tree,
9085                                      asg);
9086             }
9087             else
9088             {
9089                 tree = asg;
9090             }
9091         }
9092     }
9093
9094     if (isLateArg)
9095     {
9096         tree->gtFlags |= GTF_LATE_ARG;
9097     }
9098
9099 #ifdef DEBUG
9100     tree->gtFlags |= GTF_MORPHED;
9101
9102     if (verbose)
9103     {
9104         printf("\nfgMorphCopyBlock (after):\n");
9105         gtDispTree(tree);
9106     }
9107 #endif
9108
9109 _Done:
9110     return tree;
9111 }
9112
9113 // insert conversions and normalize to make tree amenable to register
9114 // FP architectures
9115 GenTree*  Compiler::fgMorphForRegisterFP(GenTree *tree)
9116 {
9117     GenTreePtr      op1     = tree->gtOp.gtOp1;
9118     GenTreePtr      op2     = tree->gtGetOp2();
9119
9120     if (tree->OperIsArithmetic()
9121         && varTypeIsFloating(tree))
9122     {
9123         if (op1->TypeGet() != tree->TypeGet())
9124         {
9125             tree->gtOp.gtOp1 = gtNewCastNode(tree->TypeGet(), tree->gtOp.gtOp1, tree->TypeGet());
9126         }
9127         if (op2->TypeGet() != tree->TypeGet())
9128         {
9129             tree->gtOp.gtOp2 = gtNewCastNode(tree->TypeGet(), tree->gtOp.gtOp2, tree->TypeGet());
9130         }
9131     }
9132     else if (tree->OperIsCompare()
9133              && varTypeIsFloating(op1)
9134              && op1->TypeGet() != op2->TypeGet())
9135     {
9136         // both had better be floating, just one bigger than other
9137         assert (varTypeIsFloating(op2));
9138         if (op1->TypeGet() == TYP_FLOAT)
9139         {
9140             tree->gtOp.gtOp1 = gtNewCastNode(TYP_DOUBLE, tree->gtOp.gtOp1, TYP_DOUBLE);
9141         }
9142         else if (op2->TypeGet() == TYP_FLOAT)
9143         {
9144             tree->gtOp.gtOp2 = gtNewCastNode(TYP_DOUBLE, tree->gtOp.gtOp2, TYP_DOUBLE);
9145         }
9146     }
9147
9148     return tree;
9149 }
9150
9151 GenTree* Compiler::fgMorphRecognizeBoxNullable(GenTree* compare)
9152 {
9153     GenTree* op1 = compare->gtOp.gtOp1;
9154     GenTree* op2 = compare->gtOp.gtOp2;
9155     GenTree* opCns;
9156     GenTreeCall* opCall;
9157
9158     // recognize this pattern:
9159     //
9160     // stmtExpr  void  (IL 0x000...  ???)
9161     //     return    int
9162     //             const     ref    null
9163     //         ==        int
9164     //             call help ref    HELPER.CORINFO_HELP_BOX_NULLABLE
9165     //                 const(h)  long   0x7fed96836c8 class
9166     //                 addr      byref
9167     //                     ld.lclVar struct V00 arg0
9168     //
9169     //
9170     // which comes from this code (reported by customer as being slow) :
9171     //
9172     // private static bool IsNull<T>(T arg)
9173     // {
9174     //    return arg==null;
9175     // }
9176     //
9177
9178     if (op1->IsCnsIntOrI() && op2->IsHelperCall())
9179     {
9180         opCns = op1;
9181         opCall = op2->AsCall();
9182     }
9183     else if (op1->IsHelperCall() && op2->IsCnsIntOrI())
9184     {
9185         opCns = op2;
9186         opCall = op1->AsCall();
9187     }
9188     else
9189     {
9190         return compare;
9191     }
9192
9193     if (opCns->gtIntConCommon.IconValue() != 0)
9194         return compare;
9195
9196     if (eeGetHelperNum(opCall->gtCallMethHnd) != CORINFO_HELP_BOX_NULLABLE)
9197         return compare;
9198
9199     // replace the box with an access of the nullable 'hasValue' field which is at the zero offset
9200     GenTree* newOp = gtNewOperNode(GT_IND, TYP_BOOL, opCall->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp1);
9201
9202     if (opCall == op1)
9203         compare->gtOp.gtOp1 = newOp;
9204     else
9205         compare->gtOp.gtOp2 = newOp;
9206
9207     return compare;
9208 }
9209
9210 #ifdef FEATURE_SIMD
9211
9212 //--------------------------------------------------------------------------------------
9213 // fgCopySIMDNode: make a copy of a SIMD intrinsic node, e.g. so that a field can be accessed.
9214 //
9215 // Arguments:
9216 //    simdNode  - The GenTreeSIMD node to be copied
9217 //
9218 // Return Value:
9219 //    A comma node where op1 is the assignment of the simd node to a temp, and op2 is the temp lclVar.
9220 //
9221 GenTree*
9222 Compiler::fgCopySIMDNode(GenTreeSIMD* simdNode)
9223 {
9224     // Copy the result of the SIMD intrinsic into a temp.
9225     unsigned lclNum = lvaGrabTemp(true DEBUGARG("Copy of SIMD intrinsic with field access"));
9226
9227     CORINFO_CLASS_HANDLE simdHandle = NO_CLASS_HANDLE;
9228     // We only have fields of the fixed float vectors.
9229     noway_assert(simdNode->gtSIMDBaseType == TYP_FLOAT);
9230     switch(simdNode->gtSIMDSize)
9231     {
9232     case 8:     simdHandle = SIMDVector2Handle;                 break;
9233     case 12:    simdHandle = SIMDVector3Handle;                 break;
9234     case 16:    simdHandle = SIMDVector4Handle;                 break;
9235     default:    noway_assert(!"field of unexpected SIMD type"); break;
9236     }
9237     assert(simdHandle != NO_CLASS_HANDLE);
9238
9239     lvaSetStruct(lclNum, simdHandle, false, true);
9240     lvaTable[lclNum].lvFieldAccessed = true;
9241
9242     GenTree* asg = gtNewTempAssign(lclNum, simdNode);
9243     GenTree* newLclVarNode = new (this, GT_LCL_VAR) GenTreeLclVar(simdNode->TypeGet(), lclNum, BAD_IL_OFFSET);
9244    
9245     GenTree* comma = gtNewOperNode(GT_COMMA, simdNode->TypeGet(), asg, newLclVarNode);
9246     return comma;
9247 }
9248
9249 //--------------------------------------------------------------------------------------------------------------
9250 // getSIMDStructFromField: 
9251 //   Checking whether the field belongs to a simd struct or not. If it is, return the GenTreePtr for 
9252 //   the struct node, also base type, field index and simd size. If it is not, just return  nullptr.
9253 //   Usually if the tree node is from a simd lclvar which is not used in any SIMD intrinsic, then we 
9254 //   should return nullptr, since in this case we should treat SIMD struct as a regular struct. 
9255 //   However if no matter what, you just want get simd struct node, you can set the ignoreUsedInSIMDIntrinsic
9256 //   as true. Then there will be no IsUsedInSIMDIntrinsic checking, and it will return SIMD struct node
9257 //   if the struct is a SIMD struct.
9258 //
9259 // Arguments:
9260 //       tree - GentreePtr. This node will be checked to see this is a field which belongs to a simd 
9261 //               struct used for simd intrinsic or not.
9262 //       pBaseTypeOut - var_types pointer, if the tree node is the tree we want, we set *pBaseTypeOut 
9263 //                      to simd lclvar's base type.
9264 //       indexOut - unsigned pointer, if the tree is used for simd intrinsic, we will set *indexOut 
9265 //                  equals to the index number of this field.
9266 //       simdSizeOut - unsigned pointer, if the tree is used for simd intrinsic, set the *simdSizeOut 
9267 //                     equals to the simd struct size which this tree belongs to.   
9268 //      ignoreUsedInSIMDIntrinsic - bool. If this is set to true, then this function will ignore 
9269 //                                  the UsedInSIMDIntrinsic check.
9270 //
9271 // return value:
9272 //       A GenTreePtr which points the simd lclvar tree belongs to. If the tree is not the simd 
9273 //       instrinic related field, return nullptr. 
9274 //
9275
9276 GenTreePtr Compiler::getSIMDStructFromField(GenTreePtr tree, var_types* pBaseTypeOut, unsigned* indexOut, unsigned* simdSizeOut, bool ignoreUsedInSIMDIntrinsic/*false*/)
9277 {
9278     GenTreePtr ret = nullptr;
9279     if(tree->OperGet() == GT_FIELD)
9280     {
9281         GenTreePtr objRef = tree->gtField.gtFldObj;
9282         if (objRef != nullptr)
9283         {
9284             GenTreePtr obj = nullptr;
9285             if (objRef->gtOper == GT_ADDR)
9286             {
9287                 obj = objRef->gtOp.gtOp1;
9288             }
9289             else if(ignoreUsedInSIMDIntrinsic)
9290             {
9291                 obj = objRef;
9292             }
9293             else
9294             {
9295                 return nullptr;
9296             }
9297             
9298             if (isSIMDTypeLocal(obj))
9299             {
9300                 unsigned    lclNum = obj->gtLclVarCommon.gtLclNum;
9301                 LclVarDsc*  varDsc = &lvaTable[lclNum];
9302                 if(varDsc->lvIsUsedInSIMDIntrinsic() || ignoreUsedInSIMDIntrinsic)
9303                 {
9304                     *simdSizeOut = varDsc->lvExactSize;
9305                     *pBaseTypeOut = getBaseTypeOfSIMDLocal(obj);
9306                     ret = obj;
9307                 }
9308             }
9309             else if (obj->OperGet() == GT_SIMD)
9310             {
9311                 ret = obj;
9312                 GenTreeSIMD* simdNode = obj->AsSIMD();
9313                 *simdSizeOut = simdNode->gtSIMDSize;
9314                 *pBaseTypeOut = simdNode->gtSIMDBaseType;
9315             }
9316         }
9317     }
9318     if (ret != nullptr)
9319     {
9320         unsigned BaseTypeSize = genTypeSize(*pBaseTypeOut);
9321         *indexOut = tree->gtField.gtFldOffset / BaseTypeSize;
9322     }
9323     return ret;
9324 }   
9325   
9326 /*****************************************************************************
9327 *  If a read operation tries to access simd struct field, then transform the this
9328 *  operation to to the SIMD intrinsic SIMDIntrinsicGetItem, and return the new tree. 
9329 *  Otherwise, return the old tree. 
9330 *  Argument:
9331 *   tree - GenTreePtr. If this pointer points to simd struct which is used for simd 
9332 *          intrinsic. We will morph it as simd intrinsic SIMDIntrinsicGetItem. 
9333 *  Return:
9334 *   A GenTreePtr which points to the new tree. If the tree is not for simd intrinsic,
9335 *   return nullptr. 
9336 */
9337
9338 GenTreePtr Compiler::fgMorphFieldToSIMDIntrinsicGet(GenTreePtr tree)
9339 {
9340     unsigned index = 0;
9341     var_types baseType = TYP_UNKNOWN; 
9342     unsigned simdSize = 0;
9343     GenTreePtr simdStructNode = getSIMDStructFromField(tree, &baseType, &index, &simdSize);
9344     if(simdStructNode != nullptr)
9345     {
9346         
9347         assert(simdSize >= ((index + 1) * genTypeSize(baseType)));
9348         GenTree* op2 = gtNewIconNode(index);   
9349         tree =  gtNewSIMDNode(baseType, simdStructNode, op2, SIMDIntrinsicGetItem, baseType, simdSize); 
9350 #ifdef DEBUG
9351         tree->gtFlags |= GTF_MORPHED;
9352 #endif
9353     }
9354     return tree;
9355 }    
9356
9357 /*****************************************************************************
9358 *  Transform an assignment of a SIMD struct field to SIMD intrinsic 
9359 *  SIMDIntrinsicGetItem, and return a new tree. If If it is not such an assignment,
9360 *  then return the old tree. 
9361 *  Argument:
9362 *   tree - GenTreePtr. If this pointer points to simd struct which is used for simd 
9363 *          intrinsic. We will morph it as simd intrinsic set. 
9364 *  Return:
9365 *   A GenTreePtr which points to the new tree. If the tree is not for simd intrinsic,
9366 *   return nullptr. 
9367 */
9368
9369 GenTreePtr  Compiler::fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree)
9370 {
9371     assert(tree->OperGet() == GT_ASG);
9372     GenTreePtr op1 = tree->gtGetOp1();
9373     GenTreePtr op2 = tree->gtGetOp2();
9374     
9375     unsigned index = 0;
9376     var_types baseType = TYP_UNKNOWN; 
9377     unsigned simdSize = 0;
9378     GenTreePtr simdOp1Struct = getSIMDStructFromField(op1, &baseType, &index, &simdSize);
9379     if (simdOp1Struct != nullptr)
9380     {
9381         //Generate the simd set intrinsic
9382         assert(simdSize >= ((index + 1) * genTypeSize(baseType)));
9383         
9384         SIMDIntrinsicID simdIntrinsicID = SIMDIntrinsicInvalid;     
9385         switch (index)
9386         {
9387         case 0:
9388             simdIntrinsicID = SIMDIntrinsicSetX;
9389             break;
9390         case 1:
9391             simdIntrinsicID = SIMDIntrinsicSetY;
9392             break;
9393         case 2:
9394             simdIntrinsicID = SIMDIntrinsicSetZ;
9395             break;
9396         case 3: 
9397             simdIntrinsicID = SIMDIntrinsicSetW;
9398             break;
9399         default:
9400             noway_assert("There is no set intrinsic for index bigger than 3");
9401         }
9402         
9403
9404         GenTreePtr newStruct = gtClone(simdOp1Struct);
9405         assert((newStruct != nullptr) && (varTypeIsSIMD(newStruct)));
9406         GenTreePtr simdTree = gtNewSIMDNode(newStruct->gtType, simdOp1Struct, op2, simdIntrinsicID, baseType, simdSize);
9407         GenTreePtr copyBlkDst = gtNewOperNode(GT_ADDR, TYP_BYREF, newStruct);
9408         tree = gtNewBlkOpNode(GT_COPYBLK,
9409                             copyBlkDst,
9410                             gtNewOperNode(GT_ADDR, TYP_BYREF,  simdTree),
9411                             gtNewIconNode(simdSize),
9412                             false);
9413 #ifdef DEBUG
9414         tree->gtFlags |= GTF_MORPHED;
9415 #endif
9416     }
9417     
9418     return tree;
9419 }
9420
9421 #endif
9422 /*****************************************************************************
9423  *
9424  *  Transform the given GTK_SMPOP tree for code generation.
9425  */
9426
9427 #ifdef _PREFAST_
9428 #pragma warning(push)
9429 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
9430 #endif
9431 GenTreePtr          Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
9432 {
9433     // this extra scope is a workaround for a gcc bug
9434     // the inline destructor for ALLOCA_CHECK confuses the control
9435     // flow and gcc thinks that the function never returns
9436     {
9437     ALLOCA_CHECK();
9438     noway_assert(tree->OperKind() & GTK_SMPOP);
9439
9440     /* The steps in this function are :
9441        o Perform required preorder processing
9442        o Process the first, then second operand, if any
9443        o Perform required postorder morphing
9444        o Perform optional postorder morphing if optimizing
9445      */
9446
9447     bool            isQmarkColon     = false;
9448
9449 #if LOCAL_ASSERTION_PROP
9450     AssertionIndex  origAssertionCount = DUMMY_INIT(0);
9451     AssertionDsc *  origAssertionTab   = DUMMY_INIT(NULL);
9452
9453     AssertionIndex  thenAssertionCount = DUMMY_INIT(0);
9454     AssertionDsc *  thenAssertionTab   = DUMMY_INIT(NULL);
9455 #endif
9456
9457     if (fgGlobalMorph)
9458     {
9459 #if !FEATURE_STACK_FP_X87
9460         tree = fgMorphForRegisterFP(tree);
9461 #endif
9462     }
9463
9464     genTreeOps      oper    = tree->OperGet();
9465     var_types       typ     = tree->TypeGet();
9466     GenTreePtr      op1     = tree->gtOp.gtOp1;
9467     GenTreePtr      op2     = tree->gtGetOp2();
9468
9469     /*-------------------------------------------------------------------------
9470      * First do any PRE-ORDER processing
9471      */
9472
9473     switch (oper)
9474     {
9475         // Some arithmetic operators need to use a helper call to the EE
9476         int         helper;
9477
9478     case GT_ASG:
9479         tree = fgDoNormalizeOnStore(tree);
9480         /* fgDoNormalizeOnStore can change op2 */
9481         noway_assert(op1 == tree->gtOp.gtOp1);
9482         op2 = tree->gtOp.gtOp2;
9483
9484 #ifdef FEATURE_SIMD
9485         {
9486             // We should check whether op2 should be assigned to a SIMD field or not.
9487             // if it is, we should tranlate the tree to simd intrinsic
9488             GenTreePtr newTree = fgMorphFieldAssignToSIMDIntrinsicSet(tree);
9489             if (newTree != tree)
9490             {
9491                 tree = newTree;
9492                 oper    = tree->OperGet();
9493                 typ     = tree->TypeGet();
9494                 op1 = tree->gtOp.gtOp1;
9495                 op2 = tree->gtGetOp2();
9496             }
9497         }        
9498 #endif
9499
9500         __fallthrough;
9501
9502     case GT_ASG_ADD:
9503     case GT_ASG_SUB:
9504     case GT_ASG_MUL:
9505     case GT_ASG_DIV:
9506     case GT_ASG_MOD:
9507     case GT_ASG_UDIV:
9508     case GT_ASG_UMOD:
9509     case GT_ASG_OR:
9510     case GT_ASG_XOR:
9511     case GT_ASG_AND:
9512     case GT_ASG_LSH:
9513     case GT_ASG_RSH:
9514     case GT_ASG_RSZ:
9515     case GT_CHS:
9516
9517         /* We can't CSE the LHS of an assignment. Only r-values can be CSEed */
9518         op1->gtFlags |= GTF_DONT_CSE;
9519         break;
9520
9521     case GT_ADDR:
9522
9523         /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
9524         op1->gtFlags |= GTF_DONT_CSE;
9525         break;
9526
9527     case GT_QMARK:
9528     case GT_JTRUE:
9529
9530         noway_assert(op1);
9531
9532         if (op1->OperKind() & GTK_RELOP)
9533         {
9534             noway_assert((oper == GT_JTRUE) || (op1->gtFlags & GTF_RELOP_QMARK));
9535             /* Mark the comparison node with GTF_RELOP_JMP_USED so it knows that it does
9536                not need to materialize the result as a 0 or 1. */
9537
9538             /* We also mark it as DONT_CSE, as we don't handle QMARKs with nonRELOP op1s */
9539             op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
9540
9541             // Request that the codegen for op1 sets the condition flags
9542             // when it generates the code for op1.
9543             //
9544             // Codegen for op1 must set the condition flags if
9545             // this method returns true.
9546             //
9547             op1->gtRequestSetFlags();
9548         }
9549         else
9550         {
9551             GenTreePtr effOp1 = op1->gtEffectiveVal();
9552             
9553             noway_assert( (effOp1->gtOper == GT_CNS_INT) &&
9554                          ((effOp1->gtIntCon.gtIconVal == 0) || (effOp1->gtIntCon.gtIconVal == 1)) );
9555         }
9556         break;
9557
9558     case GT_COLON:
9559 #if LOCAL_ASSERTION_PROP
9560         if (optLocalAssertionProp)
9561 #endif
9562             isQmarkColon = true;
9563         break;
9564
9565     case GT_INDEX:
9566         return fgMorphArrayIndex(tree);
9567
9568     case GT_CAST:
9569         return fgMorphCast(tree);
9570
9571     case GT_MUL:
9572
9573 #ifndef _TARGET_64BIT_
9574         if  (typ == TYP_LONG)
9575         {
9576             /* For (long)int1 * (long)int2, we dont actually do the
9577                casts, and just multiply the 32 bit values, which will
9578                give us the 64 bit result in edx:eax */
9579
9580             noway_assert(op2);
9581             if  ((op1->gtOper                                 == GT_CAST &&
9582                   op2->gtOper                                 == GT_CAST &&
9583                   genActualType(op1->CastFromType()) == TYP_INT &&
9584                   genActualType(op2->CastFromType()) == TYP_INT)&&
9585                   !op1->gtOverflow() && !op2->gtOverflow())
9586             {
9587                 // The casts have to be of the same signedness.
9588                 if ((op1->gtFlags & GTF_UNSIGNED) != (op2->gtFlags & GTF_UNSIGNED))
9589                 {
9590                     //We see if we can force an int constant to change its signedness
9591                     GenTreePtr constOp;
9592                     if (op1->gtCast.CastOp()->gtOper == GT_CNS_INT)
9593                         constOp = op1;
9594                     else if (op2->gtCast.CastOp()->gtOper == GT_CNS_INT)
9595                         constOp = op2;
9596                     else
9597                         goto NO_MUL_64RSLT;
9598
9599                     if ( ((unsigned)(constOp->gtCast.CastOp()->gtIntCon.gtIconVal) < (unsigned)(0x80000000)) )
9600                         constOp->gtFlags ^=  GTF_UNSIGNED;
9601                     else
9602                         goto NO_MUL_64RSLT;
9603                 }
9604
9605                 // The only combination that can overflow
9606                 if (tree->gtOverflow() && (tree->gtFlags & GTF_UNSIGNED) &&
9607                                          !( op1->gtFlags & GTF_UNSIGNED))
9608                     goto NO_MUL_64RSLT;
9609
9610                 /* Remaining combinations can never overflow during long mul. */
9611
9612                 tree->gtFlags &= ~GTF_OVERFLOW;
9613
9614                 /* Do unsigned mul only if the casts were unsigned */
9615
9616                 tree->gtFlags &= ~GTF_UNSIGNED;
9617                 tree->gtFlags |= op1->gtFlags & GTF_UNSIGNED;
9618
9619                 /* Since we are committing to GTF_MUL_64RSLT, we don't want
9620                    the casts to be folded away. So morph the castees directly */
9621
9622                 op1->gtOp.gtOp1 = fgMorphTree(op1->gtOp.gtOp1);
9623                 op2->gtOp.gtOp1 = fgMorphTree(op2->gtOp.gtOp1);
9624
9625                 // Propagate side effect flags up the tree
9626                 op1->gtFlags &= ~GTF_ALL_EFFECT;
9627                 op1->gtFlags |= (op1->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
9628                 op2->gtFlags &= ~GTF_ALL_EFFECT;
9629                 op2->gtFlags |= (op2->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
9630
9631                 // If the GT_MUL can be altogether folded away, we should do that.
9632
9633                 if ((op1->gtCast.CastOp()->OperKind() &
9634                      op2->gtCast.CastOp()->OperKind() & GTK_CONST) && opts.OptEnabled(CLFLG_CONSTANTFOLD))
9635                 {
9636                     tree->gtOp.gtOp1 = op1 = gtFoldExprConst(op1);
9637                     tree->gtOp.gtOp2 = op2 = gtFoldExprConst(op2);
9638                     noway_assert(op1->OperKind() & op2->OperKind() & GTK_CONST);
9639                     tree = gtFoldExprConst(tree);
9640                     noway_assert(tree->OperIsConst());
9641                     return tree;
9642                 }
9643
9644                 tree->gtFlags |= GTF_MUL_64RSLT;
9645
9646                 // If op1 and op2 are unsigned casts, we need to do an unsigned mult
9647                 tree->gtFlags |= (op1->gtFlags & GTF_UNSIGNED);
9648
9649                 // Insert GT_NOP nodes for the cast operands so that they do not get folded
9650                 // And propagate the new flags. We don't want to CSE the casts because
9651                 // codegen expects GTF_MUL_64RSLT muls to have a certain layout.
9652
9653                 if  (op1->gtCast.CastOp()->OperGet() != GT_NOP)
9654                 {
9655                     op1->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op1->gtCast.CastOp());
9656                     op1->gtFlags  &= ~GTF_ALL_EFFECT;
9657                     op1->gtFlags  |= (op1->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
9658                     op1->gtFlags  |= GTF_DONT_CSE;
9659                 }
9660
9661                 if (op2->gtCast.CastOp()->OperGet() != GT_NOP)
9662                 {
9663                     op2->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op2->gtCast.CastOp());
9664                     op2->gtFlags  &= ~GTF_ALL_EFFECT;
9665                     op2->gtFlags  |= (op2->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
9666                     op2->gtFlags  |= GTF_DONT_CSE;
9667                 }
9668
9669                 tree->gtFlags &= ~GTF_ALL_EFFECT;
9670                 tree->gtFlags |= ((op1->gtFlags | op2->gtFlags) & GTF_ALL_EFFECT);
9671
9672                 goto DONE_MORPHING_CHILDREN;
9673             }
9674             else if ((tree->gtFlags & GTF_MUL_64RSLT) == 0)
9675             {
9676 NO_MUL_64RSLT:
9677                 if (tree->gtOverflow())
9678                     helper = (tree->gtFlags & GTF_UNSIGNED) ? CORINFO_HELP_ULMUL_OVF
9679                                                             : CORINFO_HELP_LMUL_OVF;
9680                 else
9681                     helper = CORINFO_HELP_LMUL;
9682
9683                 goto USE_HELPER_FOR_ARITH;
9684             }
9685             else
9686             {
9687                 /* We are seeing this node again. We have decided to use
9688                    GTF_MUL_64RSLT, so leave it alone. */
9689
9690                 assert(tree->gtIsValid64RsltMul());
9691             }
9692         }
9693 #endif // !_TARGET_64BIT_
9694         break;
9695
9696
9697     case GT_DIV:
9698
9699 #ifndef _TARGET_64BIT_
9700         if  (typ == TYP_LONG)
9701         {
9702             helper = CORINFO_HELP_LDIV;
9703             goto USE_HELPER_FOR_ARITH;
9704         }
9705
9706 #if  USE_HELPERS_FOR_INT_DIV
9707         if  (typ == TYP_INT && !fgIsSignedDivOptimizable(op2))
9708         {
9709             helper = CORINFO_HELP_DIV;
9710             goto USE_HELPER_FOR_ARITH;
9711         }
9712 #endif
9713 #endif // !_TARGET_64BIT_
9714
9715 #ifndef LEGACY_BACKEND
9716         if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
9717         {
9718             op2 = gtFoldExprConst(op2);
9719         }
9720         
9721         if (fgShouldUseMagicNumberDivide(tree->AsOp()))
9722         {
9723             tree = fgMorphDivByConst(tree->AsOp());
9724             op1 = tree->gtOp.gtOp1;
9725             op2 = tree->gtOp.gtOp2; 
9726         }
9727 #endif // !LEGACY_BACKEND
9728         break;
9729
9730
9731     case GT_UDIV:
9732
9733 #ifndef _TARGET_64BIT_
9734         if  (typ == TYP_LONG)
9735         {
9736             helper = CORINFO_HELP_ULDIV;
9737             goto USE_HELPER_FOR_ARITH;
9738         }
9739 #if  USE_HELPERS_FOR_INT_DIV
9740         if  (typ == TYP_INT && !fgIsUnsignedDivOptimizable(op2))
9741         {
9742             helper = CORINFO_HELP_UDIV;
9743             goto USE_HELPER_FOR_ARITH;
9744         }
9745 #endif
9746 #endif // _TARGET_64BIT_
9747         break;
9748
9749
9750     case GT_MOD:
9751
9752         if  (varTypeIsFloating(typ))
9753         {
9754             helper = CORINFO_HELP_DBLREM;
9755             noway_assert(op2);
9756             if (op1->TypeGet() == TYP_FLOAT)
9757                 if (op2->TypeGet() == TYP_FLOAT)
9758                     helper = CORINFO_HELP_FLTREM;
9759                 else
9760                     tree->gtOp.gtOp1 = op1 = gtNewCastNode(TYP_DOUBLE, op1, TYP_DOUBLE);
9761             else
9762                 if (op2->TypeGet() == TYP_FLOAT)
9763                     tree->gtOp.gtOp2 = op2 = gtNewCastNode(TYP_DOUBLE, op2, TYP_DOUBLE);
9764             goto USE_HELPER_FOR_ARITH;
9765         }
9766
9767         // Do not use optimizations (unlike UMOD's idiv optimizing during codegen) for signed mod.
9768         // A similar optimization for signed mod will not work for a negative perfectly divisible
9769         // HI-word. To make it correct, we would need to divide without the sign and then flip the
9770         // result sign after mod. This requires 18 opcodes + flow making it not worthy to inline.
9771         goto ASSIGN_HELPER_FOR_MOD;
9772
9773     case GT_UMOD:
9774
9775 #ifdef _TARGET_ARMARCH_
9776         //
9777         // Note for _TARGET_ARMARCH_ we don't have  a remainder instruction, so we don't do this optimization
9778         //
9779 #else // _TARGET_XARCH
9780         /* If this is an unsigned long mod with op2 which is a cast to long from a
9781            constant int, then don't morph to a call to the helper.  This can be done
9782            faster inline using idiv.
9783         */
9784
9785         noway_assert(op2);
9786         if ((typ == TYP_LONG) && opts.OptEnabled(CLFLG_CONSTANTFOLD) &&
9787             ((tree->gtFlags & GTF_UNSIGNED) == (op1->gtFlags & GTF_UNSIGNED)) &&
9788             ((tree->gtFlags & GTF_UNSIGNED) == (op2->gtFlags & GTF_UNSIGNED)))
9789         {
9790             if (op2->gtOper == GT_CAST                                 &&
9791                 op2->gtCast.CastOp()->gtOper == GT_CNS_INT             &&
9792                 op2->gtCast.CastOp()->gtIntCon.gtIconVal >= 2          &&
9793                 op2->gtCast.CastOp()->gtIntCon.gtIconVal <= 0x3fffffff &&
9794                 (tree->gtFlags & GTF_UNSIGNED) == (op2->gtCast.CastOp()->gtFlags & GTF_UNSIGNED))
9795             {
9796                 tree->gtOp.gtOp2 = op2 = fgMorphCast(op2);
9797                 noway_assert(op2->gtOper == GT_CNS_NATIVELONG);
9798             }
9799
9800             if (op2->gtOper == GT_CNS_NATIVELONG             &&
9801                 op2->gtIntConCommon.LngValue() >= 2          &&
9802                 op2->gtIntConCommon.LngValue() <= 0x3fffffff)
9803             {
9804                 tree->gtOp.gtOp1 = op1 = fgMorphTree(op1);
9805                 noway_assert(op1->TypeGet() == TYP_LONG);
9806
9807                 // Update flags for op1 morph
9808                 tree->gtFlags &= ~GTF_ALL_EFFECT;
9809
9810                 tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT); // Only update with op1 as op2 is a constant
9811
9812                 // If op1 is a constant, then do constant folding of the division operator
9813                 if (op1->gtOper == GT_CNS_NATIVELONG)
9814                 {
9815                     tree = gtFoldExpr(tree);
9816                 }
9817                 return tree;
9818             }
9819         }
9820 #endif // _TARGET_XARCH
9821
9822     ASSIGN_HELPER_FOR_MOD:
9823
9824         // For "val % 1", return 0 if op1 doesn't have any side effects
9825         // and we are not in the CSE phase, we cannot discard 'tree'
9826         // because it may contain CSE expressions that we haven't yet examined.
9827         //
9828         if (((op1->gtFlags & GTF_SIDE_EFFECT) == 0) && !optValnumCSE_phase)
9829         {
9830             if (((op2->gtOper == GT_CNS_INT) && (op2->gtIntConCommon.IconValue() == 1))
9831                 || ((op2->gtOper == GT_CNS_LNG) && (op2->gtIntConCommon.LngValue() == 1)))
9832             {
9833                 GenTreePtr zeroNode = gtNewZeroConNode(typ);
9834 #ifdef DEBUG
9835                 zeroNode->gtFlags |= GTF_MORPHED;
9836 #endif
9837                 DEBUG_DESTROY_NODE(tree);
9838                 return zeroNode;
9839             }
9840         }
9841
9842 #ifndef  _TARGET_64BIT_
9843         if  (typ == TYP_LONG)
9844         {
9845             helper = (oper == GT_UMOD) ? CORINFO_HELP_ULMOD : CORINFO_HELP_LMOD;
9846             goto USE_HELPER_FOR_ARITH;
9847         }
9848
9849 #if  USE_HELPERS_FOR_INT_DIV
9850         if  (typ == TYP_INT)
9851         {
9852             if (oper == GT_UMOD && !fgIsUnsignedModOptimizable(op2))
9853             {
9854                 helper = CORINFO_HELP_UMOD;
9855                 goto USE_HELPER_FOR_ARITH;
9856             }
9857             else if (oper == GT_MOD && !fgIsSignedModOptimizable(op2))
9858             {
9859                 helper = CORINFO_HELP_MOD;
9860                 goto USE_HELPER_FOR_ARITH;
9861             }
9862         }
9863 #endif
9864 #endif // !_TARGET_64BIT_
9865
9866 #ifndef LEGACY_BACKEND
9867         if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
9868         {
9869             op2 = gtFoldExprConst(op2);
9870         }
9871
9872 #ifdef _TARGET_ARM64_
9873
9874         // For ARM64 we don't have a remainder instruction,
9875         // The architecture manual suggests the following transformation to 
9876         // generate code for such operator:
9877         //
9878         // a % b = a - (a / b) * b;
9879         //
9880         tree = fgMorphModToSubMulDiv(tree->AsOp());
9881         op1 = tree->gtOp.gtOp1;
9882         op2 = tree->gtOp.gtOp2;
9883
9884 #else  // !_TARGET_ARM64_
9885
9886         if (oper != GT_UMOD && fgShouldUseMagicNumberDivide(tree->AsOp()))
9887         {
9888             tree = fgMorphModByConst(tree->AsOp());
9889             op1 = tree->gtOp.gtOp1;
9890             op2 = tree->gtOp.gtOp2; 
9891         }
9892
9893 #endif //_TARGET_ARM64_
9894 #endif // !LEGACY_BACKEND
9895         break;
9896
9897     USE_HELPER_FOR_ARITH:
9898         {
9899             /* We have to morph these arithmetic operations into helper calls
9900                before morphing the arguments (preorder), else the arguments
9901                won't get correct values of fgPtrArgCntCur.
9902                However, try to fold the tree first in case we end up with a
9903                simple node which won't need a helper call at all */
9904
9905             noway_assert(tree->OperIsBinary());
9906
9907             GenTreePtr oldTree = tree;
9908
9909             tree = gtFoldExpr(tree);
9910
9911             // Were we able to fold it ?
9912             // Note that gtFoldExpr may return a non-leaf even if successful
9913             // e.g. for something like "expr / 1" - see also bug #290853
9914             if (tree->OperIsLeaf() || (oldTree != tree))
9915
9916             {
9917                 return (oldTree != tree) ? fgMorphTree(tree) : fgMorphLeaf(tree);
9918             }
9919
9920             // Did we fold it into a comma node with throw?
9921             if (tree->gtOper == GT_COMMA)
9922             {
9923                 noway_assert(fgIsCommaThrow(tree));
9924                 return fgMorphTree(tree);
9925             }
9926         }
9927         return fgMorphIntoHelperCall(tree, helper, gtNewArgList(op1, op2));
9928
9929     case GT_RETURN:
9930         // normalize small integer return values
9931         if (fgGlobalMorph && varTypeIsSmall(info.compRetType) &&
9932             (op1 != NULL) && (op1->TypeGet() != TYP_VOID) &&
9933             fgCastNeeded(op1, info.compRetType))
9934         {
9935             // Small-typed return values are normalized by the callee
9936             op1 = gtNewCastNode(TYP_INT, op1, info.compRetType);
9937
9938             // Propagate GTF_COLON_COND
9939             op1->gtFlags|=(tree->gtFlags & GTF_COLON_COND);
9940
9941             tree->gtOp.gtOp1 = fgMorphCast(op1);
9942
9943             // Propagate side effect flags
9944             tree->gtFlags &= ~GTF_ALL_EFFECT;
9945             tree->gtFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
9946
9947             return tree;
9948         }
9949         break;
9950
9951     case GT_EQ:
9952     case GT_NE:
9953
9954         // Check for typeof(...) == obj.GetType()
9955         // Also check for typeof(...) == typeof(...)
9956         // IMPORTANT NOTE: this optimization relies on a one-to-one mapping between
9957         // type handles and instances of System.Type
9958         // If this invariant is ever broken, the optimization will need updating
9959
9960 #ifdef LEGACY_BACKEND
9961         if ( op1->gtOper == GT_CALL &&
9962             op2->gtOper == GT_CALL &&
9963             ((op1->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) || (op1->gtCall.gtCallType == CT_HELPER)) &&
9964             ((op2->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) || (op2->gtCall.gtCallType == CT_HELPER)))
9965 #else
9966         if ((((op1->gtOper == GT_INTRINSIC) && (op1->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)) || 
9967              ((op1->gtOper == GT_CALL) && (op1->gtCall.gtCallType == CT_HELPER))) &&
9968             (((op2->gtOper == GT_INTRINSIC) && (op2->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)) ||
9969              ((op2->gtOper == GT_CALL) && (op2->gtCall.gtCallType == CT_HELPER))))
9970 #endif
9971         {
9972             GenTreePtr  pGetClassFromHandle;
9973             GenTreePtr  pGetType;
9974
9975 #ifdef LEGACY_BACKEND
9976             bool bOp1ClassFromHandle = gtIsTypeHandleToRuntimeTypeHelper(op1);
9977             bool bOp2ClassFromHandle = gtIsTypeHandleToRuntimeTypeHelper(op2);
9978 #else
9979             bool bOp1ClassFromHandle = op1->gtOper == GT_CALL ? gtIsTypeHandleToRuntimeTypeHelper(op1) : false;
9980             bool bOp2ClassFromHandle = op2->gtOper == GT_CALL ? gtIsTypeHandleToRuntimeTypeHelper(op2) : false;
9981 #endif
9982
9983             // Optimize typeof(...) == typeof(...)
9984             // Typically this occurs in generic code that attempts a type switch
9985             // e.g. typeof(T) == typeof(int)
9986
9987             if (bOp1ClassFromHandle && bOp2ClassFromHandle)
9988             {
9989                 GenTreePtr classFromHandleArg1 = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
9990                 GenTreePtr classFromHandleArg2 = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
9991
9992                 GenTreePtr compare = gtNewOperNode(oper, TYP_INT,
9993                                                    classFromHandleArg1,
9994                                                    classFromHandleArg2);
9995
9996                 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
9997
9998                 // Morph and return
9999                 return fgMorphTree(compare);
10000             }
10001             else if (bOp1ClassFromHandle || bOp2ClassFromHandle)
10002             {
10003                 //
10004                 // Now check for GetClassFromHandle(handle) == obj.GetType()
10005                 //
10006
10007                 if (bOp1ClassFromHandle)
10008                 {
10009                     pGetClassFromHandle = tree->gtOp.gtOp1;
10010                     pGetType = op2;
10011                 }
10012                 else
10013                 {
10014                     pGetClassFromHandle = tree->gtOp.gtOp2;
10015                     pGetType = op1;
10016                 }
10017
10018                 GenTreePtr pGetClassFromHandleArgument = pGetClassFromHandle->gtCall.gtCallArgs->gtOp.gtOp1;
10019                 GenTreePtr pConstLiteral = pGetClassFromHandleArgument;
10020
10021                 // Unwrap GT_NOP node used to prevent constant folding
10022                 if (pConstLiteral->gtOper == GT_NOP && pConstLiteral->gtType == TYP_I_IMPL)
10023                 {
10024                     pConstLiteral = pConstLiteral->gtOp.gtOp1;
10025                 }
10026
10027                 // In the ngen case, we have to go thru an indirection to get the right handle.
10028                 if (pConstLiteral->gtOper == GT_IND)
10029                 {
10030                     pConstLiteral = pConstLiteral->gtOp.gtOp1;
10031                 }
10032 #ifdef LEGACY_BACKEND
10033
10034                 if (pGetType->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC &&
10035                     info.compCompHnd->getIntrinsicID(pGetType->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType &&
10036 #else
10037                 if ((pGetType->gtOper == GT_INTRINSIC) && (pGetType->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType) &&
10038 #endif
10039                     pConstLiteral->gtOper == GT_CNS_INT &&
10040                     pConstLiteral->gtType == TYP_I_IMPL)
10041                 {
10042                     CORINFO_CLASS_HANDLE clsHnd = CORINFO_CLASS_HANDLE(pConstLiteral->gtIntCon.gtCompileTimeHandle);
10043
10044                     if (info.compCompHnd->canInlineTypeCheckWithObjectVTable(clsHnd))
10045                     {
10046                         // Method Table tree
10047 #ifdef LEGACY_BACKEND
10048                         GenTreePtr objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, pGetType->gtCall.gtCallObjp);
10049 #else
10050                         GenTreePtr objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, pGetType->gtUnOp.gtOp1);
10051 #endif
10052                         objMT->gtFlags |= GTF_EXCEPT; // Null ref exception if object is null
10053                         compCurBB->bbFlags |= BBF_HAS_VTABREF;
10054                         optMethodFlags |= OMF_HAS_VTABLEREF;
10055
10056                         // Method table constant
10057                         GenTreePtr cnsMT = pGetClassFromHandleArgument;
10058
10059                         GenTreePtr compare = gtNewOperNode(oper, TYP_INT,
10060                                                            objMT,
10061                                                            cnsMT);
10062
10063                         compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
10064
10065                         // Morph and return
10066                         return fgMorphTree(compare);
10067                     }
10068                 }
10069             }
10070         }
10071         fgMorphRecognizeBoxNullable(tree);
10072         op1 = tree->gtOp.gtOp1;
10073         op2 = tree->gtGetOp2();
10074
10075         break;
10076
10077 #ifdef _TARGET_ARM_
10078     case GT_INTRINSIC:
10079         if (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round)
10080         {
10081             switch (tree->TypeGet())
10082             {
10083             case TYP_DOUBLE:
10084                 return fgMorphIntoHelperCall(tree, CORINFO_HELP_DBLROUND, gtNewArgList(op1));
10085             case TYP_FLOAT:
10086                 return fgMorphIntoHelperCall(tree, CORINFO_HELP_FLTROUND, gtNewArgList(op1));
10087             default:
10088                 unreached();
10089             }
10090         }
10091         break;
10092 #endif
10093
10094     default:
10095         break;
10096     }
10097
10098 #if !CPU_HAS_FP_SUPPORT
10099     tree = fgMorphToEmulatedFP(tree);
10100 #endif
10101
10102     /* Could this operator throw an exception? */
10103     if  (fgGlobalMorph && tree->OperMayThrow())
10104     {
10105         if ((tree->OperGet() != GT_IND) || fgAddrCouldBeNull(tree->gtOp.gtOp1))
10106         {
10107             /* Mark the tree node as potentially throwing an exception */
10108             tree->gtFlags |= GTF_EXCEPT;
10109         }
10110     }
10111
10112     /*-------------------------------------------------------------------------
10113      * Process the first operand, if any
10114      */
10115
10116     if  (op1)
10117     {
10118
10119 #if LOCAL_ASSERTION_PROP
10120         // If we are entering the "then" part of a Qmark-Colon we must
10121         // save the state of the current copy assignment table
10122         // so that we can restore this state when entering the "else" part
10123         if (isQmarkColon)
10124         {
10125             noway_assert(optLocalAssertionProp);
10126             if (optAssertionCount)
10127             {
10128                 noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
10129                 unsigned tabSize     = optAssertionCount * sizeof(AssertionDsc);
10130                 origAssertionTab   = (AssertionDsc*) ALLOCA(tabSize);
10131                 origAssertionCount = optAssertionCount;
10132                 memcpy(origAssertionTab, optAssertionTabPrivate, tabSize);
10133             }
10134             else
10135             {
10136                 origAssertionCount = 0;
10137                 origAssertionTab   = NULL;
10138             }
10139         }
10140 #endif // LOCAL_ASSERTION_PROP
10141
10142         // We might need a new MorphAddressContext context.  (These are used to convey
10143         // parent context about how addresses being calculated will be used; see the
10144         // specification comment for MorphAddrContext for full details.)
10145         // Assume it's an Ind context to start.
10146         MorphAddrContext subIndMac1(MACK_Ind);
10147         MorphAddrContext* subMac1 = mac;
10148         if (subMac1 == NULL || subMac1->m_kind == MACK_Ind || subMac1->m_kind == MACK_CopyBlock)
10149         {
10150             switch (tree->gtOper)
10151             {
10152             case GT_ADDR:
10153                 if (subMac1 == NULL)
10154                 {
10155                     subMac1 = &subIndMac1;
10156                     subMac1->m_kind = MACK_Addr;
10157                 }
10158                 break;
10159             case GT_COMMA:
10160                 // In a comma, the incoming context only applies to the rightmost arg of the
10161                 // comma list.  The left arg (op1) gets a fresh context.
10162                 subMac1 = NULL;
10163                 break;
10164             case GT_COPYBLK:
10165             case GT_COPYOBJ:
10166                 assert(subMac1 == NULL); // Should only occur at top level, since value is void.
10167                 subMac1 = &s_CopyBlockMAC;
10168                 break;
10169             case GT_LIST:
10170                 // If the list is the first arg of a copy block, its two args should be evaluated as
10171                 // IND-context addresses, separately.
10172                 if (subMac1 != NULL && subMac1->m_kind == MACK_CopyBlock)
10173                 {
10174                     subMac1 = &subIndMac1;
10175                 }
10176                 break;
10177             case GT_IND:
10178             case GT_INITBLK:
10179             case GT_OBJ:
10180                 subMac1 = &subIndMac1;
10181                 break;
10182             default:
10183                 break;
10184             }
10185         }
10186
10187         // For additions, if we're in an IND context keep track of whether
10188         // all offsets added to the address are constant, and their sum.
10189         if (tree->gtOper == GT_ADD && subMac1 != NULL)
10190         {
10191             assert(subMac1->m_kind == MACK_Ind || subMac1->m_kind == MACK_Addr); // Can't be a CopyBlock.
10192             GenTreePtr otherOp = tree->gtOp.gtOp2;
10193             // Is the other operator a constant?
10194             if (otherOp->IsCnsIntOrI())
10195             {
10196                 ClrSafeInt<size_t> totalOffset(subMac1->m_totalOffset);
10197                 totalOffset += otherOp->gtIntConCommon.IconValue();
10198                 if (totalOffset.IsOverflow())
10199                 {
10200                     // We will consider an offset so large as to overflow as "not a constant" --
10201                     // we will do a null check.
10202                     subMac1->m_allConstantOffsets = false;
10203                 }
10204                 else
10205                 {
10206                     subMac1->m_totalOffset += otherOp->gtIntConCommon.IconValue();
10207                 }
10208             }
10209             else
10210             {
10211                 subMac1->m_allConstantOffsets = false;
10212             }
10213         }
10214
10215         tree->gtOp.gtOp1 = op1 = fgMorphTree(op1, subMac1);
10216
10217 #if LOCAL_ASSERTION_PROP
10218         // If we are exiting the "then" part of a Qmark-Colon we must
10219         // save the state of the current copy assignment table
10220         // so that we can merge this state with the "else" part exit
10221         if (isQmarkColon)
10222         {
10223             noway_assert(optLocalAssertionProp);
10224             if (optAssertionCount)
10225             {
10226                 noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
10227                 unsigned tabSize     = optAssertionCount * sizeof(AssertionDsc);
10228                 thenAssertionTab   = (AssertionDsc*) ALLOCA(tabSize);
10229                 thenAssertionCount = optAssertionCount;
10230                 memcpy(thenAssertionTab, optAssertionTabPrivate, tabSize);
10231             }
10232             else
10233             {
10234                 thenAssertionCount = 0;
10235                 thenAssertionTab   = NULL;
10236             }
10237         }
10238 #endif // LOCAL_ASSERTION_PROP
10239
10240         /* Morphing along with folding and inlining may have changed the
10241          * side effect flags, so we have to reset them
10242          *
10243          * NOTE: Don't reset the exception flags on nodes that may throw */
10244
10245         noway_assert(tree->gtOper != GT_CALL);
10246
10247         if ((tree->gtOper != GT_INTRINSIC) || !IsIntrinsicImplementedByUserCall(tree->gtIntrinsic.gtIntrinsicId))
10248         {
10249             tree->gtFlags &= ~GTF_CALL;
10250         }
10251
10252         if  (!tree->OperMayThrow())
10253             tree->gtFlags &= ~GTF_EXCEPT;
10254
10255         /* Propagate the new flags */
10256         tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
10257
10258         // &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does
10259         // Similarly for clsVar
10260         if (oper == GT_ADDR && (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_CLS_VAR))
10261             tree->gtFlags &= ~GTF_GLOB_REF;
10262     } // if (op1)
10263
10264     /*-------------------------------------------------------------------------
10265      * Process the second operand, if any
10266      */
10267
10268     if  (op2)
10269     {
10270
10271 #if LOCAL_ASSERTION_PROP
10272         // If we are entering the "else" part of a Qmark-Colon we must
10273         // reset the state of the current copy assignment table
10274         if (isQmarkColon)
10275         {
10276             noway_assert(optLocalAssertionProp);
10277             optAssertionReset(0);
10278             if (origAssertionCount)
10279             {
10280                 size_t tabSize    = origAssertionCount * sizeof(AssertionDsc);
10281                 memcpy(optAssertionTabPrivate, origAssertionTab, tabSize);
10282                 optAssertionReset(origAssertionCount);
10283             }
10284         }
10285 #endif // LOCAL_ASSERTION_PROP
10286
10287         // We might need a new MorphAddressContext context to use in evaluating op2.
10288         // (These are used to convey parent context about how addresses being calculated
10289         // will be used; see the specification comment for MorphAddrContext for full details.)
10290         // Assume it's an Ind context to start.
10291         MorphAddrContext subIndMac2(MACK_Ind);
10292         switch (tree->gtOper)
10293         {
10294         case GT_ADD:
10295             if (mac != NULL && mac->m_kind == MACK_Ind)
10296             {
10297                 GenTreePtr otherOp = tree->gtOp.gtOp1;
10298                 // Is the other operator a constant?
10299                 if (otherOp->IsCnsIntOrI())
10300                 {
10301                     mac->m_totalOffset += otherOp->gtIntConCommon.IconValue();
10302                 }
10303                 else
10304                 {
10305                     mac->m_allConstantOffsets = false;
10306                 }
10307             }
10308             break;
10309         case GT_LIST:
10310             if (mac != NULL && mac->m_kind == MACK_CopyBlock)
10311             {
10312                 mac = &subIndMac2;
10313             }
10314             break;
10315         default:
10316             break;
10317         }
10318         tree->gtOp.gtOp2 = op2 = fgMorphTree(op2, mac);
10319
10320         /* Propagate the side effect flags from op2 */
10321
10322         tree->gtFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
10323
10324 #if LOCAL_ASSERTION_PROP
10325         // If we are exiting the "else" part of a Qmark-Colon we must
10326         // merge the state of the current copy assignment table with
10327         // that of the exit of the "then" part.
10328         if (isQmarkColon)
10329         {
10330             noway_assert(optLocalAssertionProp);
10331             // If either exit table has zero entries then
10332             // the merged table also has zero entries
10333             if (optAssertionCount == 0 || thenAssertionCount == 0)
10334             {
10335                 optAssertionReset(0);
10336             }
10337             else
10338             {
10339                 size_t tabSize = optAssertionCount * sizeof(AssertionDsc);
10340                 if ( (optAssertionCount != thenAssertionCount) ||
10341                      (memcmp(thenAssertionTab, optAssertionTabPrivate, tabSize) != 0) )
10342                 {
10343                     // Yes they are different so we have to find the merged set
10344                     // Iterate over the copy asgn table removing any entries
10345                     // that do not have an exact match in the thenAssertionTab
10346                     AssertionIndex index = 1;
10347                     while (index <= optAssertionCount)
10348                     {
10349                         AssertionDsc* curAssertion = optGetAssertion(index);
10350
10351                         for (unsigned j=0; j < thenAssertionCount; j++)
10352                         {
10353                             AssertionDsc* thenAssertion = &thenAssertionTab[j];
10354
10355                             // Do the left sides match?
10356                             if ((curAssertion->op1.lcl.lclNum    == thenAssertion->op1.lcl.lclNum) &&
10357                                 (curAssertion->assertionKind == thenAssertion->assertionKind))
10358                             {
10359                                 // Do the right sides match?
10360                                 if ((curAssertion->op2.kind    == thenAssertion->op2.kind) &&
10361                                     (curAssertion->op2.lconVal == thenAssertion->op2.lconVal))
10362                                 {
10363                                     goto KEEP;
10364                                 }
10365                                 else
10366                                 {
10367                                     goto REMOVE;
10368                                 }
10369                             }
10370                         }
10371                         //
10372                         // If we fall out of the loop above then we didn't find
10373                         // any matching entry in the thenAssertionTab so it must
10374                         // have been killed on that path so we remove it here
10375                         //
10376                     REMOVE:
10377                         // The data at optAssertionTabPrivate[i] is to be removed
10378 #ifdef DEBUG
10379                         if (verbose)
10380                         {
10381                             printf("The QMARK-COLON ");
10382                             printTreeID(tree);
10383                             printf(" removes assertion candidate #%d\n", index);
10384                         }
10385 #endif
10386                         optAssertionRemove(index);
10387                         continue;
10388                     KEEP:
10389                         // The data at optAssertionTabPrivate[i] is to be kept
10390                         index++;
10391                     }
10392                 }
10393             }
10394         }
10395 #endif // LOCAL_ASSERTION_PROP
10396     } // if (op2)
10397
10398 DONE_MORPHING_CHILDREN:
10399
10400     /*-------------------------------------------------------------------------
10401      * Now do POST-ORDER processing
10402      */
10403
10404 #if FEATURE_FIXED_OUT_ARGS && !defined(_TARGET_64BIT_)
10405     // Variable shifts of a long end up being helper calls, so mark the tree as such. This
10406     // is potentially too conservative, since they'll get treated as having side effects.
10407     // It is important to mark them as calls so if they are part of an argument list,
10408     // they will get sorted and processed properly (for example, it is important to handle
10409     // all nested calls before putting struct arguments in the argument registers). We
10410     // could mark the trees just before argument processing, but it would require a full
10411     // tree walk of the argument tree, so we just do it here, instead, even though we'll
10412     // mark non-argument trees (that will still get converted to calls, anyway).
10413     if (GenTree::OperIsShift(oper) &&
10414         (tree->TypeGet() == TYP_LONG) &&
10415         (op2->OperGet() != GT_CNS_INT))
10416     {
10417         tree->gtFlags |= GTF_CALL;
10418     }
10419 #endif // FEATURE_FIXED_OUT_ARGS && !_TARGET_64BIT_
10420
10421     if (varTypeIsGC(tree->TypeGet()) && (op1 && !varTypeIsGC(op1->TypeGet()))
10422                                      && (op2 && !varTypeIsGC(op2->TypeGet())))
10423     {
10424         // The tree is really not GC but was marked as such. Now that the
10425         // children have been unmarked, unmark the tree too.
10426
10427         // Remember that GT_COMMA inherits it's type only from op2
10428         if (tree->gtOper == GT_COMMA)
10429             tree->gtType = genActualType(op2->TypeGet());
10430         else
10431             tree->gtType = genActualType(op1->TypeGet());
10432     }
10433
10434     GenTreePtr oldTree = tree;
10435
10436     GenTreePtr qmarkOp1 = NULL;
10437     GenTreePtr qmarkOp2 = NULL;
10438
10439     if ((tree->OperGet() == GT_QMARK) &&
10440         (tree->gtOp.gtOp2->OperGet() == GT_COLON))
10441     {
10442         qmarkOp1 = oldTree->gtOp.gtOp2->gtOp.gtOp1;
10443         qmarkOp2 = oldTree->gtOp.gtOp2->gtOp.gtOp2;
10444     }
10445
10446     // Try to fold it, maybe we get lucky,
10447     tree = gtFoldExpr(tree);
10448
10449     if (oldTree != tree)
10450     {
10451         /* if gtFoldExpr returned op1 or op2 then we are done */
10452         if ((tree == op1) || (tree == op2) || (tree == qmarkOp1) || (tree == qmarkOp2))
10453             return tree;
10454
10455         /* If we created a comma-throw tree then we need to morph op1 */
10456         if (fgIsCommaThrow(tree))
10457         {
10458             tree->gtOp.gtOp1 = fgMorphTree(tree->gtOp.gtOp1);
10459             fgMorphTreeDone(tree);
10460             return tree;
10461         }
10462
10463         return tree;
10464     }
10465     else if (tree->OperKind() & GTK_CONST)
10466     {
10467         return tree;
10468     }
10469
10470     /* gtFoldExpr could have used setOper to change the oper */
10471     oper    = tree->OperGet();
10472     typ     = tree->TypeGet();
10473
10474     /* gtFoldExpr could have changed op1 and op2 */
10475     op1  = tree->gtOp.gtOp1;
10476     op2  = tree->gtGetOp2();
10477
10478     // Do we have an integer compare operation?
10479     //
10480     if (tree->OperIsCompare() && varTypeIsIntegralOrI(tree->TypeGet()))
10481     {
10482         // Are we comparing against zero?
10483         //
10484         if (op2->IsZero())
10485         {
10486             // Request that the codegen for op1 sets the condition flags
10487             // when it generates the code for op1.
10488             //
10489             // Codegen for op1 must set the condition flags if
10490             // this method returns true.
10491             //
10492             op1->gtRequestSetFlags();
10493         }
10494     }
10495     /*-------------------------------------------------------------------------
10496      * Perform the required oper-specific postorder morphing
10497      */
10498
10499     GenTreePtr      temp;
10500     GenTreePtr      cns1, cns2;
10501     GenTreePtr      thenNode;
10502     GenTreePtr      elseNode;
10503     size_t          ival1, ival2;
10504     GenTreePtr      lclVarTree;
10505     GenTreeLclVarCommon* lclVarCmnTree;
10506     FieldSeqNode*   fieldSeq = NULL;
10507
10508     switch (oper)
10509     {
10510     case GT_ASG:
10511         
10512         lclVarTree = fgIsIndirOfAddrOfLocal(op1);
10513         if (lclVarTree != NULL)
10514         {
10515             lclVarTree->gtFlags |= GTF_VAR_DEF;
10516         }
10517
10518         /* If we are storing a small type, we might be able to omit a cast */
10519         if ((op1->gtOper == GT_IND) && varTypeIsSmall(op1->TypeGet()))
10520         {
10521             if (!gtIsActiveCSE_Candidate(op2) && (op2->gtOper == GT_CAST) &&  !op2->gtOverflow())
10522             {
10523                 var_types   castType = op2->CastToType();
10524
10525                 // If we are performing a narrowing cast and
10526                 // castType is larger or the same as op1's type
10527                 // then we can discard the cast.
10528
10529                 if  (varTypeIsSmall(castType) && (castType >= op1->TypeGet()))
10530                 {
10531                     tree->gtOp.gtOp2 = op2 = op2->gtCast.CastOp();
10532                 }
10533             }
10534             else if (op2->OperIsCompare() && varTypeIsByte(op1->TypeGet()))
10535             {
10536                 /* We don't need to zero extend the setcc instruction */
10537                 op2->gtType = TYP_BYTE;
10538             }
10539         }
10540         // If we introduced a CSE we may need to undo the optimization above
10541         // (i.e. " op2->gtType = TYP_BYTE;" which depends upon op1 being a GT_IND of a byte type)
10542         // When we introduce the CSE we remove the GT_IND and subsitute a GT_LCL_VAR in it place.
10543         else if (op2->OperIsCompare() && (op2->gtType == TYP_BYTE) && (op1->gtOper == GT_LCL_VAR))
10544         {
10545             unsigned    varNum = op1->gtLclVarCommon.gtLclNum;
10546             LclVarDsc * varDsc = &lvaTable[varNum];
10547
10548             /* We again need to zero extend the setcc instruction */
10549             op2->gtType = varDsc->TypeGet();
10550         }
10551
10552         __fallthrough;
10553
10554     case GT_COPYOBJ:
10555     case GT_COPYBLK:
10556     case GT_INITBLK:
10557         fgAssignSetVarDef(tree);
10558
10559         __fallthrough;
10560
10561     case GT_ASG_ADD:
10562     case GT_ASG_SUB:
10563     case GT_ASG_MUL:
10564     case GT_ASG_DIV:
10565     case GT_ASG_MOD:
10566     case GT_ASG_UDIV:
10567     case GT_ASG_UMOD:
10568     case GT_ASG_OR:
10569     case GT_ASG_XOR:
10570     case GT_ASG_AND:
10571     case GT_ASG_LSH:
10572     case GT_ASG_RSH:
10573     case GT_ASG_RSZ:
10574
10575         /* We can't CSE the LHS of an assignment */
10576         /* We also must set in the pre-morphing phase, otherwise assertionProp doesn't see it */
10577         op1->gtFlags |= GTF_DONT_CSE;
10578         break;
10579
10580     case GT_EQ:
10581     case GT_NE:
10582
10583         /* Make sure we're allowed to do this */
10584
10585         if (optValnumCSE_phase)
10586         {
10587             // It is not safe to reorder/delete CSE's
10588             break;
10589         }
10590
10591         cns2 = op2;
10592
10593         /* Check for "(expr +/- icon1) ==/!= (non-zero-icon2)" */
10594
10595         if  (cns2->gtOper == GT_CNS_INT && cns2->gtIntCon.gtIconVal != 0)
10596         {
10597             op1 = tree->gtOp.gtOp1;
10598
10599             /* Since this can occur repeatedly we use a while loop */
10600
10601             while ((op1->gtOper == GT_ADD || op1->gtOper == GT_SUB) &&
10602                    (op1->gtOp.gtOp2->gtOper == GT_CNS_INT)          &&
10603                    (op1->gtType             == TYP_INT)             &&
10604                    (op1->gtOverflow()       == false))
10605             {
10606                 /* Got it; change "x+icon1==icon2" to "x==icon2-icon1" */
10607
10608                 ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
10609                 ival2 = cns2->gtIntCon.gtIconVal;
10610
10611                 if  (op1->gtOper == GT_ADD)
10612                 {
10613                     ival2 -= ival1;
10614                 }
10615                 else
10616                 {
10617                     ival2 += ival1;
10618                 }
10619                 cns2->gtIntCon.gtIconVal = ival2;
10620
10621 #ifdef _TARGET_64BIT_
10622                 // we need to properly re-sign-extend or truncate as needed.
10623                 cns2->AsIntCon()->TruncateOrSignExtend32();
10624 #endif // _TARGET_64BIT_                
10625
10626                 op1 = tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
10627             }
10628         }
10629
10630         //
10631         // Here we look for the following tree
10632         //
10633         //                        EQ/NE
10634         //                        /  \
10635         //                      op1   CNS 0/1
10636         //
10637         ival2 = INT_MAX;  // The value of INT_MAX for ival2 just means that the constant value is not 0 or 1
10638
10639         // cast to unsigned allows test for both 0 and 1
10640         if ((cns2->gtOper == GT_CNS_INT) && (((size_t) cns2->gtIntConCommon.IconValue()) <= 1U))
10641         {
10642             ival2 = (size_t) cns2->gtIntConCommon.IconValue();
10643         }
10644         else // cast to UINT64 allows test for both 0 and 1
10645         if ((cns2->gtOper == GT_CNS_LNG) && (((UINT64) cns2->gtIntConCommon.LngValue()) <= 1ULL))
10646         {
10647             ival2 = (size_t) cns2->gtIntConCommon.LngValue();
10648         }
10649
10650         if (ival2 != INT_MAX)
10651         {
10652             // If we don't have a comma and relop, we can't do this optimization
10653             //
10654             if ((op1->gtOper == GT_COMMA) && (op1->gtOp.gtOp2->OperIsCompare()))
10655             {
10656                 // Here we look for the following transformation
10657                 //
10658                 //                  EQ/NE                    Possible REVERSE(RELOP)
10659                 //                  /  \                           /      \
10660                 //               COMMA CNS 0/1             ->   COMMA   relop_op2
10661                 //              /   \                          /    \
10662                 //             x  RELOP                       x     relop_op1
10663                 //               /    \
10664                 //         relop_op1  relop_op2
10665                 //
10666                 //
10667                 //
10668                 GenTreePtr comma = op1;
10669                 GenTreePtr relop = comma->gtOp.gtOp2;
10670
10671                 GenTreePtr relop_op1 = relop->gtOp.gtOp1;
10672
10673                 bool reverse = ((ival2 == 0) == (oper == GT_EQ));
10674
10675                 if (reverse)
10676                 {
10677                     gtReverseCond(relop);
10678                 }
10679
10680                 relop->gtOp.gtOp1 = comma;
10681                 comma->gtOp.gtOp2 = relop_op1;
10682
10683                 // Comma now has fewer nodes underneath it, so we need to regenerate its flags
10684                 comma->gtFlags &= ~GTF_ALL_EFFECT;
10685                 comma->gtFlags |= (comma->gtOp.gtOp1->gtFlags) & GTF_ALL_EFFECT;
10686                 comma->gtFlags |= (comma->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
10687
10688                 noway_assert((relop->gtFlags & GTF_RELOP_JMP_USED) == 0);
10689                 noway_assert((relop->gtFlags & GTF_REVERSE_OPS)    == 0);
10690                 relop->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED|GTF_RELOP_QMARK|GTF_DONT_CSE|GTF_ALL_EFFECT);
10691
10692                 return relop;
10693             }
10694
10695             if (op1->gtOper == GT_COMMA)
10696             {
10697                 // Here we look for the following tree
10698                 // and when the LCL_VAR is a temp we can fold the tree:
10699                 //
10700                 //                        EQ/NE                  EQ/NE
10701                 //                        /  \                   /  \
10702                 //                     COMMA  CNS 0/1  ->     RELOP CNS 0/1
10703                 //                     /   \                   / \
10704                 //                   ASG  LCL_VAR
10705                 //                  /  \
10706                 //           LCL_VAR   RELOP
10707                 //                      / \
10708                 //
10709
10710                 GenTreePtr  asg = op1->gtOp.gtOp1;
10711                 GenTreePtr  lcl = op1->gtOp.gtOp2;
10712
10713                 /* Make sure that the left side of the comma is the assignment of the LCL_VAR */
10714                 if (asg->gtOper != GT_ASG)
10715                     goto SKIP;
10716
10717                 /* The right side of the comma must be a LCL_VAR temp */
10718                 if (lcl->gtOper != GT_LCL_VAR)
10719                     goto SKIP;
10720
10721                 unsigned lclNum = lcl->gtLclVarCommon.gtLclNum;   noway_assert(lclNum < lvaCount);
10722
10723                 /* If the LCL_VAR is not a temp then bail, a temp has a single def */
10724                 if (!lvaTable[lclNum].lvIsTemp)
10725                     goto SKIP;
10726
10727 #if FEATURE_ANYCSE
10728                 /* If the LCL_VAR is a CSE temp then bail, it could have multiple defs/uses */
10729                 // Fix 383856 X86/ARM ILGEN
10730                 if (lclNumIsCSE(lclNum))
10731                     goto SKIP;
10732 #endif
10733
10734                 /* We also must be assigning the result of a RELOP */
10735                 if (asg->gtOp.gtOp1->gtOper != GT_LCL_VAR)
10736                     goto SKIP;
10737
10738                 /* Both of the LCL_VAR must match */
10739                 if (asg->gtOp.gtOp1->gtLclVarCommon.gtLclNum != lclNum)
10740                     goto SKIP;
10741
10742                 /* If right side of asg is not a RELOP then skip */
10743                 if (!asg->gtOp.gtOp2->OperIsCompare())
10744                     goto SKIP;
10745
10746                 LclVarDsc * varDsc = lvaTable + lclNum;
10747
10748                 /* Set op1 to the right side of asg, (i.e. the RELOP) */
10749                 op1 = asg->gtOp.gtOp2;
10750
10751                 DEBUG_DESTROY_NODE(asg->gtOp.gtOp1);
10752                 DEBUG_DESTROY_NODE(lcl);
10753
10754                 /* This local variable should never be used again */
10755                 // <BUGNUM>
10756                 // VSW 184221: Make RefCnt to zero to indicate that this local var
10757                 // is not used any more. (Keey the lvType as is.)
10758                 // Otherwise lvOnFrame will be set to true in Compiler::raMarkStkVars
10759                 // And then emitter::emitEndCodeGen will assert in the following line:
10760                 //        noway_assert( dsc->lvTracked);
10761                 // </BUGNUM>
10762                 noway_assert(varDsc->lvRefCnt == 0  ||  // lvRefCnt may not have been set yet.
10763                              varDsc->lvRefCnt == 2      // Or, we assume this tmp should only be used here,
10764                                                         // and it only shows up twice.
10765                       );
10766                 lvaTable[lclNum].lvRefCnt = 0;
10767                 lvaTable[lclNum].lvaResetSortAgainFlag(this);
10768             }
10769
10770
10771             if (op1->OperIsCompare())
10772             {
10773                 // Here we look for the following tree
10774                 //
10775                 //                        EQ/NE           ->      RELOP/!RELOP
10776                 //                        /  \                       /    \
10777                 //                     RELOP  CNS 0/1
10778                 //                     /   \
10779                 //
10780                 // Note that we will remove/destroy the EQ/NE node and move 
10781                 // the RELOP up into it's location.
10782
10783                 /* Here we reverse the RELOP if necessary */
10784
10785                 bool reverse = ((ival2 == 0) == (oper == GT_EQ));
10786
10787                 if (reverse)
10788                 {
10789                     gtReverseCond(op1);
10790                 }
10791
10792                 /* Propagate gtType of tree into op1 in case it is TYP_BYTE for setcc optimization */
10793                 op1->gtType = tree->gtType;
10794
10795                 noway_assert((op1->gtFlags & GTF_RELOP_JMP_USED) == 0);
10796                 op1->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED|GTF_RELOP_QMARK|GTF_DONT_CSE);
10797
10798                 DEBUG_DESTROY_NODE(tree);
10799                 return op1;
10800
10801             }
10802
10803             //
10804             // Now we check for a compare with the result of an '&' operator
10805             //
10806             // Here we look for the following transformation:
10807             //
10808             //                        EQ/NE                  EQ/NE
10809             //                        /  \                   /  \
10810             //                      AND   CNS 0/1  ->      AND   CNS 0
10811             //                     /   \                  /   \
10812             //                RSZ/RSH   CNS 1            x     CNS (1 << y)
10813             //                  /  \
10814             //                 x   CNS_INT +y
10815
10816             if (op1->gtOper == GT_AND)
10817             {
10818                 GenTreePtr andOp    = op1;
10819                 GenTreePtr rshiftOp = andOp->gtOp.gtOp1;
10820
10821                 if ((rshiftOp->gtOper != GT_RSZ) && (rshiftOp->gtOper != GT_RSH))
10822                     goto SKIP;
10823
10824                 if (!rshiftOp->gtOp.gtOp2->IsCnsIntOrI())
10825                     goto SKIP;
10826
10827                 ssize_t shiftAmount = rshiftOp->gtOp.gtOp2->gtIntCon.gtIconVal;
10828
10829                 if (shiftAmount < 0)
10830                     goto SKIP;
10831
10832                 if (andOp->gtType == TYP_INT)
10833                 {
10834                     if (!andOp->gtOp.gtOp2->IsCnsIntOrI())
10835                         goto SKIP;
10836
10837                     if (andOp->gtOp.gtOp2->gtIntCon.gtIconVal != 1)
10838                         goto SKIP;
10839
10840                     if (shiftAmount > 31)
10841                         goto SKIP;
10842
10843                     UINT32 newAndOperand = ((UINT32) 1) << shiftAmount;
10844
10845                     andOp->gtOp.gtOp2->gtIntCon.gtIconVal = newAndOperand;
10846
10847                     // Reverse the cond if necessary
10848                     if (ival2 == 1)
10849                     {
10850                         gtReverseCond(tree);
10851                         cns2->gtIntCon.gtIconVal = 0;
10852                         oper = tree->gtOper;
10853                     }
10854
10855                 }
10856                 else if (andOp->gtType == TYP_LONG)
10857                 {
10858                     if (andOp->gtOp.gtOp2->gtOper != GT_CNS_NATIVELONG)
10859                         goto SKIP;
10860
10861                     if (andOp->gtOp.gtOp2->gtIntConCommon.LngValue() != 1)
10862                         goto SKIP;
10863
10864                     if (shiftAmount > 63)
10865                         goto SKIP;
10866
10867                     UINT64 newAndOperand = ((UINT64) 1) << shiftAmount;
10868
10869                     andOp->gtOp.gtOp2->gtIntConCommon.SetLngValue(newAndOperand);
10870
10871                     // Reverse the cond if necessary
10872                     if (ival2 == 1)
10873                     {
10874                         gtReverseCond(tree);
10875                         cns2->gtIntConCommon.SetLngValue(0);
10876                         oper = tree->gtOper;
10877                     }
10878                 }
10879
10880                 andOp->gtOp.gtOp1 = rshiftOp->gtOp.gtOp1;
10881
10882                 DEBUG_DESTROY_NODE(rshiftOp->gtOp.gtOp2);
10883                 DEBUG_DESTROY_NODE(rshiftOp);
10884             }
10885         } // END if (ival2 != INT_MAX)
10886
10887 SKIP:
10888         /* Now check for compares with small constant longs that can be cast to int */
10889
10890         if (!cns2->OperIsConst())
10891             goto COMPARE;
10892
10893         if (cns2->TypeGet() != TYP_LONG)
10894             goto COMPARE;
10895
10896         /* Is the constant 31 bits or smaller? */
10897
10898         if ((cns2->gtIntConCommon.LngValue() >> 31) != 0)
10899             goto COMPARE;
10900
10901         /* Is the first comparand mask operation of type long ? */
10902
10903         if  (op1->gtOper != GT_AND)
10904         {
10905             /* Another interesting case: cast from int */
10906
10907             if  (op1->gtOper         == GT_CAST &&
10908                  op1->CastFromType() == TYP_INT &&
10909                  !gtIsActiveCSE_Candidate(op1)  &&  // op1 cannot be a CSE candidate
10910                  !op1->gtOverflow())                // cannot be an overflow checking cast
10911             {
10912                 /* Simply make this into an integer comparison */
10913
10914                 tree->gtOp.gtOp1 = op1->gtCast.CastOp();
10915                 tree->gtOp.gtOp2 = gtNewIconNode((int)cns2->gtIntConCommon.LngValue(), TYP_INT);
10916             }
10917
10918             goto COMPARE;
10919         }
10920
10921         noway_assert(op1->TypeGet() == TYP_LONG && op1->OperGet() == GT_AND);
10922
10923         /* Is the result of the mask effectively an INT ? */
10924
10925         GenTreePtr andMask; andMask = op1->gtOp.gtOp2;
10926         if  (andMask->gtOper != GT_CNS_NATIVELONG)
10927             goto COMPARE;
10928         if  ((andMask->gtIntConCommon.LngValue() >> 32) != 0)
10929             goto COMPARE;
10930
10931         /* Now we know that we can cast gtOp.gtOp1 of AND to int */
10932
10933         op1->gtOp.gtOp1 = gtNewCastNode(TYP_INT,
10934                                          op1->gtOp.gtOp1,
10935                                          TYP_INT);
10936
10937         /* now replace the mask node (gtOp.gtOp2 of AND node) */
10938
10939         noway_assert(andMask == op1->gtOp.gtOp2);
10940
10941         ival1 = (int) andMask->gtIntConCommon.LngValue();
10942         andMask->SetOper(GT_CNS_INT);
10943         andMask->gtType             = TYP_INT;
10944         andMask->gtIntCon.gtIconVal = ival1;
10945
10946         /* now change the type of the AND node */
10947
10948         op1->gtType = TYP_INT;
10949
10950         /* finally we replace the comparand */
10951
10952         ival2 = (int) cns2->gtIntConCommon.LngValue();
10953         cns2->SetOper(GT_CNS_INT);
10954         cns2->gtType = TYP_INT;
10955
10956         noway_assert(cns2 == op2);
10957         cns2->gtIntCon.gtIconVal = ival2;
10958
10959         goto COMPARE;
10960
10961     case GT_LT:
10962     case GT_LE:
10963     case GT_GE:
10964     case GT_GT:
10965  
10966         if ((tree->gtFlags & GTF_UNSIGNED) == 0)
10967         {
10968             if (op2->gtOper == GT_CNS_INT)
10969             {
10970                 cns2 = op2;
10971                 /* Check for "expr relop 1" */
10972                 if (cns2->gtIntCon.gtIconVal == +1)
10973                 {
10974                     /* Check for "expr >= 1" */
10975                     if (oper == GT_GE)
10976                     {
10977                         /* Change to "expr > 0" */
10978                         oper = GT_GT;
10979                         goto SET_OPER;
10980                     }
10981                     /* Check for "expr < 1" */
10982                     else if (oper == GT_LT)
10983                     {
10984                         /* Change to "expr <= 0" */
10985                         oper = GT_LE;
10986                         goto SET_OPER;
10987                     }
10988                 }
10989                 /* Check for "expr relop -1" */
10990                 else if ((cns2->gtIntCon.gtIconVal == -1) && ((oper == GT_LE) || (oper == GT_GT)))
10991                 {
10992                     /* Check for "expr <= -1" */
10993                     if (oper == GT_LE)
10994                     {
10995                         /* Change to "expr < 0" */
10996                         oper = GT_LT;
10997                         goto SET_OPER;
10998                     }
10999                     /* Check for "expr > -1" */
11000                     else if (oper == GT_GT)
11001                     {
11002                         /* Change to "expr >= 0" */
11003                         oper = GT_GE;
11004
11005 SET_OPER:
11006                         // IF we get here we should be changing 'oper' 
11007                         assert(tree->OperGet() != oper);
11008
11009                         // Keep the old ValueNumber for 'tree' as the new expr
11010                         // will still compute the same value as before
11011                         tree->SetOper(oper, GenTree::PRESERVE_VN);
11012                         cns2->gtIntCon.gtIconVal = 0;
11013
11014                         // vnStore is null before the ValueNumber phase has run
11015                         if (vnStore != nullptr)
11016                         {
11017                             // Update the ValueNumber for 'cns2', as we just changed it to 0
11018                             fgValueNumberTreeConst(cns2);
11019                         }
11020                      
11021                         op2 = tree->gtOp.gtOp2 = gtFoldExpr(op2);
11022                     }
11023                 }
11024             }
11025         }
11026
11027 COMPARE:
11028
11029         noway_assert(tree->OperKind() & GTK_RELOP);
11030
11031         /* Check if the result of the comparison is used for a jump.
11032          * If not then only the int (i.e. 32 bit) case is handled in
11033          * the code generator through the (x86) "set" instructions.
11034          * For the rest of the cases, the simplest way is to
11035          * "simulate" the comparison with ?:
11036          *
11037          * On ARM, we previously used the IT instruction, but the IT instructions
11038          * have mostly been declared obsolete and off-limits, so all cases on ARM
11039          * get converted to ?: */
11040
11041         if (!(tree->gtFlags & GTF_RELOP_JMP_USED) &&
11042             fgMorphRelopToQmark(op1))
11043         {
11044             /* We convert it to "(CMP_TRUE) ? (1):(0)" */
11045
11046             op1  = tree;
11047             op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
11048             op1->gtRequestSetFlags();
11049
11050             op2  = new (this, GT_COLON) GenTreeColon(TYP_INT, gtNewIconNode(1), gtNewIconNode(0)
11051                                                      );
11052             op2  = fgMorphTree(op2);
11053
11054             tree = gtNewQmarkNode(TYP_INT, op1, op2);
11055
11056             fgMorphTreeDone(tree);
11057
11058             return tree;
11059         }
11060         break;
11061
11062    case GT_QMARK:
11063
11064         /* If op1 is a comma throw node then we won't be keeping op2 */
11065         if (fgIsCommaThrow(op1))
11066             break;
11067
11068         /* Get hold of the two branches */
11069
11070         noway_assert(op2->OperGet() == GT_COLON);
11071         elseNode = op2->AsColon()->ElseNode();
11072         thenNode = op2->AsColon()->ThenNode();
11073
11074         /* Try to hoist assignments out of qmark colon constructs.
11075            ie. replace (cond?(x=a):(x=b)) with (x=(cond?a:b)). */
11076
11077         if (tree->TypeGet() == TYP_VOID &&
11078             thenNode->OperGet() == GT_ASG &&
11079             elseNode->OperGet() == GT_ASG &&
11080             thenNode->TypeGet() != TYP_LONG &&
11081             GenTree::Compare(thenNode->gtOp.gtOp1, elseNode->gtOp.gtOp1) &&
11082             thenNode->gtOp.gtOp2->TypeGet() == elseNode->gtOp.gtOp2->TypeGet())
11083         {
11084                 noway_assert(thenNode->TypeGet() == elseNode->TypeGet());
11085
11086                 GenTreePtr asg = thenNode;
11087                 GenTreePtr colon = op2;
11088                 colon->gtOp.gtOp1 = thenNode->gtOp.gtOp2;
11089                 colon->gtOp.gtOp2 = elseNode->gtOp.gtOp2;
11090                 tree->gtType = colon->gtType = asg->gtOp.gtOp2->gtType;
11091                 asg->gtOp.gtOp2 = tree;
11092
11093                 // Asg will have all the flags that the QMARK had
11094                 asg->gtFlags       |= (tree->gtFlags & GTF_ALL_EFFECT);
11095
11096                 // Colon flag won't have the flags that x had.
11097                 colon->gtFlags &= ~GTF_ALL_EFFECT;
11098                 colon->gtFlags |= (colon->gtOp.gtOp1->gtFlags |
11099                                    colon->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
11100
11101                 DEBUG_DESTROY_NODE(elseNode->gtOp.gtOp1);
11102                 DEBUG_DESTROY_NODE(elseNode);
11103
11104                 return asg;
11105         }
11106
11107
11108         /* If the 'else' branch is empty swap the two branches and reverse the condition */
11109
11110         if (elseNode->IsNothingNode())
11111         {
11112             /* This can only happen for VOID ?: */
11113             noway_assert(op2->gtType == TYP_VOID);
11114
11115             /* If the thenNode and elseNode are both nop nodes then optimize away the QMARK */
11116             if (thenNode->IsNothingNode())
11117             {
11118                 // We may be able to throw away op1 (unless it has side-effects)
11119
11120                 if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
11121                 {
11122                     /* Just return a a Nop Node */
11123                     return thenNode;
11124                 }
11125                 else
11126                 {
11127                     /* Just return the relop, but clear the special flags.  Note
11128                        that we can't do that for longs and floats (see code under
11129                        COMPARE label above) */
11130
11131                     if (!fgMorphRelopToQmark(op1->gtOp.gtOp1))
11132                     {
11133                         op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
11134                         return op1;
11135                     }
11136                 }
11137             }
11138             else
11139             {
11140                 GenTreePtr tmp = elseNode;
11141
11142                 op2->AsColon()->ElseNode() = elseNode = thenNode;
11143                 op2->AsColon()->ThenNode() = thenNode = tmp;
11144                 gtReverseCond(op1);
11145             }
11146         }
11147
11148 #if !defined(_TARGET_ARM_)
11149         // If we have (cond)?0:1, then we just return "cond" for TYP_INTs
11150         //
11151         // Don't do this optimization for ARM: we always require assignment
11152         // to boolean to remain ?:, since we don't have any way to generate
11153         // this with straight-line code, like x86 does using setcc (at least
11154         // after the IT instruction is deprecated).
11155
11156         if (genActualType(op1->gtOp.gtOp1->gtType) == TYP_INT    &&
11157             genActualType(typ)                     == TYP_INT    &&
11158             thenNode->gtOper                       == GT_CNS_INT &&
11159             elseNode->gtOper                       == GT_CNS_INT)
11160         {
11161             ival1 = thenNode->gtIntCon.gtIconVal;
11162             ival2 = elseNode->gtIntCon.gtIconVal;
11163
11164             // Is one constant 0 and the other 1?
11165             if ((ival1 | ival2) == 1 && (ival1 & ival2) == 0)
11166             {
11167                 // If the constants are {1, 0}, reverse the condition
11168                 if (ival1 == 1)
11169                     gtReverseCond(op1);
11170
11171                 // Unmark GTF_RELOP_JMP_USED on the condition node so it knows that it
11172                 // needs to materialize the result as a 0 or 1.
11173                 noway_assert(op1->gtFlags & (GTF_RELOP_QMARK | GTF_RELOP_JMP_USED));
11174                 op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
11175
11176                 DEBUG_DESTROY_NODE(tree);
11177                 DEBUG_DESTROY_NODE(op2);
11178
11179                 return op1;
11180             }
11181         }
11182 #endif // !_TARGET_ARM_
11183
11184         break; // end case GT_QMARK
11185
11186
11187     case GT_MUL:
11188
11189 #ifndef _TARGET_64BIT_
11190         if (typ == TYP_LONG)
11191         {
11192             // This must be GTF_MUL_64RSLT
11193             assert(tree->gtIsValid64RsltMul());
11194             return tree;
11195         }
11196 #endif // _TARGET_64BIT_
11197         goto CM_OVF_OP;
11198
11199     case GT_SUB:
11200
11201         if (tree->gtOverflow())
11202             goto CM_OVF_OP;
11203
11204         /* Check for "op1 - cns2" , we change it to "op1 + (-cns2)" */
11205
11206         noway_assert(op2);
11207         if  (op2->IsCnsIntOrI())
11208         {
11209             /* Negate the constant and change the node to be "+" */
11210
11211             op2->gtIntConCommon.SetIconValue(-op2->gtIntConCommon.IconValue());
11212             oper = GT_ADD;
11213             tree->ChangeOper(oper);
11214             goto CM_ADD_OP;
11215         }
11216
11217         /* Check for "cns1 - op2" , we change it to "(cns1 + (-op2))" */
11218
11219         noway_assert(op1);
11220         if  (op1->IsCnsIntOrI())
11221         {
11222             noway_assert(varTypeIsIntOrI(tree));
11223
11224             tree->gtOp.gtOp2 = op2 = gtNewOperNode(GT_NEG, tree->gtType, op2); // The type of the new GT_NEG node should be the same
11225                                                                                // as the type of the tree, i.e. tree->gtType.
11226             fgMorphTreeDone(op2);
11227
11228             oper = GT_ADD;
11229             tree->ChangeOper(oper);
11230             goto CM_ADD_OP;
11231         }
11232
11233         /* No match - exit */
11234
11235         break;
11236
11237 #ifdef _TARGET_ARM64_
11238     case GT_DIV:
11239         if (!varTypeIsFloating(tree->gtType))
11240         {
11241             // Codegen for this instruction needs to be able to throw two exceptions:
11242             fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
11243             fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
11244         }
11245         break;
11246     case GT_UDIV:
11247         // Codegen for this instruction needs to be able to throw one exception:
11248         fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
11249         break;
11250 #endif
11251
11252     case GT_ADD:
11253
11254 CM_OVF_OP :
11255         if (tree->gtOverflow())
11256         {
11257             tree->gtRequestSetFlags();
11258
11259             // Add the excptn-throwing basic block to jump to on overflow
11260
11261             fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
11262
11263             // We can't do any commutative morphing for overflow instructions
11264
11265             break;
11266         }
11267
11268 CM_ADD_OP:
11269
11270     case GT_OR:
11271     case GT_XOR:
11272     case GT_AND:
11273
11274         /* Commute any non-REF constants to the right */
11275
11276         noway_assert(op1);
11277         if  (op1->OperIsConst() && (op1->gtType != TYP_REF))
11278         {
11279             // TODO-Review: We used to assert here that
11280             // noway_assert(!op2->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD));
11281             // With modifications to AddrTaken==>AddrExposed, we did more assertion propagation,
11282             // and would sometimes hit this assertion.  This may indicate a missed "remorph".
11283             // Task is to re-enable this assertion and investigate.
11284
11285             /* Swap the operands */
11286             tree->gtOp.gtOp1 = op2;
11287             tree->gtOp.gtOp2 = op1;
11288
11289             op1 = op2;
11290             op2 = tree->gtOp.gtOp2;
11291         }
11292
11293         /* See if we can fold GT_ADD nodes. */
11294
11295         if (oper == GT_ADD)
11296         {
11297             /* Fold "((x+icon1)+(y+icon2)) to ((x+y)+(icon1+icon2))" */
11298
11299             if (op1->gtOper             == GT_ADD     &&
11300                 op2->gtOper             == GT_ADD     &&
11301                 !gtIsActiveCSE_Candidate(op2)         &&
11302                 op1->gtOp.gtOp2->gtOper == GT_CNS_INT &&
11303                 op2->gtOp.gtOp2->gtOper == GT_CNS_INT &&
11304                 !op1->gtOverflow()                    &&
11305                 !op2->gtOverflow()                       )
11306             {
11307                 cns1 = op1->gtOp.gtOp2;
11308                 cns2 = op2->gtOp.gtOp2;
11309                 cns1->gtIntCon.gtIconVal += cns2->gtIntCon.gtIconVal;
11310 #ifdef _TARGET_64BIT_
11311                 if (cns1->TypeGet() == TYP_INT)
11312                 {
11313                     // we need to properly re-sign-extend or truncate after adding two int constants above
11314                     cns1->AsIntCon()->TruncateOrSignExtend32();
11315                 }
11316 #endif //_TARGET_64BIT_
11317
11318                 tree->gtOp.gtOp2    = cns1;
11319                 DEBUG_DESTROY_NODE(cns2);
11320
11321                 op1->gtOp.gtOp2     = op2->gtOp.gtOp1;
11322                 op1->gtFlags       |= (op1->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT);
11323                 DEBUG_DESTROY_NODE(op2);
11324                 op2 = tree->gtOp.gtOp2;
11325             }
11326
11327             if (op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ))
11328             {
11329                 /* Fold "((x+icon1)+icon2) to (x+(icon1+icon2))" */
11330
11331                 if (op1->gtOper == GT_ADD          &&
11332                     !gtIsActiveCSE_Candidate(op1)  &&
11333                     op1->gtOp.gtOp2->IsCnsIntOrI() &&
11334                     !op1->gtOverflow()             &&
11335                     op1->gtOp.gtOp2->OperGet() == op2->OperGet())
11336                 {
11337                     cns1 = op1->gtOp.gtOp2;
11338                     op2->gtIntConCommon.SetIconValue(cns1->gtIntConCommon.IconValue() + op2->gtIntConCommon.IconValue());  
11339 #ifdef _TARGET_64BIT_
11340                     if (op2->TypeGet() == TYP_INT)
11341                     {
11342                         // we need to properly re-sign-extend or truncate after adding two int constants above
11343                         op2->AsIntCon()->TruncateOrSignExtend32();
11344                     }
11345 #endif //_TARGET_64BIT_
11346
11347                     if (cns1->OperGet() == GT_CNS_INT)
11348                     {
11349                         op2->gtIntCon.gtFieldSeq = 
11350                             GetFieldSeqStore()->Append(cns1->gtIntCon.gtFieldSeq,
11351                                                        op2->gtIntCon.gtFieldSeq);
11352                     }
11353                     DEBUG_DESTROY_NODE(cns1);
11354
11355                     tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
11356                     DEBUG_DESTROY_NODE(op1);
11357                     op1 = tree->gtOp.gtOp1;
11358                 }
11359
11360                 // Fold (x + 0).
11361
11362                 if ((op2->gtIntConCommon.IconValue() == 0) && !gtIsActiveCSE_Candidate(tree))
11363                 {
11364
11365                     // If this addition is adding an offset to a null pointer,
11366                     // avoid the work and yield the null pointer immediately.
11367                     // Dereferencing the pointer in either case will have the
11368                     // same effect.
11369
11370                     if (!gtIsActiveCSE_Candidate(op1) && varTypeIsGC(op2->TypeGet()))
11371                     {
11372                         op2->gtType = tree->gtType;
11373                         DEBUG_DESTROY_NODE(op1);
11374                         DEBUG_DESTROY_NODE(tree);
11375                         return op2;
11376                     }
11377
11378                     // Remove the addition iff it won't change the tree type
11379                     // to TYP_REF.
11380
11381                     if (!gtIsActiveCSE_Candidate(op2) && 
11382                         ((op1->TypeGet() == tree->TypeGet()) ||
11383                         (op1->TypeGet() != TYP_REF)))
11384                     {
11385                         if (fgGlobalMorph &&
11386                             (op2->OperGet() == GT_CNS_INT)      &&
11387                             (op2->gtIntCon.gtFieldSeq != NULL)  &&
11388                             (op2->gtIntCon.gtFieldSeq != FieldSeqStore::NotAField()))
11389                         {
11390                             fgAddFieldSeqForZeroOffset(op1, op2->gtIntCon.gtFieldSeq);
11391                         }
11392
11393                         DEBUG_DESTROY_NODE(op2);
11394                         DEBUG_DESTROY_NODE(tree);
11395
11396                         return op1;
11397                     }
11398                 }
11399             }
11400         }
11401              /* See if we can fold GT_MUL by const nodes */
11402         else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
11403         {
11404 #ifndef _TARGET_64BIT_
11405             noway_assert(typ <= TYP_UINT);
11406 #endif // _TARGET_64BIT_
11407             noway_assert(!tree->gtOverflow());
11408
11409             ssize_t mult = op2->gtIntConCommon.IconValue();
11410             bool op2IsConstIndex = op2->OperGet() == GT_CNS_INT &&
11411                                    op2->gtIntCon.gtFieldSeq != nullptr &&
11412                                    op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq();
11413
11414             assert(!op2IsConstIndex || op2->AsIntCon()->gtFieldSeq->m_next == nullptr);
11415
11416             if (mult == 0)
11417             {
11418                 // We may be able to throw away op1 (unless it has side-effects)
11419
11420                 if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
11421                 {
11422                     DEBUG_DESTROY_NODE(op1);
11423                     DEBUG_DESTROY_NODE(tree);
11424                     return op2; // Just return the "0" node
11425                 }
11426
11427                 // We need to keep op1 for the side-effects. Hang it off
11428                 // a GT_COMMA node
11429
11430                 tree->ChangeOper(GT_COMMA);
11431                 return tree;
11432             }
11433
11434             size_t abs_mult = (mult >= 0) ? mult : -mult;
11435             size_t lowestBit = genFindLowestBit(abs_mult);
11436             bool changeToShift = false;
11437
11438             // is it a power of two? (positive or negative)
11439             if  (abs_mult == lowestBit)
11440             {
11441                     // if negative negate (min-int does not need negation)
11442                 if (mult < 0 && mult != SSIZE_T_MIN)
11443                 {
11444                     tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_NEG, op1->gtType, op1);
11445                     fgMorphTreeDone(op1);
11446                 }
11447
11448                 // If "op2" is a constant array index, the other multiplicand must be a constant.
11449                 // Transfer the annotation to the other one.
11450                 if (op2->OperGet() == GT_CNS_INT &&
11451                     op2->gtIntCon.gtFieldSeq != nullptr &&
11452                     op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
11453                 {
11454                     assert(op2->gtIntCon.gtFieldSeq->m_next == nullptr);
11455                     GenTreePtr otherOp = op1;
11456                     if (otherOp->OperGet() == GT_NEG)
11457                         otherOp = otherOp->gtOp.gtOp1;
11458                     assert(otherOp->OperGet() == GT_CNS_INT);
11459                     assert(otherOp->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
11460                     otherOp->gtIntCon.gtFieldSeq = op2->gtIntCon.gtFieldSeq;
11461                 }
11462
11463                 if (abs_mult == 1)
11464                 {
11465                     DEBUG_DESTROY_NODE(op2);
11466                     DEBUG_DESTROY_NODE(tree);
11467                     return op1;
11468                 }
11469
11470                 /* Change the multiplication into a shift by log2(val) bits */
11471                 op2->gtIntConCommon.SetIconValue(genLog2(abs_mult));
11472                 changeToShift = true;
11473             }
11474 #if LEA_AVAILABLE
11475             else if ((lowestBit > 1) && jitIsScaleIndexMul(lowestBit) && optAvoidIntMult())
11476             {
11477                 int     shift = genLog2(lowestBit);
11478                 ssize_t factor = abs_mult >> shift;
11479
11480                 if (factor == 3 || factor == 5 || factor == 9)
11481                 {
11482                     // if negative negate (min-int does not need negation)
11483                     if (mult < 0 && mult != SSIZE_T_MIN)
11484                     {
11485                         tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_NEG, op1->gtType, op1);
11486                         fgMorphTreeDone(op1);
11487                     }
11488
11489                     GenTreePtr factorIcon = gtNewIconNode(factor, TYP_I_IMPL);
11490                     if (op2IsConstIndex)
11491                     {
11492                         factorIcon->AsIntCon()->gtFieldSeq = GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
11493                     }
11494
11495                     // change the multiplication into a smaller multiplication (by 3, 5 or 9) and a shift
11496                     tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_MUL, tree->gtType, op1, factorIcon);
11497                     fgMorphTreeDone(op1);
11498
11499                     op2->gtIntConCommon.SetIconValue(shift);
11500                     changeToShift = true;
11501                 }
11502             }
11503 #endif // LEA_AVAILABLE
11504             if (changeToShift)
11505             {
11506                 // vnStore is null before the ValueNumber phase has run
11507                 if (vnStore != nullptr)
11508                 {
11509                     // Update the ValueNumber for 'op2', as we just changed the constant
11510                     fgValueNumberTreeConst(op2);
11511                 }
11512                 oper = GT_LSH;
11513                 // Keep the old ValueNumber for 'tree' as the new expr
11514                 // will still compute the same value as before
11515                 tree->ChangeOper(oper, GenTree::PRESERVE_VN);
11516
11517                 goto DONE_MORPHING_CHILDREN;
11518             }
11519         }
11520         else if (fgOperIsBitwiseRotationRoot(oper))
11521         {
11522             tree = fgRecognizeAndMorphBitwiseRotation(tree);
11523
11524             // fgRecognizeAndMorphBitwiseRotation may return a new tree
11525             oper = tree->OperGet();
11526             typ = tree->TypeGet();
11527             op1 = tree->gtOp.gtOp1;
11528             op2 = tree->gtOp.gtOp2;
11529         }
11530
11531         break;
11532
11533     case GT_CHS:
11534     case GT_NOT:
11535     case GT_NEG:
11536
11537         /* Any constant cases should have been folded earlier */
11538         noway_assert(!op1->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD) || optValnumCSE_phase);
11539         break;
11540
11541     case GT_CKFINITE:
11542
11543         noway_assert(varTypeIsFloating(op1->TypeGet()));
11544
11545         fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_ARITH_EXCPN, fgPtrArgCntCur);
11546         break;
11547
11548     case GT_IND:
11549
11550         // Can not remove a GT_IND if it is currently a CSE candidate.
11551         if (gtIsActiveCSE_Candidate(tree))
11552             break;
11553
11554         bool foldAndReturnTemp; foldAndReturnTemp = false;
11555         temp = nullptr;
11556         ival1 = 0;
11557
11558         /* Try to Fold *(&X) into X */
11559         if (op1->gtOper == GT_ADDR) 
11560         {
11561             // Can not remove a GT_ADDR if it is currently a CSE candidate.
11562             if (gtIsActiveCSE_Candidate(op1))
11563                 break;
11564
11565             temp = op1->gtOp.gtOp1;         // X
11566
11567             // In the test below, if they're both TYP_STRUCT, this of course does *not* mean that
11568             // they are the *same* struct type.  In fact, they almost certainly aren't.  If the
11569             // address has an associated field sequence, that identifies this case; go through
11570             // the "lcl_fld" path rather than this one.
11571             FieldSeqNode* addrFieldSeq = NULL;  // This is an unused out parameter below.
11572             if (   typ == temp->TypeGet()
11573                 && !GetZeroOffsetFieldMap()->Lookup(op1, &addrFieldSeq))
11574             {
11575                 foldAndReturnTemp = true;
11576             }
11577             else if (temp->OperIsLocal())
11578             {
11579                 unsigned lclNum = temp->gtLclVarCommon.gtLclNum;
11580                 LclVarDsc *  varDsc = &lvaTable[lclNum];
11581
11582                 // We will try to optimize when we have a promoted struct promoted with a zero lvFldOffset
11583                 if (varDsc->lvPromoted && (varDsc->lvFldOffset == 0))
11584                 {
11585                     noway_assert(varTypeIsStruct(varDsc));
11586
11587                     // We will try to optimize when we have a single field struct that is being struct promoted
11588                     if (varDsc->lvFieldCnt == 1)
11589                     {
11590                         unsigned lclNumFld = varDsc->lvFieldLclStart;
11591                         // just grab the promoted field
11592                         LclVarDsc *  fieldVarDsc = &lvaTable[lclNumFld];
11593
11594                         // Also make sure that the tree type matches the fieldVarType and that it's lvFldOffset is zero
11595                         if (fieldVarDsc->TypeGet() == tree->TypeGet() && (fieldVarDsc->lvFldOffset == 0))
11596                         {
11597                             // We can just use the existing promoted field LclNum
11598                             temp->gtLclVarCommon.SetLclNum(lclNumFld);
11599                             temp->gtType = fieldVarDsc->TypeGet();
11600
11601                             foldAndReturnTemp = true;
11602                         }
11603                     }
11604                 }
11605                 // If the type of the IND (typ) is a "small int", and the type of the local has the
11606                 // same width, then we can reduce to just the local variable -- it will be
11607                 // correctly normalized, and signed/unsigned differences won't matter.
11608                 //
11609                 // The below transformation cannot be applied if the local var needs to be normalized on load.
11610                 else if ( varTypeIsSmall(typ) && 
11611                          (genTypeSize(lvaTable[lclNum].lvType) == genTypeSize(typ)) && 
11612                          !lvaTable[lclNum].lvNormalizeOnLoad() )
11613                 {
11614                     tree->gtType = temp->gtType;
11615                     foldAndReturnTemp = true;
11616                 }
11617                 else 
11618                 {
11619                     // Assumes that when Lookup returns "false" it will leave "fieldSeq" unmodified (i.e. nullptr)
11620                     assert(fieldSeq == nullptr);
11621                     bool b = GetZeroOffsetFieldMap()->Lookup(op1, &fieldSeq);
11622                     assert(b || fieldSeq == nullptr);
11623
11624                     if ((fieldSeq != nullptr) && (temp->OperGet() == GT_LCL_FLD))
11625                     {
11626                         // Append the field sequence, change the type.
11627                         temp->AsLclFld()->gtFieldSeq = GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
11628                         temp->gtType = tree->TypeGet();
11629
11630                         foldAndReturnTemp = true;
11631                     }
11632                 }
11633                 // Otherwise will will fold this into a GT_LCL_FLD below
11634                 //   where we check (temp != nullptr)
11635             }
11636             else // !temp->OperIsLocal()
11637             {
11638                 // We don't try to fold away the GT_IND/GT_ADDR for this case
11639                 temp = nullptr;
11640             }
11641         }
11642         else  if (op1->OperGet() == GT_ADD)
11643         {
11644             /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */
11645
11646             if (op1->gtOp.gtOp1->OperGet() == GT_ADDR &&
11647                 op1->gtOp.gtOp2->OperGet() == GT_CNS_INT
11648                 && (!(opts.MinOpts() || opts.compDbgCode)))
11649             {
11650                 // No overflow arithmetic with pointers
11651                 noway_assert(!op1->gtOverflow());
11652
11653                 temp = op1->gtOp.gtOp1->gtOp.gtOp1;
11654                 if (!temp->OperIsLocal())
11655                 {
11656                     temp = nullptr;
11657                     break;
11658                 }
11659
11660                 // Can not remove the GT_ADDR if it is currently a CSE candidate.
11661                 if (gtIsActiveCSE_Candidate(op1->gtOp.gtOp1))
11662                     break;
11663
11664                 ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
11665                 fieldSeq = op1->gtOp.gtOp2->gtIntCon.gtFieldSeq;
11666
11667                 // Does the address have an associated zero-offset field sequence?
11668                 FieldSeqNode* addrFieldSeq = NULL;
11669                 if (GetZeroOffsetFieldMap()->Lookup(op1->gtOp.gtOp1, &addrFieldSeq))
11670                 {
11671                     fieldSeq = GetFieldSeqStore()->Append(addrFieldSeq, fieldSeq);
11672                 }
11673
11674                 if (ival1 == 0 &&
11675                     typ == temp->TypeGet() &&
11676                     temp->TypeGet() != TYP_STRUCT)
11677                 {
11678                     noway_assert(!varTypeIsGC(temp->TypeGet()));
11679                     foldAndReturnTemp = true;
11680                 }
11681                 else
11682                 {
11683                     // The emitter can't handle large offsets
11684                     if (ival1 != (unsigned short)ival1)
11685                         break;
11686
11687                     // The emitter can get confused by invalid offsets
11688                     if (ival1 >= Compiler::lvaLclSize(temp->gtLclVarCommon.gtLclNum))
11689                         break;
11690
11691 #ifdef _TARGET_ARM_
11692                     // Check for a LclVar TYP_STRUCT with misalignment on a Floating Point field
11693                     //
11694                     if (varTypeIsFloating(tree->TypeGet()))
11695                     {
11696                         if ((ival1 % emitTypeSize(tree->TypeGet())) != 0)
11697                         {
11698                             tree->gtFlags |= GTF_IND_UNALIGNED;
11699                             break;
11700                         }
11701                     }
11702 #endif
11703                 }
11704                 // Now we can fold this into a GT_LCL_FLD below
11705                 //   where we check (temp != nullptr)
11706             }
11707         }
11708
11709 #ifdef DEBUG
11710         // If we have decided to fold, then temp cannot be nullptr
11711         if (foldAndReturnTemp)
11712         {
11713             assert(temp != nullptr);
11714         }
11715 #endif
11716
11717         if (temp != nullptr)
11718         {
11719             noway_assert(op1->gtOper == GT_ADD || op1->gtOper == GT_ADDR);
11720
11721             // If we haven't already decided to fold this expression
11722             //
11723             if (!foldAndReturnTemp)
11724             {
11725                 noway_assert(temp->OperIsLocal());
11726                 LclVarDsc* varDsc = &(lvaTable[temp->AsLclVarCommon()->gtLclNum]);
11727                 // Make sure we don't separately promote the fields of this struct.
11728                 if (varDsc->lvRegStruct)
11729                 {
11730                     // We can enregister, but can't promote.
11731                     varDsc->lvPromoted = false;
11732                 }
11733                 else
11734                 {
11735                     lvaSetVarDoNotEnregister(temp->gtLclVarCommon.gtLclNum DEBUGARG(DNER_LocalField));
11736                 }
11737
11738                 // We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
11739                 // or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
11740                 // Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
11741                 //
11742                 if (temp->OperGet() == GT_LCL_FLD)
11743                 {
11744                     temp->AsLclFld()->gtLclOffs += (unsigned short)ival1;
11745                     temp->AsLclFld()->gtFieldSeq =
11746                         GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
11747                 }
11748                 else
11749                 {
11750                     temp->ChangeOper(GT_LCL_FLD);  // Note that this makes the gtFieldSeq "NotAField"...
11751                     temp->AsLclFld()->gtLclOffs = (unsigned short)ival1;
11752                     if (fieldSeq != NULL)          // If it does represent a field, note that.
11753                         temp->AsLclFld()->gtFieldSeq = fieldSeq;
11754                 }
11755                 temp->gtType = tree->gtType;
11756                 foldAndReturnTemp = true;
11757             }
11758
11759             assert(foldAndReturnTemp == true);
11760
11761             // Keep the DONT_CSE flag in sync
11762             // (i.e keep the original value of this flag from tree)
11763             // as it can be set for 'temp' because a GT_ADDR always marks it for it's op1
11764             //
11765             temp->gtFlags &= ~GTF_DONT_CSE;
11766             temp->gtFlags |= (tree->gtFlags & GTF_DONT_CSE);
11767
11768             noway_assert(op1->gtOper == GT_ADD || op1->gtOper == GT_ADDR);
11769             noway_assert(temp->gtType == tree->gtType);
11770
11771             if (op1->OperGet() == GT_ADD)
11772             {
11773                 DEBUG_DESTROY_NODE(op1->gtOp.gtOp1);    // GT_ADDR
11774                 DEBUG_DESTROY_NODE(op1->gtOp.gtOp2);    // GT_CNS_INT
11775             }
11776             DEBUG_DESTROY_NODE(op1);                    // GT_ADD or GT_ADDR
11777             DEBUG_DESTROY_NODE(tree);                   // GT_IND
11778
11779             return temp;
11780         }
11781
11782         // Only do this optimization when we are in the global optimizer. Doing this after value numbering
11783         // could result in an invalid value number for the newly generated GT_IND node.
11784         if ((op1->OperGet() == GT_COMMA) && fgGlobalMorph)
11785         {
11786             // Perform the transform IND(COMMA(x, ..., z)) == COMMA(x, ..., IND(z)).
11787             // TBD: this transformation is currently necessary for correctness -- it might
11788             // be good to analyze the failures that result if we don't do this, and fix them
11789             // in other ways.  Ideally, this should be optional.
11790             GenTreePtr commaNode = op1;
11791             unsigned treeFlags = tree->gtFlags;
11792             commaNode->gtType = typ;
11793             commaNode->gtFlags = (treeFlags & ~GTF_REVERSE_OPS); // Bashing the GT_COMMA flags here is dangerous, clear the GTF_REVERSE_OPS at least.
11794 #ifdef DEBUG
11795             commaNode->gtFlags |= GTF_MORPHED;
11796 #endif
11797             while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
11798             {
11799                 commaNode = commaNode->gtOp.gtOp2;
11800                 commaNode->gtType = typ;
11801                 commaNode->gtFlags = (treeFlags & ~GTF_REVERSE_OPS); // Bashing the GT_COMMA flags here is dangerous, clear the GTF_REVERSE_OPS at least.
11802 #ifdef DEBUG
11803                 commaNode->gtFlags |= GTF_MORPHED;
11804 #endif
11805             }
11806             bool wasArrIndex = (tree->gtFlags & GTF_IND_ARR_INDEX) != 0;
11807             ArrayInfo arrInfo;
11808             if (wasArrIndex)
11809             {
11810                 bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
11811                 assert(b);
11812                 GetArrayInfoMap()->Remove(tree);
11813             }
11814             tree = op1;
11815             op1 = gtNewOperNode(GT_IND, typ, commaNode->gtOp.gtOp2);
11816             op1->gtFlags = treeFlags;
11817             if (wasArrIndex)
11818             {
11819                 GetArrayInfoMap()->Set(op1, arrInfo);
11820             }
11821 #ifdef DEBUG
11822             op1->gtFlags |= GTF_MORPHED;
11823 #endif
11824             commaNode->gtOp.gtOp2 = op1;
11825             return tree;
11826         }
11827
11828         break;
11829
11830     case GT_ADDR:
11831
11832         // Can not remove op1 if it is currently a CSE candidate.
11833         if (gtIsActiveCSE_Candidate(op1))
11834             break;
11835
11836         if (op1->OperGet() == GT_IND)
11837         {
11838             if ((op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
11839             {
11840                 // Can not remove a GT_ADDR if it is currently a CSE candidate.
11841                 if (gtIsActiveCSE_Candidate(tree))
11842                     break;
11843
11844                 // Perform the transform ADDR(IND(...)) == (...).  
11845                 GenTreePtr addr = op1->gtOp.gtOp1;
11846
11847                 noway_assert(varTypeIsGC(addr->gtType) || addr->gtType == TYP_I_IMPL);
11848
11849                 DEBUG_DESTROY_NODE(op1);
11850                 DEBUG_DESTROY_NODE(tree);
11851
11852                 return addr;
11853             }
11854         }
11855         else if (op1->gtOper == GT_CAST)
11856         {
11857             GenTreePtr casting = op1->gtCast.CastOp();
11858             if (casting->gtOper == GT_LCL_VAR || casting->gtOper == GT_CLS_VAR)
11859             {
11860                 DEBUG_DESTROY_NODE(op1);
11861                 tree->gtOp.gtOp1 = op1 = casting;
11862             }
11863         }
11864         else if ((op1->gtOper == GT_COMMA) && !optValnumCSE_phase)
11865         {
11866             // Perform the transform ADDR(COMMA(x, ..., z)) == COMMA(x, ..., ADDR(z)).
11867             // (Be sure to mark "z" as an l-value...)
11868             GenTreePtr commaNode = op1;
11869             while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
11870             {
11871                 commaNode = commaNode->gtOp.gtOp2;
11872             }
11873             // The top-level addr might be annotated with a zeroOffset field.
11874             FieldSeqNode* zeroFieldSeq = nullptr;
11875             bool isZeroOffset = GetZeroOffsetFieldMap()->Lookup(tree, &zeroFieldSeq);
11876             tree = op1;
11877             commaNode->gtOp.gtOp2->gtFlags |= GTF_DONT_CSE;
11878
11879             // If the node we're about to put under a GT_ADDR is a GT_IND, the indirection
11880             // doesn't need to be materialized, since we only want the addressing mode. Because 
11881             // of this, this GT_IND is not a faulting indirection and we don't have to extract it
11882             // as a side effect.
11883             GenTree* commaOp2 = commaNode->gtOp.gtOp2;
11884             if (commaOp2->gtOper == GT_IND)
11885             {
11886                 commaOp2->gtFlags |= GTF_IND_NONFAULTING;
11887             }
11888
11889             op1 = gtNewOperNode(GT_ADDR, TYP_BYREF, commaOp2);
11890
11891             if (isZeroOffset)
11892             {
11893                 // Transfer the annotation to the new GT_ADDR node.
11894                 GetZeroOffsetFieldMap()->Set(op1, zeroFieldSeq);
11895             }
11896             commaNode->gtOp.gtOp2 = op1;
11897             // Originally, I gave all the comma nodes type "byref".  But the ADDR(IND(x)) == x transform
11898             // might give op1 a type different from byref (like, say, native int).  So now go back and give
11899             // all the comma nodes the type of op1.
11900             commaNode = tree;
11901             while (commaNode->gtOper == GT_COMMA)
11902             {
11903                 commaNode->gtType = op1->gtType; commaNode->gtFlags |= op1->gtFlags;
11904 #ifdef DEBUG
11905                 commaNode->gtFlags |= GTF_MORPHED;
11906 #endif
11907                 commaNode = commaNode->gtOp.gtOp2;
11908             }
11909
11910             return tree;
11911         }
11912
11913         /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
11914         op1->gtFlags |= GTF_DONT_CSE;
11915         break;
11916
11917     case GT_COLON:
11918         if (fgGlobalMorph)
11919         {
11920             /* Mark the nodes that are conditionally executed */
11921             fgWalkTreePre(&tree, gtMarkColonCond);
11922         }
11923         /* Since we're doing this postorder we clear this if it got set by a child */
11924         fgRemoveRestOfBlock = false;
11925         break;
11926
11927     case GT_COMMA:
11928
11929         /* Special case: trees that don't produce a value */
11930         if  ((op2->OperKind() & GTK_ASGOP) ||
11931              (op2->OperGet() == GT_COMMA && op2->TypeGet() == TYP_VOID) ||
11932              fgIsThrow(op2))
11933         {
11934             typ = tree->gtType = TYP_VOID;
11935         }
11936
11937         // If we are in the Valuenum CSE phase then don't morph away anything as these
11938         // nodes may have CSE defs/uses in them.
11939         //
11940         if (!optValnumCSE_phase)
11941         {
11942             //Extract the side effects from the left side of the comma.  Since they don't "go" anywhere, this is
11943             //all we need.
11944
11945             GenTreePtr op1SideEffects = NULL;
11946             // The addition of "GTF_MAKE_CSE" below prevents us from throwing away (for example)
11947             // hoisted expressions in loops.
11948             gtExtractSideEffList(op1, &op1SideEffects, (GTF_SIDE_EFFECT | GTF_MAKE_CSE));
11949             if (op1SideEffects)
11950             {
11951                 //Replace the left hand side with the side effect list.
11952                 tree->gtOp.gtOp1 = op1SideEffects;
11953                 tree->gtFlags |= (op1SideEffects->gtFlags & GTF_ALL_EFFECT);
11954             }
11955             else
11956             {
11957                 /* The left operand is worthless, throw it away */
11958                 if (lvaLocalVarRefCounted)
11959                 {
11960                     lvaRecursiveDecRefCounts(op1);
11961                 }
11962                 op2->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
11963                 DEBUG_DESTROY_NODE(tree);
11964                 DEBUG_DESTROY_NODE(op1);
11965                 return op2;
11966             }
11967
11968             /* If the right operand is just a void nop node, throw it away */
11969             if  (op2->IsNothingNode() && op1->gtType == TYP_VOID)
11970             {
11971                 op1->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
11972                 DEBUG_DESTROY_NODE(tree);
11973                 DEBUG_DESTROY_NODE(op2);
11974                 return op1;
11975             }
11976         }
11977
11978         break;
11979
11980     case GT_JTRUE:
11981
11982         /* Special case if fgRemoveRestOfBlock is set to true */
11983         if (fgRemoveRestOfBlock)
11984         {
11985             if (fgIsCommaThrow(op1, true))
11986             {
11987                 GenTreePtr throwNode = op1->gtOp.gtOp1;
11988                 noway_assert(throwNode->gtType == TYP_VOID);
11989
11990                 return throwNode;
11991             }
11992
11993             noway_assert(op1->OperKind() & GTK_RELOP);
11994             noway_assert(op1->gtFlags    & GTF_EXCEPT);
11995
11996             // We need to keep op1 for the side-effects. Hang it off
11997             // a GT_COMMA node
11998
11999             tree->ChangeOper(GT_COMMA);
12000             tree->gtOp.gtOp2 = op2 = gtNewNothingNode();
12001
12002             // Additionally since we're eliminating the JTRUE
12003             // codegen won't like it if op1 is a RELOP of longs, floats or doubles.
12004             // So we change it into a GT_COMMA as well.
12005             op1->ChangeOper(GT_COMMA);
12006             op1->gtType = op1->gtOp.gtOp1->gtType;
12007
12008             return tree;
12009         }
12010
12011     default:
12012         break;
12013     }
12014
12015     noway_assert(oper == tree->gtOper);
12016
12017     // If we are in the Valuenum CSE phase then don't morph away anything as these
12018     // nodes may have CSE defs/uses in them.
12019     //
12020     if (!optValnumCSE_phase && (oper != GT_ASG) && (oper != GT_COLON) && !tree->IsList())
12021     {
12022         /* Check for op1 as a GT_COMMA with a unconditional throw node */
12023         if (op1 && fgIsCommaThrow(op1, true))
12024         {
12025             if ((op1->gtFlags & GTF_COLON_COND) == 0)
12026             {
12027                 /* We can safely throw out the rest of the statements */
12028                 fgRemoveRestOfBlock = true;
12029             }
12030
12031             GenTreePtr throwNode = op1->gtOp.gtOp1;
12032             noway_assert(throwNode->gtType == TYP_VOID);
12033
12034             if (oper == GT_COMMA)
12035             {
12036                 /* Both tree and op1 are GT_COMMA nodes */
12037                 /* Change the tree's op1 to the throw node: op1->gtOp.gtOp1 */
12038                 tree->gtOp.gtOp1 = throwNode;
12039                 return tree;
12040             }
12041             else if (oper != GT_NOP)
12042             {
12043                 if (genActualType(typ) == genActualType(op1->gtType))
12044                 {
12045                     /* The types match so, return the comma throw node as the new tree */
12046                     return op1;
12047                 }
12048                 else
12049                 {
12050                     if (typ == TYP_VOID)
12051                     {
12052                         // Return the throw node
12053                         return throwNode;
12054                     }
12055                     else
12056                     {
12057                         GenTreePtr commaOp2 = op1->gtOp.gtOp2;
12058
12059                         // need type of oper to be same as tree
12060                         if (typ == TYP_LONG)
12061                         {
12062                             commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
12063                             commaOp2->gtIntConCommon.SetLngValue(0);
12064                             /* Change the types of oper and commaOp2 to TYP_LONG */
12065                             op1->gtType = commaOp2->gtType = TYP_LONG;
12066                         }
12067                         else if (varTypeIsFloating(typ))
12068                         {
12069                             commaOp2->ChangeOperConst(GT_CNS_DBL);
12070                             commaOp2->gtDblCon.gtDconVal = 0.0;
12071                             /* Change the types of oper and commaOp2 to TYP_DOUBLE */
12072                             op1->gtType = commaOp2->gtType = TYP_DOUBLE;
12073                         }
12074                         else
12075                         {
12076                             commaOp2->ChangeOperConst(GT_CNS_INT);
12077                             commaOp2->gtIntConCommon.SetIconValue(0);
12078                             /* Change the types of oper and commaOp2 to TYP_INT */
12079                             op1->gtType = commaOp2->gtType = TYP_INT;
12080                         }
12081
12082                         /* Return the GT_COMMA node as the new tree */
12083                         return op1;
12084                     }
12085                 }
12086             }
12087         }
12088
12089         /* Check for op2 as a GT_COMMA with a unconditional throw */
12090
12091         if (op2 && fgIsCommaThrow(op2, true))
12092         {
12093             if ((op2->gtFlags & GTF_COLON_COND) == 0)
12094             {
12095                 /* We can safely throw out the rest of the statements */
12096                 fgRemoveRestOfBlock = true;
12097             }
12098
12099             // If op1 has no side-effects
12100             if ((op1->gtFlags & GTF_ALL_EFFECT) == 0)
12101             {
12102                 // If tree is an asg node
12103                 if (tree->OperIsAssignment())
12104                 {
12105                     /* Return the throw node as the new tree */
12106                     return op2->gtOp.gtOp1;
12107                 }
12108
12109                 if (tree->OperGet() == GT_ARR_BOUNDS_CHECK)
12110                 {
12111                     /* Return the throw node as the new tree */
12112                     return op2->gtOp.gtOp1;
12113                 }
12114
12115                 // If tree is a comma node
12116                 if (tree->OperGet() == GT_COMMA)
12117                 {
12118                     /* Return the throw node as the new tree */
12119                      return op2->gtOp.gtOp1;
12120                 }
12121
12122                 /* for the shift nodes the type of op2 can differ from the tree type */
12123                 if ((typ == TYP_LONG) && (genActualType(op2->gtType) == TYP_INT))
12124                 {
12125                     noway_assert(GenTree::OperIsShiftOrRotate(oper));
12126
12127                     GenTreePtr commaOp2 = op2->gtOp.gtOp2;
12128
12129                     commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
12130                     commaOp2->gtIntConCommon.SetLngValue(0);
12131
12132                     /* Change the types of oper and commaOp2 to TYP_LONG */
12133                     op2->gtType = commaOp2->gtType = TYP_LONG;
12134                 }
12135
12136                 if ((genActualType(typ) == TYP_INT) && (genActualType(op2->gtType) == TYP_LONG ||
12137                                                         varTypeIsFloating(op2->TypeGet())))
12138                 {
12139                     // An example case is comparison (say GT_GT) of two longs or floating point values.
12140
12141                     GenTreePtr commaOp2 = op2->gtOp.gtOp2;
12142
12143                     commaOp2->ChangeOperConst(GT_CNS_INT);
12144                     commaOp2->gtIntCon.gtIconVal = 0;
12145                     /* Change the types of oper and commaOp2 to TYP_INT */
12146                     op2->gtType = commaOp2->gtType = TYP_INT;
12147                 }
12148
12149                 if ((typ == TYP_BYREF) && (genActualType(op2->gtType) == TYP_I_IMPL))
12150                 {
12151                     noway_assert(tree->OperGet() == GT_ADD);
12152
12153                     GenTreePtr commaOp2 = op2->gtOp.gtOp2;
12154
12155                     commaOp2->ChangeOperConst(GT_CNS_INT);
12156                     commaOp2->gtIntCon.gtIconVal = 0;
12157                     /* Change the types of oper and commaOp2 to TYP_BYREF */
12158                     op2->gtType = commaOp2->gtType = TYP_BYREF;
12159                 }
12160
12161                 /* types should now match */
12162                 noway_assert( (genActualType(typ) == genActualType(op2->gtType)));
12163
12164                 /* Return the GT_COMMA node as the new tree */
12165                 return op2;
12166             }
12167         }
12168     }
12169
12170     /*-------------------------------------------------------------------------
12171      * Optional morphing is done if tree transformations is permitted
12172      */
12173
12174     if  ((opts.compFlags & CLFLG_TREETRANS) == 0)
12175         return tree;
12176
12177     tree = fgMorphSmpOpOptional(tree->AsOp());
12178
12179     } // extra scope for gcc workaround
12180     return tree;
12181 }
12182 #ifdef _PREFAST_
12183 #pragma warning(pop)
12184 #endif
12185
12186
12187 GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
12188 {
12189     genTreeOps oper = tree->gtOper;
12190     GenTree* op1 = tree->gtOp1;
12191     GenTree* op2 = tree->gtOp2;
12192     var_types       typ     = tree->TypeGet();
12193
12194     if  (GenTree::OperIsCommutative(oper))
12195     {
12196         /* Swap the operands so that the more expensive one is 'op1' */
12197
12198         if  (tree->gtFlags & GTF_REVERSE_OPS)
12199         {
12200             tree->gtOp1 = op2;
12201             tree->gtOp2 = op1;
12202
12203             op2 = op1;
12204             op1 = tree->gtOp1;
12205
12206             tree->gtFlags &= ~GTF_REVERSE_OPS;
12207         }
12208
12209         if (oper == op2->gtOper)
12210         {
12211             /*  Reorder nested operators at the same precedence level to be
12212                 left-recursive. For example, change "(a+(b+c))" to the
12213                 equivalent expression "((a+b)+c)".
12214              */
12215
12216             /* Things are handled differently for floating-point operators */
12217
12218             if  (!varTypeIsFloating(tree->TypeGet()))
12219             {
12220                 fgMoveOpsLeft(tree);
12221                 op1 = tree->gtOp1;
12222                 op2 = tree->gtOp2;
12223             }
12224         }
12225
12226     }
12227
12228 #if REARRANGE_ADDS
12229
12230     /* Change "((x+icon)+y)" to "((x+y)+icon)"
12231        Don't reorder floating-point operations */
12232
12233     if  ((oper        == GT_ADD) && !tree->gtOverflow() &&
12234          (op1->gtOper == GT_ADD) && ! op1->gtOverflow() && varTypeIsIntegralOrI(typ))
12235     {
12236         GenTreePtr      ad2 = op1->gtOp.gtOp2;
12237
12238         if  (op2->OperIsConst() == 0 &&
12239              ad2->OperIsConst() != 0)
12240         {
12241             //This takes
12242             //       + (tree)
12243             //      / \
12244             //     /   \
12245             //    /     \
12246             //   + (op1) op2
12247             //  / \
12248             //     \
12249             //     ad2
12250             //
12251             // And it swaps ad2 and op2.  If (op2) is varTypeIsGC, then this implies that (tree) is
12252             // varTypeIsGC.  If (op1) is not, then when we swap (ad2) and (op2), then we have a TYP_INT node
12253             // (op1) with a child that is varTypeIsGC.  If we encounter that situation, make (op1) the same
12254             // type as (tree).
12255             //
12256             // Also, if (ad2) is varTypeIsGC then (tree) must also be (since op1 is), so no fixing is
12257             // necessary
12258
12259             if (varTypeIsGC(op2->TypeGet()))
12260             {
12261                 noway_assert(varTypeIsGC(typ));
12262                 op1->gtType = typ;
12263             }
12264             tree->gtOp2 = ad2;
12265
12266             op1 ->gtOp.gtOp2 = op2;
12267             op1->gtFlags    |= op2->gtFlags & GTF_ALL_EFFECT;
12268
12269             op2 = tree->gtOp2;
12270         }
12271     }
12272
12273 #endif
12274
12275     /*-------------------------------------------------------------------------
12276      * Perform optional oper-specific postorder morphing
12277      */
12278
12279     switch (oper)
12280     {
12281         genTreeOps      cmop;
12282         bool            dstIsSafeLclVar;
12283
12284     case GT_ASG:
12285
12286         /* We'll convert "a = a <op> x" into "a <op>= x"                     */
12287         /*     and also  "a = x <op> a" into "a <op>= x" for communative ops */
12288
12289 #if !LONG_ASG_OPS
12290         if  (typ == TYP_LONG)
12291             break;
12292 #endif
12293
12294         /* Make sure we're allowed to do this */
12295
12296         if (optValnumCSE_phase)
12297         {
12298             // It is not safe to reorder/delete CSE's
12299             break;
12300         }
12301
12302         /* Are we assigning to a GT_LCL_VAR ? */
12303
12304         dstIsSafeLclVar = (op1->gtOper == GT_LCL_VAR);
12305
12306         /* If we have a GT_LCL_VAR, then is the address taken? */
12307         if (dstIsSafeLclVar)
12308         {
12309             unsigned     lclNum = op1->gtLclVarCommon.gtLclNum;
12310             LclVarDsc *  varDsc = lvaTable + lclNum;
12311
12312             noway_assert(lclNum < lvaCount);
12313
12314             /* Is the address taken? */
12315             if  (varDsc->lvAddrExposed)
12316             {
12317                 dstIsSafeLclVar = false;
12318             }
12319             else if (op2->gtFlags & GTF_ASG)
12320             {
12321                 break;
12322             }
12323         }
12324
12325         if (!dstIsSafeLclVar)
12326         {
12327             if (op2->gtFlags & GTF_ASG)
12328                 break;
12329
12330             if  ((op2->gtFlags & GTF_CALL) && (op1->gtFlags & GTF_ALL_EFFECT))
12331                 break;
12332         }
12333
12334         /* Special case: a cast that can be thrown away */
12335
12336         if  (op1->gtOper == GT_IND  &&
12337              op2->gtOper == GT_CAST &&
12338              !op2->gtOverflow()      )
12339         {
12340             var_types       srct;
12341             var_types       cast;
12342             var_types       dstt;
12343
12344             srct =             op2->gtCast.CastOp()->TypeGet();
12345             cast = (var_types) op2->CastToType();
12346             dstt =             op1->TypeGet();
12347
12348             /* Make sure these are all ints and precision is not lost */
12349
12350             if  (cast >= dstt && dstt <= TYP_INT && srct <= TYP_INT)
12351                 op2 = tree->gtOp2 = op2->gtCast.CastOp();
12352         }
12353
12354         /* Make sure we have the operator range right */
12355
12356         noway_assert(GT_SUB == GT_ADD + 1);
12357         noway_assert(GT_MUL == GT_ADD + 2);
12358         noway_assert(GT_DIV == GT_ADD + 3);
12359         noway_assert(GT_MOD == GT_ADD + 4);
12360         noway_assert(GT_UDIV== GT_ADD + 5);
12361         noway_assert(GT_UMOD== GT_ADD + 6);
12362
12363         noway_assert(GT_OR  == GT_ADD + 7);
12364         noway_assert(GT_XOR == GT_ADD + 8);
12365         noway_assert(GT_AND == GT_ADD + 9);
12366
12367         noway_assert(GT_LSH == GT_ADD + 10);
12368         noway_assert(GT_RSH == GT_ADD + 11);
12369         noway_assert(GT_RSZ == GT_ADD + 12);
12370
12371         /* Check for a suitable operator on the RHS */
12372
12373         cmop = op2->OperGet();
12374
12375         switch (cmop)
12376         {
12377         case GT_NEG:
12378             // GT_CHS only supported for integer types
12379             if  ( varTypeIsFloating(tree->TypeGet()))
12380                 break;
12381
12382             goto ASG_OP;
12383
12384         case GT_MUL:
12385             // GT_ASG_MUL only supported for floating point types
12386             if  (!varTypeIsFloating(tree->TypeGet()))
12387                 break;
12388
12389             __fallthrough;
12390
12391         case GT_ADD:
12392         case GT_SUB:
12393             if (op2->gtOverflow())
12394             {
12395                 /* Disable folding into "<op>=" if the result can be
12396                    visible to anyone as <op> may throw an exception and
12397                    the assignment should not proceed
12398                    We are safe with an assignment to a local variables
12399                  */
12400                 if (ehBlockHasExnFlowDsc(compCurBB))
12401                     break;
12402                 if (!dstIsSafeLclVar)
12403                     break;
12404             }
12405 #ifndef _TARGET_AMD64_
12406             // This is hard for byte-operations as we need to make
12407             // sure both operands are in RBM_BYTE_REGS.
12408             if (varTypeIsByte(op2->TypeGet()))
12409                 break;
12410 #endif // _TARGET_AMD64_
12411             goto ASG_OP;
12412
12413         case GT_DIV:
12414         case GT_UDIV:
12415             // GT_ASG_DIV only supported for floating point types
12416             if  (!varTypeIsFloating(tree->TypeGet()))
12417                 break;
12418
12419         case GT_LSH:
12420         case GT_RSH:
12421         case GT_RSZ:
12422
12423 #if LONG_ASG_OPS
12424
12425             if  (typ == TYP_LONG)
12426                 break;
12427 #endif
12428
12429         case GT_OR:
12430         case GT_XOR:
12431         case GT_AND:
12432
12433 #if LONG_ASG_OPS
12434
12435             /* TODO: allow non-const long assignment operators */
12436
12437             if  (typ == TYP_LONG && op2->gtOp.gtOp2->gtOper != GT_CNS_LNG)
12438                 break;
12439 #endif
12440
12441 ASG_OP:
12442             {
12443                 bool bReverse = false;
12444                 bool bAsgOpFoldable = fgShouldCreateAssignOp(tree, &bReverse);
12445                 if (bAsgOpFoldable)
12446                 {
12447                     if (bReverse)
12448                     {
12449                         // We will transform this from "a = x <op> a" to "a <op>= x"
12450                         // so we can now destroy the duplicate "a"
12451                         DEBUG_DESTROY_NODE(op2->gtOp.gtOp2);
12452                         op2->gtOp.gtOp2 = op2->gtOp.gtOp1;
12453                     }
12454
12455                     /* Special case: "x |= -1" and "x &= 0" */
12456                     if  (cmop == GT_AND || cmop == GT_OR)
12457                     {
12458                         if  (op2->gtOp.gtOp2->IsCnsIntOrI())
12459                         {
12460                             ssize_t     icon = op2->gtOp.gtOp2->gtIntCon.gtIconVal;
12461
12462                             noway_assert(typ <= TYP_UINT);
12463
12464                             if  ((cmop == GT_AND && icon == 0) ||
12465                                 (cmop == GT_OR  && icon == -1))
12466                             {
12467                                 /* Simply change to an assignment */
12468                                 tree->gtOp2 = op2->gtOp.gtOp2;
12469                                 break;
12470                             }
12471                         }
12472                     }
12473
12474                     if  (cmop == GT_NEG)
12475                     {
12476                         /* This is "x = -x;", use the flipsign operator */
12477
12478                         tree->ChangeOper  (GT_CHS);
12479
12480                         if  (op1->gtOper == GT_LCL_VAR)
12481                             op1->gtFlags |= GTF_VAR_USEASG;
12482
12483                         tree->gtOp2 = gtNewIconNode(0, op1->TypeGet());
12484
12485                         break;
12486                     }
12487
12488                     if (cmop == GT_RSH && varTypeIsSmall(op1->TypeGet()) && varTypeIsUnsigned(op1->TypeGet()))
12489                     {
12490                         // Changing from x = x op y to x op= y when x is a small integer type
12491                         // makes the op size smaller (originally the op size was 32 bits, after
12492                         // sign or zero extension of x, and there is an implicit truncation in the
12493                         // assignment).
12494                         // This is ok in most cases because the upper bits were
12495                         // lost when assigning the op result to a small type var,
12496                         // but it may not be ok for the right shift operation where the higher bits
12497                         // could be shifted into the lower bits and preserved.
12498                         // Signed right shift of signed x still works (i.e. (sbyte)((int)(sbyte)x >>signed y) == (sbyte)x >>signed y))
12499                         // as do unsigned right shift ((ubyte)((int)(ubyte)x >>unsigned y) == (ubyte)x >>unsigned y), but
12500                         // signed right shift of an unigned small type may give the wrong result:
12501                         // e.g. (ubyte)((int)(ubyte)0xf0 >>signed 4) == 0x0f,
12502                         // but  (ubyte)0xf0 >>signed 4 == 0xff which is incorrect.
12503                         // The result becomes correct if we use >>unsigned instead of >>signed.
12504                         noway_assert(op1->TypeGet() == op2->gtOp.gtOp1->TypeGet());
12505                         cmop = GT_RSZ;
12506                     }
12507
12508                     /* Replace with an assignment operator */
12509                     noway_assert(GT_ADD - GT_ADD == GT_ASG_ADD - GT_ASG_ADD);
12510                     noway_assert(GT_SUB - GT_ADD == GT_ASG_SUB - GT_ASG_ADD);
12511                     noway_assert(GT_OR  - GT_ADD == GT_ASG_OR  - GT_ASG_ADD);
12512                     noway_assert(GT_XOR - GT_ADD == GT_ASG_XOR - GT_ASG_ADD);
12513                     noway_assert(GT_AND - GT_ADD == GT_ASG_AND - GT_ASG_ADD);
12514                     noway_assert(GT_LSH - GT_ADD == GT_ASG_LSH - GT_ASG_ADD);
12515                     noway_assert(GT_RSH - GT_ADD == GT_ASG_RSH - GT_ASG_ADD);
12516                     noway_assert(GT_RSZ - GT_ADD == GT_ASG_RSZ - GT_ASG_ADD);
12517
12518                     tree->SetOper((genTreeOps)(cmop - GT_ADD + GT_ASG_ADD));
12519                     tree->gtOp2 = op2->gtOp.gtOp2;
12520
12521                     /* Propagate GTF_OVERFLOW */
12522
12523                     if (op2->gtOverflowEx())
12524                     {
12525                         tree->gtType   =  op2->gtType;
12526                         tree->gtFlags |= (op2->gtFlags &
12527                             (GTF_OVERFLOW|GTF_EXCEPT|GTF_UNSIGNED));
12528                     }
12529
12530 #if FEATURE_SET_FLAGS
12531
12532                     /* Propagate GTF_SET_FLAGS */
12533                     if (op2->gtSetFlags())
12534                     {
12535                         tree->gtRequestSetFlags();
12536                     }
12537
12538 #endif // FEATURE_SET_FLAGS
12539
12540                     DEBUG_DESTROY_NODE(op2);
12541                     op2 = tree->gtOp2;
12542
12543                     /* The target is used as well as being defined */
12544                     if (op1->OperIsLocal())
12545                         op1->gtFlags |= GTF_VAR_USEASG;
12546
12547
12548 #if CPU_HAS_FP_SUPPORT
12549                     /* Check for the special case "x += y * x;" */
12550
12551                     // GT_ASG_MUL only supported for floating point types
12552                     if (cmop != GT_ADD && cmop != GT_SUB)
12553                         break;
12554
12555                     if  (op2->gtOper == GT_MUL && varTypeIsFloating(tree->TypeGet()))
12556                     {
12557                         if      (GenTree::Compare(op1, op2->gtOp.gtOp1))
12558                         {
12559                             /* Change "x += x * y" into "x *= (y + 1)" */
12560
12561                             op2 = op2->gtOp.gtOp2;
12562                         }
12563                         else if (GenTree::Compare(op1, op2->gtOp.gtOp2))
12564                         {
12565                             /* Change "x += y * x" into "x *= (y + 1)" */
12566
12567                             op2 = op2->gtOp.gtOp1;
12568                         }
12569                         else
12570                             break;
12571
12572                         op1 = gtNewDconNode(1.0);
12573
12574                         /* Now make the "*=" node */
12575
12576                         if (cmop == GT_ADD)
12577                         {
12578                             /* Change "x += x * y" into "x *= (y + 1)" */
12579
12580                             tree->gtOp2 = op2 = gtNewOperNode(GT_ADD,
12581                                 tree->TypeGet(),
12582                                 op2,
12583                                 op1);
12584                         }
12585                         else
12586                         {
12587                             /* Change "x -= x * y" into "x *= (1 - y)" */
12588
12589                             noway_assert(cmop == GT_SUB);
12590                             tree->gtOp2 = op2 = gtNewOperNode(GT_SUB,
12591                                 tree->TypeGet(),
12592                                 op1,
12593                                 op2);
12594                         }
12595                         tree->ChangeOper(GT_ASG_MUL);
12596                     }
12597 #endif // CPU_HAS_FP_SUPPORT
12598                 }
12599             }
12600
12601             break;
12602
12603         case GT_NOT:
12604
12605             /* Is the destination identical to the first RHS sub-operand? */
12606
12607             if  (GenTree::Compare(op1, op2->gtOp.gtOp1))
12608             {
12609                 /* This is "x = ~x" which is the same as "x ^= -1"
12610                  * Transform the node into a GT_ASG_XOR */
12611
12612                 noway_assert(genActualType(typ) == TYP_INT ||
12613                        genActualType(typ) == TYP_LONG);
12614
12615                 op2->gtOp.gtOp2 = (genActualType(typ) == TYP_INT)
12616                                     ? gtNewIconNode(-1)
12617                                     : gtNewLconNode(-1);
12618
12619                 cmop = GT_XOR;
12620                 goto ASG_OP;
12621             }
12622
12623             break;
12624         default:
12625             break;
12626         }
12627
12628         break;
12629
12630     case GT_MUL:
12631
12632         /* Check for the case "(val + icon) * icon" */
12633
12634         if  (op2->gtOper == GT_CNS_INT &&
12635              op1->gtOper == GT_ADD)
12636         {
12637             GenTreePtr  add = op1->gtOp.gtOp2;
12638
12639             if  (add->IsCnsIntOrI() && (op2->GetScaleIndexMul() != 0))
12640             {
12641                 if (tree->gtOverflow() || op1->gtOverflow())
12642                 {
12643                     break;
12644                 }
12645
12646                 ssize_t     imul = op2->gtIntCon.gtIconVal;
12647                 ssize_t     iadd = add->gtIntCon.gtIconVal;
12648
12649                 /* Change '(val + iadd) * imul' -> '(val * imul) + (iadd * imul)' */
12650
12651                 oper         = GT_ADD;
12652                 tree->ChangeOper(oper);
12653
12654                 op2->gtIntCon.gtIconVal = iadd * imul;
12655
12656                 op1->ChangeOper(GT_MUL);
12657
12658                 add->gtIntCon.gtIconVal = imul;
12659 #ifdef _TARGET_64BIT_
12660                 if (add->gtType == TYP_INT)
12661                 {
12662                     // we need to properly re-sign-extend or truncate after multiplying two int constants above
12663                     add->AsIntCon()->TruncateOrSignExtend32();
12664                 }
12665 #endif //_TARGET_64BIT_
12666             }
12667         }
12668
12669         break;
12670
12671     case GT_DIV:
12672
12673         /* For "val / 1", just return "val" */
12674
12675         if ((op2->gtOper == GT_CNS_INT) && (op2->gtIntConCommon.IconValue() == 1))
12676         {
12677             DEBUG_DESTROY_NODE(tree);
12678             return op1;
12679         }
12680         // Do this for "long" constants as well as ints.
12681         else if ((op2->gtOper == GT_CNS_LNG) && (op2->gtIntConCommon.LngValue() == 1))
12682         {
12683             DEBUG_DESTROY_NODE(tree);
12684             return op1;
12685         }
12686
12687         break;
12688
12689     case GT_LSH:
12690
12691         /* Check for the case "(val + icon) << icon" */
12692
12693         if  (op2->IsCnsIntOrI() &&
12694              op1->gtOper == GT_ADD && !op1->gtOverflow())
12695         {
12696             GenTreePtr  cns = op1->gtOp.gtOp2;
12697
12698             if  (cns->IsCnsIntOrI() && (op2->GetScaleIndexShf() != 0))
12699             {
12700                 ssize_t     ishf = op2->gtIntConCommon.IconValue();
12701                 ssize_t     iadd = cns->gtIntConCommon.IconValue();
12702
12703 //                  printf("Changing '(val+icon1)<<icon2' into '(val<<icon2+icon1<<icon2)'\n");
12704
12705                 /* Change "(val + iadd) << ishf" into "(val<<ishf + iadd<<ishf)" */
12706
12707                 tree->ChangeOper(GT_ADD);
12708                 ssize_t     result = iadd << ishf;
12709                 op2->gtIntConCommon.SetIconValue(result);
12710 #ifdef _TARGET_64BIT_
12711                 if (op1->gtType == TYP_INT)
12712                 {
12713                     op2->AsIntCon()->TruncateOrSignExtend32();
12714                 }
12715 #endif // _TARGET_64BIT_
12716                 
12717                 // we are reusing the shift amount node here, but the type we want is that of the shift result
12718                 op2->gtType = op1->gtType;
12719
12720                 if (cns->gtOper == GT_CNS_INT &&
12721                     cns->gtIntCon.gtFieldSeq != nullptr &&
12722                     cns->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
12723                 {
12724                     assert(cns->gtIntCon.gtFieldSeq->m_next == nullptr);
12725                     op2->gtIntCon.gtFieldSeq = cns->gtIntCon.gtFieldSeq;
12726                 }
12727
12728                 op1->ChangeOper(GT_LSH);
12729
12730                 cns->gtIntConCommon.SetIconValue(ishf);
12731             }
12732         }
12733
12734         break;
12735
12736     case GT_XOR:
12737
12738         if (!optValnumCSE_phase)
12739         {
12740             /* "x ^ -1" is "~x" */
12741             
12742             if ((op2->gtOper == GT_CNS_INT) && (op2->gtIntConCommon.IconValue() == -1))
12743             {
12744                 tree->ChangeOper(GT_NOT);
12745                 tree->gtOp2 = NULL;
12746                 DEBUG_DESTROY_NODE(op2);
12747             }
12748             else if ((op2->gtOper == GT_CNS_LNG) && (op2->gtIntConCommon.LngValue() == -1))
12749             {
12750                 tree->ChangeOper(GT_NOT);
12751                 tree->gtOp2 = NULL;
12752                 DEBUG_DESTROY_NODE(op2);
12753             }
12754             else if ((op2->gtOper == GT_CNS_INT) && (op2->gtIntConCommon.IconValue() == 1) &&
12755                      op1->OperIsCompare())
12756             {
12757                 /* "binaryVal ^ 1" is "!binaryVal" */
12758                 gtReverseCond(op1);
12759                 DEBUG_DESTROY_NODE(op2);
12760                 DEBUG_DESTROY_NODE(tree);
12761                 return op1;
12762             }
12763         }
12764
12765         break;
12766
12767     case GT_INITBLK:
12768         return fgMorphInitBlock(tree);
12769         break;
12770
12771     case GT_COPYOBJ:
12772     case GT_COPYBLK:
12773         return fgMorphCopyBlock(tree);
12774         break;
12775
12776     default:
12777         break;
12778     }
12779     return tree;
12780 }
12781
12782
12783 // code to generate a magic number and shift amount for the magic number division 
12784 // optimization.  This code is previously from UTC where it notes it was taken from
12785 // _The_PowerPC_Compiler_Writer's_Guide_, pages 57-58.
12786 // The paper it is based on is "Division by invariant integers using multiplication"
12787 // by Torbjorn Granlund and Peter L. Montgomery in PLDI 94
12788
12789 template <typename T>
12790 T GetSignedMagicNumberForDivide(T denom, int *shift /*out*/)
12791 {
12792     // static SMAG smag;
12793     const int bits = sizeof(T) * 8;
12794     const int bits_minus_1 = bits - 1;
12795
12796     typedef typename jitstd::make_unsigned<T>::type UT;
12797
12798     const UT two_nminus1 = UT(1) << bits_minus_1;
12799
12800     int p;
12801     UT absDenom;
12802     UT absNc;
12803     UT delta;
12804     UT q1;
12805     UT r1;
12806     UT r2;
12807     UT q2;
12808     UT t;
12809     T result_magic;
12810     int result_shift;
12811     int iters = 0;
12812
12813     absDenom = abs(denom);
12814     t = two_nminus1 + ((unsigned int)denom >> 31);
12815     absNc = t - 1 - (t % absDenom);     // absolute value of nc
12816     p = bits_minus_1;                   // initialize p
12817     q1 = two_nminus1 / absNc;           // initialize q1 = 2^p / abs(nc)
12818     r1 = two_nminus1 - (q1 * absNc);    // initialize r1 = rem(2^p, abs(nc))
12819     q2 = two_nminus1 / absDenom;        // initialize q1 = 2^p / abs(denom)
12820     r2 = two_nminus1 - (q2 * absDenom); // initialize r1 = rem(2^p, abs(denom))
12821
12822     do {
12823         iters++;
12824         p++;
12825         q1 *= 2;                        // update q1 = 2^p / abs(nc)
12826         r1 *= 2;                        // update r1 = rem(2^p / abs(nc))
12827
12828         if (r1 >= absNc) {              // must be unsigned comparison
12829             q1++;
12830             r1 -= absNc;
12831         }
12832
12833         q2 *= 2;                        // update q2 = 2^p / abs(denom)
12834         r2 *= 2;                        // update r2 = rem(2^p / abs(denom))
12835
12836         if (r2 >= absDenom) {           // must be unsigned comparison
12837             q2++;
12838             r2 -= absDenom;
12839         }
12840
12841         delta = absDenom - r2;
12842     } while (q1 < delta || (q1 == delta && r1 == 0));
12843
12844     result_magic = q2 + 1;              // resulting magic number
12845     if (denom < 0) {
12846         result_magic = -result_magic;
12847     }
12848     *shift = p - bits;                  // resulting shift
12849
12850     return result_magic;
12851 }
12852
12853
12854 bool Compiler::fgShouldUseMagicNumberDivide(GenTreeOp* tree)
12855 {
12856 #ifdef _TARGET_ARM64_
12857     // TODO-ARM64-NYI: We don't have a 'mulHi' implementation yet for ARM64
12858     return false;
12859 #else
12860
12861     // During the optOptimizeValnumCSEs phase we can call fgMorph and when we do,
12862     // if this method returns true we will introduce a new LclVar and
12863     // a couple of new GenTree nodes, including an assignment to the new LclVar.
12864     // None of these new GenTree nodes will have valid ValueNumbers. 
12865     // That is an invalid state for a GenTree node during the optOptimizeValnumCSEs phase.
12866     //
12867     // Also during optAssertionProp when extracting side effects we can assert 
12868     // during gtBuildCommaList if we have one tree that has Value Numbers
12869     //  and another one that does not.
12870     // 
12871     if (!fgGlobalMorph)
12872     {
12873         // We only perform the Magic Number Divide optimization during
12874         // the initial global morph phase
12875         return false;
12876     }
12877
12878     if (tree->gtFlags & GTF_OVERFLOW)
12879         return false;
12880
12881     if (tree->gtOp2->gtOper != GT_CNS_INT && tree->gtOp2->gtOper != GT_CNS_LNG)
12882         return false;
12883
12884     ssize_t cons = tree->gtOp2->gtIntConCommon.IconValue();
12885
12886     if (cons == 0 || cons == -1 || cons == 1)
12887         return false;
12888
12889     // codegen will expand these
12890     if (isPow2(cons))
12891         return false;
12892
12893     // someone else will fold this away, so don't make it complicated for them
12894     if (tree->gtOp1->IsCnsIntOrI())
12895         return false;
12896
12897     // There is no technical barrier to handling unsigned, however it is quite rare
12898     // and more work to support and test
12899     if (tree->gtFlags & GTF_UNSIGNED)
12900         return false;
12901
12902     return true;
12903 #endif
12904 }
12905
12906
12907 // transform x%c -> x-((x/c)*c)
12908
12909 GenTree* Compiler::fgMorphModByConst(GenTreeOp* tree)
12910 {
12911     assert(fgShouldUseMagicNumberDivide(tree));
12912
12913     var_types type = tree->gtType;
12914
12915     GenTree* cns = tree->gtOp2;
12916
12917     GenTree* numerator = fgMakeMultiUse(&tree->gtOp1);
12918
12919     tree->SetOper(GT_DIV);
12920
12921     GenTree* mul = gtNewOperNode(GT_MUL, type, tree, gtCloneExpr(cns));
12922
12923     GenTree* sub = gtNewOperNode(GT_SUB, type, numerator, mul);
12924
12925 #ifdef DEBUG
12926     sub->gtFlags |= GTF_MORPHED;
12927 #endif
12928
12929     return sub;
12930 }
12931
12932 // For ARM64 we don't have a remainder instruction,
12933 // The architecture manual suggests the following transformation to 
12934 // generate code for such operator:
12935 //
12936 // a % b = a - (a / b) * b;
12937 //
12938 // This method will produce the above expression in 'a' and 'b' are
12939 // leaf nodes, otherwise, if any of them is not a leaf it will spill
12940 // its value into a temporary variable, an example:
12941 // (x * 2 - 1) % (y + 1) ->  t1 - (t2 * ( comma(t1 = x * 2 - 1, t1) / comma(t2 = y + 1, t2) ) )
12942 //
12943 GenTree* Compiler::fgMorphModToSubMulDiv(GenTreeOp* tree)
12944 {
12945 #ifndef _TARGET_ARM64_
12946     assert(!"This should only be called for ARM64");
12947 #endif
12948
12949     if (tree->OperGet() == GT_MOD)
12950     {
12951         tree->SetOper(GT_DIV);
12952     }
12953     else  if (tree->OperGet() == GT_UMOD)
12954     {
12955         tree->SetOper(GT_UDIV);
12956     }
12957     else
12958     {
12959         noway_assert(!"Illegal gtOper in fgMorphModToSubMulDiv");
12960     }
12961
12962     var_types type = tree->gtType;
12963     GenTree* denominator = tree->gtOp2;
12964     GenTree* numerator = tree->gtOp1;
12965
12966     if (!numerator->OperIsLeaf())
12967     {
12968         numerator = fgMakeMultiUse(&tree->gtOp1);
12969     }
12970
12971     if (!denominator->OperIsLeaf())
12972     {
12973         denominator = fgMakeMultiUse(&tree->gtOp2);
12974     }
12975
12976     GenTree* mul = gtNewOperNode(GT_MUL, type, tree, gtCloneExpr(denominator));
12977     GenTree* sub = gtNewOperNode(GT_SUB, type, gtCloneExpr(numerator), mul);
12978
12979 #ifdef DEBUG
12980     sub->gtFlags |= GTF_MORPHED;
12981 #endif
12982
12983     return sub;
12984 }
12985
12986 // Turn a division by a constant into a multiplication by constant + some adjustments
12987 // see comments on GetSignedMagicNumberForDivide for source of this algorithm.
12988 // returns: the transformed tree
12989
12990 GenTree* Compiler::fgMorphDivByConst(GenTreeOp* tree)
12991 {
12992     assert(fgShouldUseMagicNumberDivide(tree));
12993
12994     JITDUMP("doing magic number divide optimization\n");
12995
12996     int64_t   denominator = tree->gtOp2->gtIntConCommon.IconValue();
12997     int64_t   magic;
12998     int       shift;
12999     var_types type = tree->gtType;
13000
13001     if (tree->gtType == TYP_INT)
13002     {
13003         magic = GetSignedMagicNumberForDivide<int32_t>((int32_t) denominator, &shift);
13004     }
13005     else
13006     {
13007         magic = GetSignedMagicNumberForDivide<int64_t>((int64_t) denominator, &shift);
13008     }
13009
13010     GenTree* numerator = nullptr;
13011
13012     // If signs of the denominator and magic number don't match,
13013     // we will need to use the numerator again.
13014     if (signum(denominator) != signum(magic))
13015     {
13016         numerator = fgMakeMultiUse(&tree->gtOp1);
13017         tree->gtFlags |= GTF_ASG;
13018     }
13019
13020     if (type == TYP_LONG)
13021         tree->gtOp2->gtIntConCommon.SetLngValue(magic);
13022     else
13023         tree->gtOp2->gtIntConCommon.SetIconValue((ssize_t)magic);
13024
13025     tree->SetOper(GT_MULHI);
13026             
13027     GenTree* t = tree;
13028     GenTree* mulresult = tree;
13029
13030     JITDUMP("Multiply Result:\n");
13031     DISPTREE(mulresult);
13032             
13033     GenTree *adjusted = mulresult;
13034
13035     if (denominator > 0 && magic < 0) 
13036     {
13037         // add the numerator back in
13038         adjusted = gtNewOperNode(GT_ADD, type, mulresult, numerator);
13039     } 
13040     else if (denominator < 0 && magic > 0) 
13041     {
13042         // subtract the numerator off
13043         adjusted = gtNewOperNode(GT_SUB, type, mulresult, numerator);
13044     }
13045     else
13046     {
13047         adjusted = mulresult;
13048     }
13049
13050     GenTree* result1 = adjusted;
13051     if (shift != 0)
13052     {
13053         result1 = gtNewOperNode(GT_RSH, type, adjusted, gtNewIconNode(shift, TYP_INT));
13054     }
13055
13056     GenTree* secondClone = fgMakeMultiUse(&result1);
13057
13058     GenTree* result2 = gtNewOperNode(GT_RSZ, type, secondClone, gtNewIconNode(genTypeSize(type) * 8 - 1, type));
13059             
13060
13061     GenTree* result = gtNewOperNode(GT_ADD, type, result1, result2);
13062     JITDUMP("Final Magic Number divide:\n");
13063     DISPTREE(result);
13064
13065 #ifdef DEBUG
13066     result->gtFlags |= GTF_MORPHED;
13067 #endif
13068
13069     return result;
13070 }
13071
13072 //------------------------------------------------------------------------------
13073 // fgOperIsBitwiseRotationRoot : Check if the operation can be a root of a bitwise rotation tree.
13074 //
13075 //
13076 // Arguments:
13077 //    oper  - Operation to check
13078 //
13079 // Return Value:
13080 //    True if the operation can be a root of a bitwise rotation tree; false otherwise.
13081
13082 bool Compiler::fgOperIsBitwiseRotationRoot(genTreeOps oper)
13083 {
13084     return (oper == GT_OR) || (oper == GT_XOR);
13085 }
13086
13087 //------------------------------------------------------------------------------
13088 // fgRecognizeAndMorphBitwiseRotation : Check if the tree represents a left or right rotation. If so, return
13089 //                                      an equivalent GT_ROL or GT_ROR tree; otherwise, return the original tree.
13090 //
13091 // Arguments:
13092 //    tree  - tree to check for a rotation pattern
13093 //
13094 // Return Value:
13095 //    An equivalent GT_ROL or GT_ROR tree if a pattern is found; original tree otherwise.
13096 //
13097 // Assumption:
13098 //    The input is a GT_OR or a GT_XOR tree.
13099
13100 GenTreePtr Compiler::fgRecognizeAndMorphBitwiseRotation(GenTreePtr tree)
13101 {
13102 #ifndef LEGACY_BACKEND
13103     //
13104     // Check for a rotation pattern, e.g.,
13105     //
13106     //                         OR                      ROL
13107     //                      /      \                   / \
13108         //                    LSH      RSZ      ->        x   y
13109     //                    / \      / \
13110         //                   x  AND   x  AND
13111     //                      / \      / \
13112         //                     y  31   ADD  31
13113     //                             / \
13114         //                            NEG 32
13115     //                             |
13116     //                             y
13117     // The patterns recognized:
13118     // (x << (y & M)) op (x >>> ((-y + N) & M))
13119     // (x >>> ((-y + N) & M)) op (x << (y & M))
13120     //
13121     // (x << y) op (x >>> (-y + N))
13122     // (x >> > (-y + N)) op (x << y)
13123     //
13124     // (x >>> (y & M)) op (x << ((-y + N) & M))
13125     // (x << ((-y + N) & M)) op (x >>> (y & M))
13126     //
13127     // (x >>> y) op (x << (-y + N))
13128     // (x << (-y + N)) op (x >>> y)
13129     //
13130     // (x << c1) op (x >>> c2)
13131     // (x >>> c1) op (x << c2)
13132     //
13133     // where 
13134     // c1 and c2 are const
13135     // c1 + c2 == bitsize(x)
13136     // N == bitsize(x)
13137     // M is const
13138     // M & (N - 1) == N - 1
13139     // op is either | or ^
13140
13141     if (((tree->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) != 0) ||
13142         ((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0))
13143     {
13144         // We can't do anything if the tree has assignments, calls, or volatile
13145         // reads. Note that we allow GTF_EXCEPT side effect since any exceptions
13146         // thrown by the original tree will be thrown by the transformed tree as well.
13147         return tree;
13148     }
13149
13150     genTreeOps      oper = tree->OperGet();
13151     assert(fgOperIsBitwiseRotationRoot(oper));
13152
13153     // Check if we have an LSH on one side of the OR and an RSZ on the other side.
13154     GenTreePtr op1 = tree->gtGetOp1();
13155     GenTreePtr op2 = tree->gtGetOp2();
13156     GenTreePtr leftShiftTree = nullptr;
13157     GenTreePtr rightShiftTree = nullptr;
13158     if ((op1->OperGet() == GT_LSH) && (op2->OperGet() == GT_RSZ))
13159     {
13160         leftShiftTree = op1;
13161         rightShiftTree = op2;
13162     }
13163     else if ((op1->OperGet() == GT_RSZ) && (op2->OperGet() == GT_LSH))
13164     {
13165         leftShiftTree = op2;
13166         rightShiftTree = op1;
13167     }
13168     else
13169     {
13170         return tree;
13171     }
13172
13173     // Check if the trees representing the value to shift are identical.
13174     // We already checked that there are no side effects above.
13175     if (GenTree::Compare(leftShiftTree->gtGetOp1(), rightShiftTree->gtGetOp1()))
13176     {
13177         GenTreePtr rotatedValue = leftShiftTree->gtGetOp1();
13178         var_types rotatedValueActualType = genActualType(rotatedValue->gtType);
13179         ssize_t rotatedValueBitSize = genTypeSize(rotatedValueActualType) * 8;
13180         noway_assert((rotatedValueBitSize == 32) || (rotatedValueBitSize == 64));
13181         GenTreePtr leftShiftIndex = leftShiftTree->gtGetOp2();
13182         GenTreePtr rightShiftIndex = rightShiftTree->gtGetOp2();
13183
13184         // The shift index may be masked. At least (rotatedValueBitSize - 1) lower bits
13185         // shouldn't be masked for the transformation to be valid. If additional
13186         // higher bits are not masked, the transformation is still valid since the result
13187         // of MSIL shift instructions is unspecified if the shift amount is greater or equal
13188         // than the width of the value being shifted.
13189         ssize_t minimalMask = rotatedValueBitSize - 1;
13190         ssize_t leftShiftMask = -1;
13191         ssize_t rightShiftMask = -1;
13192
13193         if ((leftShiftIndex->OperGet() == GT_AND))
13194         {
13195             if (leftShiftIndex->gtGetOp2()->IsCnsIntOrI())
13196             {
13197                 leftShiftMask = leftShiftIndex->gtGetOp2()->gtIntCon.gtIconVal;
13198                 leftShiftIndex = leftShiftIndex->gtGetOp1();
13199             }
13200             else
13201             {
13202                 return tree;
13203             }
13204         }
13205
13206         if ((rightShiftIndex->OperGet() == GT_AND))
13207         {
13208             if (rightShiftIndex->gtGetOp2()->IsCnsIntOrI())
13209             {
13210                 rightShiftMask = rightShiftIndex->gtGetOp2()->gtIntCon.gtIconVal;
13211                 rightShiftIndex = rightShiftIndex->gtGetOp1();
13212             }
13213             else
13214             {
13215                 return tree;
13216             }
13217         }
13218
13219         if (((minimalMask & leftShiftMask) != minimalMask) ||
13220             ((minimalMask & rightShiftMask) != minimalMask))
13221         {
13222             // The shift index is overmasked, e.g., we have
13223             // something like (x << y & 15) or
13224             // (x >> (32 - y) & 15 with 32 bit x.
13225             // The transformation is not valid.
13226             return tree;
13227         }
13228
13229         GenTreePtr shiftIndexWithAdd = nullptr;
13230         GenTreePtr shiftIndexWithoutAdd = nullptr;
13231         genTreeOps rotateOp = GT_NONE;
13232         GenTreePtr rotateIndex = nullptr;
13233
13234         if (leftShiftIndex->OperGet() == GT_ADD)
13235         {
13236             shiftIndexWithAdd = leftShiftIndex;
13237             shiftIndexWithoutAdd = rightShiftIndex;
13238             rotateOp = GT_ROR;
13239         }
13240         else if (rightShiftIndex->OperGet() == GT_ADD)
13241         {
13242             shiftIndexWithAdd = rightShiftIndex;
13243             shiftIndexWithoutAdd = leftShiftIndex;
13244             rotateOp = GT_ROL;
13245         }
13246
13247         if (shiftIndexWithAdd != nullptr)
13248         {
13249             if (shiftIndexWithAdd->gtGetOp2()->IsCnsIntOrI())
13250             {
13251                 if (shiftIndexWithAdd->gtGetOp2()->gtIntCon.gtIconVal == rotatedValueBitSize)
13252                 {
13253                     if (shiftIndexWithAdd->gtGetOp1()->OperGet() == GT_NEG)
13254                     {
13255                         if (GenTree::Compare(shiftIndexWithAdd->gtGetOp1()->gtGetOp1(), shiftIndexWithoutAdd))
13256                         {
13257                             // We found one of these patterns:
13258                             // (x << (y & M)) | (x >>> ((-y + N) & M))
13259                             // (x << y) | (x >>> (-y + N))
13260                             // (x >>> (y & M)) | (x << ((-y + N) & M))
13261                             // (x >>> y) | (x << (-y + N))
13262                             // where N == bitsize(x), M is const, and
13263                             // M & (N - 1) == N - 1
13264
13265 #ifndef _TARGET_64BIT_
13266                             if (!shiftIndexWithoutAdd->IsCnsIntOrI() && (rotatedValueBitSize == 64))
13267                             {
13268                                 // TODO: we need to handle variable-sized long shifts specially on x86.
13269                                 // GT_LSH, GT_RSH, and GT_RSZ have helpers for this case. We may need
13270                                 // to add helpers for GT_ROL and GT_ROR.
13271                                 NYI("Rotation of a long value by variable amount");
13272                             }
13273 #endif
13274
13275                             rotateIndex = shiftIndexWithoutAdd;
13276                         }
13277                     }
13278                 }
13279             }
13280         }
13281         else if ((leftShiftIndex->IsCnsIntOrI() &&
13282                   rightShiftIndex->IsCnsIntOrI()))
13283         {
13284             if (leftShiftIndex->gtIntCon.gtIconVal +
13285                 rightShiftIndex->gtIntCon.gtIconVal == rotatedValueBitSize)
13286             {
13287                 // We found this pattern:
13288                 // (x << c1) | (x >>> c2)
13289                 // where c1 and c2 are const and c1 + c2 == bitsize(x)
13290                 rotateOp = GT_ROL;
13291                 rotateIndex = leftShiftIndex;
13292             }
13293         }
13294
13295         if (rotateIndex != nullptr)
13296         {
13297             noway_assert(GenTree::OperIsRotate(rotateOp));
13298
13299             unsigned inputTreeEffects = tree->gtFlags & GTF_ALL_EFFECT;
13300
13301             // We can use the same tree only during global morph; reusing the tree in a later morph
13302             // may invalidate value numbers.
13303             if (fgGlobalMorph)
13304             {
13305                 tree->gtOp.gtOp1 = rotatedValue;
13306                 tree->gtOp.gtOp2 = rotateIndex;
13307                 tree->ChangeOper(rotateOp);
13308                 noway_assert(inputTreeEffects == ((rotatedValue->gtFlags | rotateIndex->gtFlags) & GTF_ALL_EFFECT));
13309             }
13310             else
13311             {
13312                 tree = gtNewOperNode(rotateOp, rotatedValueActualType, rotatedValue, rotateIndex);
13313                 noway_assert(inputTreeEffects == (tree->gtFlags & GTF_ALL_EFFECT));
13314             }
13315
13316             return tree;
13317         }
13318     }
13319 #endif //LEGACY_BACKEND
13320     return tree;
13321 }
13322
13323 #if !CPU_HAS_FP_SUPPORT
13324 GenTreePtr Compiler::fgMorphToEmulatedFP(GenTreePtr tree)
13325 {
13326
13327     genTreeOps      oper    = tree->OperGet();
13328     var_types       typ     = tree->TypeGet();
13329     GenTreePtr      op1     = tree->gtOp.gtOp1;
13330     GenTreePtr      op2     = tree->gtGetOp2();
13331
13332     /*
13333         We have to use helper calls for all FP operations:
13334
13335             FP operators that operate on FP values
13336             casts to and from FP
13337             comparisons of FP values
13338      */
13339
13340     if  (varTypeIsFloating(typ) || (op1 && varTypeIsFloating(op1->TypeGet())))
13341     {
13342         int         helper;
13343         GenTreePtr  args;
13344         size_t      argc = genTypeStSz(typ);
13345
13346         /* Not all FP operations need helper calls */
13347
13348         switch (oper)
13349         {
13350         case GT_ASG:
13351         case GT_IND:
13352         case GT_LIST:
13353         case GT_ADDR:
13354         case GT_COMMA:
13355             return tree;
13356         }
13357
13358 #ifdef DEBUG
13359
13360         /* If the result isn't FP, it better be a compare or cast */
13361
13362         if  (!(varTypeIsFloating(typ) ||
13363                tree->OperIsCompare()  || oper == GT_CAST))
13364             gtDispTree(tree);
13365
13366         noway_assert(varTypeIsFloating(typ) ||
13367                tree->OperIsCompare()  || oper == GT_CAST);
13368 #endif
13369
13370         /* Keep track of how many arguments we're passing */
13371
13372         fgPtrArgCntCur += argc;
13373
13374         /* Is this a binary operator? */
13375
13376         if  (op2)
13377         {
13378             /* Add the second operand to the argument count */
13379
13380             fgPtrArgCntCur += argc; argc *= 2;
13381
13382             /* What kind of an operator do we have? */
13383
13384             switch (oper)
13385             {
13386             case GT_ADD: helper = CPX_R4_ADD; break;
13387             case GT_SUB: helper = CPX_R4_SUB; break;
13388             case GT_MUL: helper = CPX_R4_MUL; break;
13389             case GT_DIV: helper = CPX_R4_DIV; break;
13390 //              case GT_MOD: helper = CPX_R4_REM; break;
13391
13392             case GT_EQ : helper = CPX_R4_EQ ; break;
13393             case GT_NE : helper = CPX_R4_NE ; break;
13394             case GT_LT : helper = CPX_R4_LT ; break;
13395             case GT_LE : helper = CPX_R4_LE ; break;
13396             case GT_GE : helper = CPX_R4_GE ; break;
13397             case GT_GT : helper = CPX_R4_GT ; break;
13398
13399             default:
13400 #ifdef DEBUG
13401                 gtDispTree(tree);
13402 #endif
13403                 noway_assert(!"unexpected FP binary op");
13404                 break;
13405             }
13406
13407             args = gtNewArgList(tree->gtOp.gtOp2, tree->gtOp.gtOp1);
13408         }
13409         else
13410         {
13411             switch (oper)
13412             {
13413             case GT_RETURN:
13414                 return tree;
13415
13416             case GT_CAST:
13417                 noway_assert(!"FP cast");
13418
13419             case GT_NEG: helper = CPX_R4_NEG; break;
13420
13421             default:
13422 #ifdef DEBUG
13423                 gtDispTree(tree);
13424 #endif
13425                 noway_assert(!"unexpected FP unary op");
13426                 break;
13427             }
13428
13429             args = gtNewArgList(tree->gtOp.gtOp1);
13430         }
13431
13432         /* If we have double result/operands, modify the helper */
13433
13434         if  (typ == TYP_DOUBLE)
13435         {
13436             noway_assert(CPX_R4_NEG+1 == CPX_R8_NEG);
13437             noway_assert(CPX_R4_ADD+1 == CPX_R8_ADD);
13438             noway_assert(CPX_R4_SUB+1 == CPX_R8_SUB);
13439             noway_assert(CPX_R4_MUL+1 == CPX_R8_MUL);
13440             noway_assert(CPX_R4_DIV+1 == CPX_R8_DIV);
13441
13442             helper++;
13443         }
13444         else
13445         {
13446             noway_assert(tree->OperIsCompare());
13447
13448             noway_assert(CPX_R4_EQ+1 == CPX_R8_EQ);
13449             noway_assert(CPX_R4_NE+1 == CPX_R8_NE);
13450             noway_assert(CPX_R4_LT+1 == CPX_R8_LT);
13451             noway_assert(CPX_R4_LE+1 == CPX_R8_LE);
13452             noway_assert(CPX_R4_GE+1 == CPX_R8_GE);
13453             noway_assert(CPX_R4_GT+1 == CPX_R8_GT);
13454         }
13455
13456         tree = fgMorphIntoHelperCall(tree, helper, args);
13457
13458         if  (fgPtrArgCntMax < fgPtrArgCntCur)
13459             fgPtrArgCntMax = fgPtrArgCntCur;
13460
13461         fgPtrArgCntCur -= argc;
13462         return tree;
13463
13464     case GT_RETURN:
13465
13466         if  (op1)
13467         {
13468
13469             if  (compCurBB == genReturnBB)
13470             {
13471                 /* This is the 'exitCrit' call at the exit label */
13472
13473                 noway_assert(op1->gtType == TYP_VOID);
13474                 noway_assert(op2 == 0);
13475
13476                 tree->gtOp.gtOp1 = op1 = fgMorphTree(op1);
13477
13478                 return tree;
13479             }
13480
13481             /* This is a (real) return value -- check its type */
13482
13483 #ifdef DEBUG
13484             if (genActualType(op1->TypeGet()) != genActualType(info.compRetType))
13485             {
13486                 bool allowMismatch = false;
13487
13488                 // Allow TYP_BYREF to be returned as TYP_I_IMPL and vice versa
13489                 if ((info.compRetType == TYP_BYREF &&
13490                      genActualType(op1->TypeGet()) == TYP_I_IMPL) ||
13491                     (op1->TypeGet() == TYP_BYREF &&
13492                      genActualType(info.compRetType) == TYP_I_IMPL))
13493                     allowMismatch = true;
13494
13495                 if (varTypeIsFloating(info.compRetType) && varTypeIsFloating(op1->TypeGet()))
13496                     allowMismatch = true;
13497
13498                 if (!allowMismatch)
13499                     NO_WAY("Return type mismatch");
13500             }
13501 #endif
13502         }
13503         break;
13504
13505     }
13506     return tree;
13507 }
13508 #endif
13509
13510 /*****************************************************************************
13511  *
13512  *  Transform the given tree for code generation and return an equivalent tree.
13513  */
13514
13515
13516 GenTreePtr          Compiler::fgMorphTree(GenTreePtr tree, MorphAddrContext* mac)
13517 {
13518     noway_assert(tree);
13519     noway_assert(tree->gtOper != GT_STMT);
13520
13521 #ifdef DEBUG
13522     if (verbose)
13523     {
13524         if ((unsigned)JitConfig.JitBreakMorphTree() == tree->gtTreeID)
13525         {
13526             noway_assert(!"JitBreakMorphTree hit");
13527         }
13528     }
13529 #endif
13530
13531 #ifdef DEBUG
13532     int thisMorphNum = 0;
13533     if (verbose && treesBeforeAfterMorph)
13534     {
13535         thisMorphNum = morphNum++;
13536         printf("\nfgMorphTree (before %d):\n", thisMorphNum);
13537         gtDispTree(tree);
13538     }
13539 #endif
13540
13541     /*-------------------------------------------------------------------------
13542      * fgMorphTree() can potentially replace a tree with another, and the
13543      * caller has to store the return value correctly.
13544      * Turn this on to always make copy of "tree" here to shake out
13545      * hidden/unupdated references.
13546      */
13547
13548 #ifdef DEBUG
13549
13550     if  (compStressCompile(STRESS_GENERIC_CHECK, 0))
13551     {
13552         GenTreePtr      copy;
13553
13554 #ifdef SMALL_TREE_NODES
13555         if  (GenTree::s_gtNodeSizes[tree->gtOper] == TREE_NODE_SZ_SMALL)
13556         {
13557             copy = gtNewLargeOperNode(GT_ADD, TYP_INT);
13558         }
13559         else
13560 #endif
13561         {
13562             copy = new (this, GT_CALL) GenTreeCall(TYP_INT);
13563         }
13564
13565         copy->CopyFrom(tree, this);
13566
13567 #if defined (LATE_DISASM)
13568         // GT_CNS_INT is considered small, so CopyFrom() won't copy all fields
13569         if  ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
13570         {
13571             copy->gtIntCon.gtIconHdl.gtIconHdl1 = tree->gtIntCon.gtIconHdl.gtIconHdl1;
13572             copy->gtIntCon.gtIconHdl.gtIconHdl2 = tree->gtIntCon.gtIconHdl.gtIconHdl2;
13573         }
13574 #endif
13575
13576         DEBUG_DESTROY_NODE(tree);
13577         tree = copy;
13578     }
13579 #endif // DEBUG
13580
13581     if (fgGlobalMorph)
13582     {
13583         /* Ensure that we haven't morphed this node already */
13584         assert(((tree->gtFlags & GTF_MORPHED) == 0) && "ERROR: Already morphed this node!");
13585
13586 #if LOCAL_ASSERTION_PROP
13587         /* Before morphing the tree, we try to propagate any active assertions */
13588         if (optLocalAssertionProp)
13589         {
13590             /* Do we have any active assertions? */
13591
13592             if (optAssertionCount > 0)
13593             {
13594                 GenTreePtr newTree = tree;
13595                 while (newTree != NULL)
13596                 {
13597                     tree = newTree;
13598                     /* newTree is non-Null if we propagated an assertion */
13599                     newTree = optAssertionProp(apFull, tree, NULL);
13600                 }
13601                 noway_assert(tree != NULL);
13602             }
13603         }
13604         PREFAST_ASSUME(tree != NULL);
13605 #endif
13606     }
13607
13608     /* Save the original un-morphed tree for fgMorphTreeDone */
13609
13610     GenTreePtr oldTree = tree;
13611
13612     /* Figure out what kind of a node we have */
13613
13614     unsigned kind = tree->OperKind();
13615
13616     /* Is this a constant node? */
13617
13618     if  (kind & GTK_CONST)
13619     {
13620         tree = fgMorphConst(tree);
13621         goto DONE;
13622     }
13623
13624     /* Is this a leaf node? */
13625
13626     if  (kind & GTK_LEAF)
13627     {
13628         tree = fgMorphLeaf(tree);
13629         goto DONE;
13630     }
13631
13632     /* Is it a 'simple' unary/binary operator? */
13633
13634     if  (kind & GTK_SMPOP)
13635     {
13636         tree = fgMorphSmpOp(tree, mac);
13637         goto DONE;
13638     }
13639
13640     /* See what kind of a special operator we have here */
13641
13642     switch  (tree->OperGet())
13643     {
13644     case GT_FIELD:
13645         tree = fgMorphField(tree, mac);
13646         break;
13647
13648     case GT_CALL:
13649         tree = fgMorphCall(tree->AsCall());
13650         break;
13651
13652     case GT_ARR_BOUNDS_CHECK:
13653 #ifdef FEATURE_SIMD
13654     case GT_SIMD_CHK:
13655 #endif // FEATURE_SIMD
13656         {
13657             fgSetRngChkTarget(tree);
13658
13659             GenTreeBoundsChk* bndsChk = tree->AsBoundsChk();
13660             bndsChk->gtArrLen = fgMorphTree(bndsChk->gtArrLen);
13661             bndsChk->gtIndex = fgMorphTree(bndsChk->gtIndex);
13662             // If the index is a comma(throw, x), just return that.
13663             if (!optValnumCSE_phase && fgIsCommaThrow(bndsChk->gtIndex))
13664             {
13665                 tree = bndsChk->gtIndex;
13666             }
13667
13668             // Propagate effects flags upwards
13669             bndsChk->gtFlags |= (bndsChk->gtArrLen->gtFlags & GTF_ALL_EFFECT);
13670             bndsChk->gtFlags |= (bndsChk->gtIndex->gtFlags  & GTF_ALL_EFFECT);
13671
13672             // Otherwise, we don't change the tree.
13673         }
13674         break;
13675
13676     case GT_ARR_ELEM:
13677         tree->gtArrElem.gtArrObj        = fgMorphTree(tree->gtArrElem.gtArrObj);
13678         tree->gtFlags |= tree->gtArrElem.gtArrObj->gtFlags & GTF_ALL_EFFECT;
13679
13680         unsigned dim;
13681         for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
13682         {
13683             tree->gtArrElem.gtArrInds[dim] = fgMorphTree(tree->gtArrElem.gtArrInds[dim]);
13684             tree->gtFlags |= tree->gtArrElem.gtArrInds[dim]->gtFlags & GTF_ALL_EFFECT;
13685         }
13686         if (fgGlobalMorph)
13687             fgSetRngChkTarget(tree, false);
13688         break;
13689
13690     case GT_ARR_OFFSET:
13691         tree->gtArrOffs.gtOffset   = fgMorphTree(tree->gtArrOffs.gtOffset);
13692         tree->gtFlags |= tree->gtArrOffs.gtOffset->gtFlags & GTF_ALL_EFFECT;
13693         tree->gtArrOffs.gtIndex        = fgMorphTree(tree->gtArrOffs.gtIndex);
13694         tree->gtFlags |= tree->gtArrOffs.gtIndex->gtFlags & GTF_ALL_EFFECT;
13695         tree->gtArrOffs.gtArrObj       = fgMorphTree(tree->gtArrOffs.gtArrObj);
13696         tree->gtFlags |= tree->gtArrOffs.gtArrObj->gtFlags & GTF_ALL_EFFECT;
13697         if (fgGlobalMorph)
13698             fgSetRngChkTarget(tree, false);
13699         break;
13700
13701     case GT_CMPXCHG:
13702         tree->gtCmpXchg.gtOpLocation  = fgMorphTree(tree->gtCmpXchg.gtOpLocation);
13703         tree->gtCmpXchg.gtOpValue     = fgMorphTree(tree->gtCmpXchg.gtOpValue);
13704         tree->gtCmpXchg.gtOpComparand = fgMorphTree(tree->gtCmpXchg.gtOpComparand);
13705         break;
13706
13707     default:
13708 #ifdef DEBUG
13709         gtDispTree(tree);
13710 #endif
13711         noway_assert(!"unexpected operator");
13712     }
13713 DONE:
13714
13715     fgMorphTreeDone(tree, oldTree DEBUGARG(thisMorphNum));
13716
13717     return tree;
13718 }
13719
13720
13721 #if LOCAL_ASSERTION_PROP
13722 /*****************************************************************************
13723  *
13724  *  Kill all dependent assertions with regard to lclNum.
13725  *
13726  */
13727
13728 void                Compiler::fgKillDependentAssertions(unsigned lclNum
13729                                                         DEBUGARG(GenTreePtr tree))
13730 {
13731     LclVarDsc * varDsc = &lvaTable[lclNum];
13732
13733     if (varDsc->lvPromoted)
13734     {
13735         noway_assert(varTypeIsStruct(varDsc));
13736
13737         // Kill the field locals.
13738         for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
13739         {
13740             fgKillDependentAssertions(i DEBUGARG(tree));
13741         }
13742
13743         // Fall through to kill the struct local itself.
13744     }
13745
13746     /* All dependent assertions are killed here */
13747
13748     ASSERT_TP killed = BitVecOps::MakeCopy(apTraits, GetAssertionDep(lclNum));
13749
13750     if (killed)
13751     {
13752         AssertionIndex   index = optAssertionCount;
13753         while (killed && (index > 0))
13754         {
13755             if  (BitVecOps::IsMember(apTraits, killed, index - 1))
13756             {
13757 #ifdef DEBUG
13758                 AssertionDsc* curAssertion = optGetAssertion(index);
13759                 noway_assert((curAssertion->op1.lcl.lclNum  == lclNum)     ||
13760                              ((curAssertion->op2.kind   == O2K_LCLVAR_COPY) &&
13761                               (curAssertion->op2.lcl.lclNum == lclNum)));
13762                 if (verbose)
13763                 {
13764                     printf("\nThe assignment ");
13765                     printTreeID(tree);
13766                     printf(" using V%02u removes: ", curAssertion->op1.lcl.lclNum);
13767                     optPrintAssertion(curAssertion);
13768                 }
13769 #endif
13770                 // Remove this bit from the killed mask
13771                 BitVecOps::RemoveElemD(apTraits, killed, index - 1);
13772
13773                 optAssertionRemove(index);
13774             }
13775
13776             index--;
13777         }
13778
13779         // killed mask should now be zero
13780         noway_assert(BitVecOps::IsEmpty(apTraits, killed));
13781     }
13782 }
13783 #endif // LOCAL_ASSERTION_PROP
13784
13785
13786 /*****************************************************************************
13787  *
13788  *  This function is called to complete the morphing of a tree node
13789  *  It should only be called once for each node.
13790  *  If DEBUG is defined the flag GTF_MORPHED is checked and updated,
13791  *  to enforce the invariant that each node is only morphed once.
13792  *  If LOCAL_ASSERTION_PROP is enabled the result tree may be replaced
13793  *  by an equivalent tree.
13794  *
13795  */
13796
13797 void                Compiler::fgMorphTreeDone(GenTreePtr tree,
13798                                               GenTreePtr oldTree /* == NULL */
13799                                               DEBUGARG(int morphNum))
13800 {
13801 #ifdef DEBUG
13802     if (verbose && treesBeforeAfterMorph)
13803     {
13804         printf("\nfgMorphTree (after %d):\n", morphNum);
13805         gtDispTree(tree);
13806         printf("");         // in our logic this causes a flush
13807     }
13808 #endif
13809
13810     if (!fgGlobalMorph)
13811         return;
13812
13813     if ((oldTree != NULL) && (oldTree != tree))
13814     {
13815         /* Ensure that we have morphed this node */
13816         assert((tree->gtFlags & GTF_MORPHED) && "ERROR: Did not morph this node!");
13817
13818 #ifdef DEBUG
13819         TransferTestDataToNode(oldTree, tree);
13820 #endif
13821     }
13822     else
13823     {
13824         // Ensure that we haven't morphed this node already 
13825         assert(((tree->gtFlags & GTF_MORPHED) == 0) && "ERROR: Already morphed this node!");
13826     }
13827
13828     if (tree->OperKind() & GTK_CONST)
13829         goto DONE;
13830
13831 #if LOCAL_ASSERTION_PROP
13832
13833     if (!optLocalAssertionProp)
13834         goto DONE;
13835
13836     /* Do we have any active assertions? */
13837
13838     if (optAssertionCount > 0)
13839     {
13840         /* Is this an assignment to a local variable */
13841
13842         if ((tree->OperKind() & GTK_ASGOP) &&
13843             (tree->gtOp.gtOp1->gtOper == GT_LCL_VAR || tree->gtOp.gtOp1->gtOper == GT_LCL_FLD))
13844         {
13845             unsigned op1LclNum = tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum; noway_assert(op1LclNum  < lvaCount);
13846             fgKillDependentAssertions(op1LclNum DEBUGARG(tree));
13847         }
13848     }
13849
13850     /* If this tree makes a new assertion - make it available */
13851     optAssertionGen(tree);
13852
13853 #endif // LOCAL_ASSERTION_PROP
13854
13855 DONE:;
13856
13857 #ifdef DEBUG
13858     /* Mark this node as being morphed */
13859     tree->gtFlags |= GTF_MORPHED;
13860 #endif
13861 }
13862
13863
13864 /*****************************************************************************
13865  *
13866  *  Check and fold blocks of type BBJ_COND and BBJ_SWITCH on constants
13867  *  Returns true if we modified the flow graph
13868  */
13869
13870 bool                Compiler::fgFoldConditional(BasicBlock * block)
13871 {
13872     bool result = false;
13873
13874     // We don't want to make any code unreachable
13875     if (opts.compDbgCode || opts.MinOpts())
13876       return false;
13877
13878     if (block->bbJumpKind == BBJ_COND)
13879     {
13880         noway_assert(block->bbTreeList && block->bbTreeList->gtPrev);
13881
13882         GenTreePtr stmt = block->bbTreeList->gtPrev;
13883
13884         noway_assert(stmt->gtNext == NULL);
13885
13886         if (stmt->gtStmt.gtStmtExpr->gtOper == GT_CALL)
13887         {
13888             noway_assert(fgRemoveRestOfBlock);
13889
13890             /* Unconditional throw - transform the basic block into a BBJ_THROW */
13891             fgConvertBBToThrowBB(block);
13892
13893             /* Remove 'block' from the predecessor list of 'block->bbNext' */
13894             fgRemoveRefPred(block->bbNext, block);
13895
13896             /* Remove 'block' from the predecessor list of 'block->bbJumpDest' */
13897             fgRemoveRefPred(block->bbJumpDest, block);
13898
13899 #ifdef DEBUG
13900             if  (verbose)
13901             {
13902                 printf("\nConditional folded at BB%02u\n", block->bbNum);
13903                 printf("BB%02u becomes a BBJ_THROW\n", block->bbNum);
13904             }
13905 #endif
13906             goto DONE_COND;
13907         }
13908
13909         noway_assert(stmt->gtStmt.gtStmtExpr->gtOper == GT_JTRUE);
13910
13911         /* Did we fold the conditional */
13912
13913         noway_assert(stmt->gtStmt.gtStmtExpr->gtOp.gtOp1);
13914         GenTreePtr  cond; cond = stmt->gtStmt.gtStmtExpr->gtOp.gtOp1;
13915
13916         if (cond->OperKind() & GTK_CONST)
13917         {
13918             /* Yupee - we folded the conditional!
13919              * Remove the conditional statement */
13920
13921             noway_assert(cond->gtOper == GT_CNS_INT);
13922             noway_assert((block->bbNext->countOfInEdges()     > 0) &&
13923                          (block->bbJumpDest->countOfInEdges() > 0));
13924
13925             /* remove the statement from bbTreelist - No need to update
13926              * the reference counts since there are no lcl vars */
13927             fgRemoveStmt(block, stmt);
13928
13929             // block is a BBJ_COND that we are folding the conditional for
13930             // bTaken is the path that will always be taken from block
13931             // bNotTaken is the path that will never be taken from block
13932             //
13933             BasicBlock * bTaken;
13934             BasicBlock * bNotTaken;
13935
13936             if (cond->gtIntCon.gtIconVal != 0)
13937             {
13938                 /* JTRUE 1 - transform the basic block into a BBJ_ALWAYS */
13939                 block->bbJumpKind = BBJ_ALWAYS;
13940                 bTaken    = block->bbJumpDest;
13941                 bNotTaken = block->bbNext;
13942             }
13943             else
13944             {
13945                 /* Unmark the loop if we are removing a backwards branch */
13946                 /* dest block must also be marked as a loop head and     */
13947                 /* We must be able to reach the backedge block           */
13948                 if ((block->bbJumpDest->isLoopHead())          &&
13949                     (block->bbJumpDest->bbNum <= block->bbNum) &&
13950                     fgReachable(block->bbJumpDest, block))
13951                 {
13952                     optUnmarkLoopBlocks(block->bbJumpDest, block);
13953                 }
13954
13955                 /* JTRUE 0 - transform the basic block into a BBJ_NONE   */
13956                 block->bbJumpKind = BBJ_NONE;
13957                 noway_assert(!(block->bbFlags & BBF_NEEDS_GCPOLL));
13958                 bTaken    = block->bbNext;
13959                 bNotTaken = block->bbJumpDest;
13960             }
13961
13962             if (fgHaveValidEdgeWeights)
13963             {
13964                 // We are removing an edge from block to bNotTaken
13965                 // and we have already computed the edge weights, so
13966                 // we will try to adjust some of the weights
13967                 //
13968                 flowList *    edgeTaken = fgGetPredForBlock(bTaken, block);
13969                 BasicBlock *  bUpdated  = NULL;  // non-NULL if we updated the weight of an internal block
13970
13971                 // We examine the taken edge (block -> bTaken)
13972                 // if block has valid profile weight and bTaken does not we try to adjust bTaken's weight
13973                 // else if bTaken has valid profile weight and block does not we try to adjust block's weight
13974                 // We can only adjust the block weights when (the edge block -> bTaken) is the only edge into bTaken
13975                 //
13976                 if (block->bbFlags & BBF_PROF_WEIGHT)
13977                 {
13978                     // The edge weights for (block -> bTaken) are 100% of block's weight
13979                     edgeTaken->flEdgeWeightMin = block->bbWeight;
13980                     edgeTaken->flEdgeWeightMax = block->bbWeight;
13981
13982                     if ((bTaken->bbFlags & BBF_PROF_WEIGHT) == 0)
13983                     {
13984                         if ((bTaken->countOfInEdges() == 1) || (bTaken->bbWeight < block->bbWeight))
13985                         {
13986                             // Update the weight of bTaken
13987                             bTaken->inheritWeight(block);
13988                             bUpdated = bTaken;
13989                         }
13990                     }
13991                 }
13992                 else if (bTaken->bbFlags & BBF_PROF_WEIGHT)
13993                 {
13994                     if (bTaken->countOfInEdges() == 1)
13995                     {
13996                         // There is only one in edge to bTaken
13997                         edgeTaken->flEdgeWeightMin = bTaken->bbWeight;
13998                         edgeTaken->flEdgeWeightMax = bTaken->bbWeight;
13999
14000                         // Update the weight of block
14001                         block->inheritWeight(bTaken);
14002                         bUpdated = block;
14003                     }
14004                 }
14005
14006                 if (bUpdated != NULL)
14007                 {
14008                     flowList * edge;
14009                     // Now fix the weights of the edges out of 'bUpdated'
14010                     switch (bUpdated->bbJumpKind) {
14011                     case BBJ_NONE:
14012                         edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated);
14013                         edge->flEdgeWeightMax = bUpdated->bbWeight;
14014                         break;
14015                     case BBJ_COND:
14016                         edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated);
14017                         edge->flEdgeWeightMax = bUpdated->bbWeight;
14018                         __fallthrough;
14019                     case BBJ_ALWAYS:
14020                         edge = fgGetPredForBlock(bUpdated->bbJumpDest, bUpdated);
14021                         edge->flEdgeWeightMax = bUpdated->bbWeight;
14022                         break;
14023                     default:
14024                         // We don't handle BBJ_SWITCH
14025                         break;
14026                     }
14027                 }
14028
14029             }
14030
14031             /* modify the flow graph */
14032
14033             /* Remove 'block' from the predecessor list of 'bNotTaken' */
14034             fgRemoveRefPred(bNotTaken, block);
14035
14036 #ifdef DEBUG
14037             if  (verbose)
14038             {
14039                 printf("\nConditional folded at BB%02u\n", block->bbNum);
14040                 printf("BB%02u becomes a %s", block->bbNum,
14041                        block->bbJumpKind == BBJ_ALWAYS ? "BBJ_ALWAYS" : "BBJ_NONE");
14042                 if  (block->bbJumpKind == BBJ_ALWAYS)
14043                     printf(" to BB%02u", block->bbJumpDest->bbNum);
14044                 printf("\n");
14045             }
14046 #endif
14047
14048             /* if the block was a loop condition we may have to modify
14049              * the loop table */
14050
14051             for (unsigned loopNum = 0; loopNum < optLoopCount; loopNum++)
14052             {
14053                 /* Some loops may have been already removed by
14054                  * loop unrolling or conditional folding */
14055
14056                 if (optLoopTable[loopNum].lpFlags & LPFLG_REMOVED)
14057                     continue;
14058
14059                 /* We are only interested in the loop bottom */
14060
14061                 if  (optLoopTable[loopNum].lpBottom == block)
14062                 {
14063                     if  (cond->gtIntCon.gtIconVal == 0)
14064                     {
14065                         /* This was a bogus loop (condition always false)
14066                          * Remove the loop from the table */
14067
14068                         optLoopTable[loopNum].lpFlags |= LPFLG_REMOVED;
14069 #ifdef DEBUG
14070                         if  (verbose)
14071                         {
14072                             printf("Removing loop L%02u (from BB%02u to BB%02u)\n\n",
14073                                    loopNum,
14074                                    optLoopTable[loopNum].lpFirst ->bbNum,
14075                                    optLoopTable[loopNum].lpBottom->bbNum);
14076                         }
14077 #endif
14078                     }
14079                 }
14080             }
14081 DONE_COND:
14082             result = true;
14083         }
14084     }
14085     else if  (block->bbJumpKind == BBJ_SWITCH)
14086     {
14087         noway_assert(block->bbTreeList && block->bbTreeList->gtPrev);
14088
14089         GenTreePtr stmt = block->bbTreeList->gtPrev;
14090
14091         noway_assert(stmt->gtNext == NULL);
14092
14093         if (stmt->gtStmt.gtStmtExpr->gtOper == GT_CALL)
14094         {
14095             noway_assert(fgRemoveRestOfBlock);
14096
14097             /* Unconditional throw - transform the basic block into a BBJ_THROW */
14098             fgConvertBBToThrowBB(block);
14099
14100             /* update the flow graph */
14101
14102             unsigned        jumpCnt   = block->bbJumpSwt->bbsCount;
14103             BasicBlock * *  jumpTab   = block->bbJumpSwt->bbsDstTab;
14104
14105             for (unsigned val = 0; val < jumpCnt; val++, jumpTab++)
14106             {
14107                 BasicBlock *  curJump = *jumpTab;
14108
14109                 /* Remove 'block' from the predecessor list of 'curJump' */
14110                 fgRemoveRefPred(curJump, block);
14111             }
14112
14113 #ifdef DEBUG
14114             if  (verbose)
14115             {
14116                 printf("\nConditional folded at BB%02u\n", block->bbNum);
14117                 printf("BB%02u becomes a BBJ_THROW\n", block->bbNum);
14118
14119             }
14120 #endif
14121             goto DONE_SWITCH;
14122         }
14123
14124         noway_assert(stmt->gtStmt.gtStmtExpr->gtOper == GT_SWITCH);
14125
14126         /* Did we fold the conditional */
14127
14128         noway_assert(stmt->gtStmt.gtStmtExpr->gtOp.gtOp1);
14129         GenTreePtr  cond; cond = stmt->gtStmt.gtStmtExpr->gtOp.gtOp1;
14130
14131         if (cond->OperKind() & GTK_CONST)
14132         {
14133             /* Yupee - we folded the conditional!
14134              * Remove the conditional statement */
14135
14136             noway_assert(cond->gtOper == GT_CNS_INT);
14137
14138             /* remove the statement from bbTreelist - No need to update
14139              * the reference counts since there are no lcl vars */
14140             fgRemoveStmt(block, stmt);
14141
14142             /* modify the flow graph */
14143
14144             /* Find the actual jump target */
14145             unsigned        switchVal; switchVal = (unsigned)cond->gtIntCon.gtIconVal;
14146             unsigned        jumpCnt;   jumpCnt   = block->bbJumpSwt->bbsCount;
14147             BasicBlock * *  jumpTab;   jumpTab   = block->bbJumpSwt->bbsDstTab;
14148             bool            foundVal;  foundVal  = false;
14149
14150             for (unsigned val = 0; val < jumpCnt; val++, jumpTab++)
14151             {
14152                 BasicBlock *  curJump = *jumpTab;
14153
14154                 assert (curJump->countOfInEdges() > 0);
14155
14156                 // If val matches switchVal or we are at the last entry and
14157                 // we never found the switch value then set the new jump dest
14158
14159                 if ( (val == switchVal) || (!foundVal && (val == jumpCnt-1)))
14160                 {
14161                     if (curJump != block->bbNext)
14162                     {
14163                         /* transform the basic block into a BBJ_ALWAYS */
14164                         block->bbJumpKind = BBJ_ALWAYS;
14165                         block->bbJumpDest = curJump;
14166
14167                         //if we are jumping backwards, make sure we have a GC Poll.
14168                         if (curJump->bbNum > block->bbNum)
14169                             block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14170                     }
14171                     else
14172                     {
14173                         /* transform the basic block into a BBJ_NONE */
14174                         block->bbJumpKind = BBJ_NONE;
14175                         block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14176                     }
14177                     foundVal = true;
14178                 }
14179                 else
14180                 {
14181                     /* Remove 'block' from the predecessor list of 'curJump' */
14182                     fgRemoveRefPred(curJump, block);
14183                 }
14184             }
14185 #ifdef DEBUG
14186             if  (verbose)
14187             {
14188                 printf("\nConditional folded at BB%02u\n", block->bbNum);
14189                 printf("BB%02u becomes a %s", block->bbNum,
14190                        block->bbJumpKind == BBJ_ALWAYS ? "BBJ_ALWAYS" : "BBJ_NONE");
14191                 if  (block->bbJumpKind == BBJ_ALWAYS)
14192                     printf(" to BB%02u", block->bbJumpDest->bbNum);
14193                 printf("\n");
14194             }
14195 #endif
14196 DONE_SWITCH:
14197             result = true;
14198         }
14199     }
14200     return result;
14201 }
14202
14203
14204 //*****************************************************************************
14205 //
14206 // Morphs a single statement in a block.
14207 // Can be called anytime, unlike fgMorphStmts() which should only be called once.
14208 //
14209 // Returns true  if 'stmt' was removed from the block.
14210 // Returns false if 'stmt' is still in the block (even if other statements were removed).
14211 //
14212
14213 bool                Compiler::fgMorphBlockStmt(BasicBlock * block,
14214                                                GenTreePtr   stmt
14215                                       DEBUGARG(const char * msg)  )
14216 {
14217     noway_assert(stmt->gtOper == GT_STMT);
14218
14219     compCurBB = block;
14220     compCurStmt = stmt;
14221
14222     GenTreePtr morph  = fgMorphTree(stmt->gtStmt.gtStmtExpr);
14223
14224     // Bug 1106830 - During the CSE phase we can't just remove 
14225     // morph->gtOp.gtOp2 as it could contain CSE expressions.
14226     // This leads to a noway_assert in OptCSE.cpp when
14227     // searching for the removed CSE ref. (using gtFindLink)
14228     //
14229     if (!optValnumCSE_phase)
14230     {
14231         /* Check for morph as a GT_COMMA with an unconditional throw */
14232         if (fgIsCommaThrow(morph, true))
14233         {
14234 #ifdef DEBUG
14235             if (verbose)
14236             {
14237                 printf("Folding a top-level fgIsCommaThrow stmt\n");
14238                 printf("Removing op2 as unreachable:\n");
14239                 gtDispTree(morph->gtOp.gtOp2);
14240                 printf("\n");
14241             }
14242 #endif
14243             /* Use the call as the new stmt */
14244             morph = morph->gtOp.gtOp1;
14245             noway_assert(morph->gtOper == GT_CALL);
14246         }
14247
14248         /* we can get a throw as a statement root*/
14249         if (fgIsThrow(morph))
14250         {
14251 #ifdef DEBUG
14252             if (verbose)
14253             {
14254                 printf("We have a top-level fgIsThrow stmt\n");
14255                 printf("Removing the rest of block as unreachable:\n");
14256             }
14257 #endif
14258             noway_assert((morph->gtFlags & GTF_COLON_COND) == 0);
14259             fgRemoveRestOfBlock = true;
14260         }
14261     }
14262
14263     stmt->gtStmt.gtStmtExpr = morph;
14264
14265     /* Can the entire tree be removed ? */
14266
14267     bool removedStmt = fgCheckRemoveStmt(block, stmt);
14268
14269     /* Or this is the last statement of a conditional branch that was just folded */
14270
14271     if ((!removedStmt) && (stmt->gtNext == NULL) && !fgRemoveRestOfBlock)
14272     {
14273          if (fgFoldConditional(block))
14274          {
14275             if (block->bbJumpKind != BBJ_THROW)
14276                 removedStmt = true;
14277          }
14278     }
14279
14280     if (!removedStmt)
14281     {
14282         /* Have to re-do the evaluation order since for example
14283          * some later code does not expect constants as op1 */
14284         gtSetStmtInfo(stmt);
14285
14286         /* Have to re-link the nodes for this statement */
14287         fgSetStmtSeq(stmt);
14288     }
14289
14290 #ifdef DEBUG
14291     if (verbose)
14292     {
14293         printf("%s %s tree:\n", msg, (removedStmt ? "removed" : "morphed"));
14294         gtDispTree(morph);
14295         printf("\n");
14296     }
14297 #endif
14298
14299     if (fgRemoveRestOfBlock)
14300     {
14301         /* Remove the rest of the stmts in the block */
14302
14303         while (stmt->gtNext)
14304         {
14305             stmt = stmt->gtNext;
14306             noway_assert(stmt->gtOper == GT_STMT);
14307
14308             fgRemoveStmt(block, stmt);
14309         }
14310
14311         // The rest of block has been removed
14312         // and we will always throw an exception
14313
14314         // Update succesors of block
14315         fgRemoveBlockAsPred(block);
14316
14317         // For compDbgCode, we prepend an empty BB as the firstBB, it is BBJ_NONE.
14318         // We should not convert it to a ThrowBB.
14319         if ((block != fgFirstBB) || ((fgFirstBB->bbFlags & BBF_INTERNAL) == 0) ) {
14320             // Convert block to a throw bb
14321             fgConvertBBToThrowBB(block);
14322         }
14323
14324 #ifdef DEBUG
14325         if (verbose)
14326         {
14327             printf("\n%s Block BB%02u becomes a throw block.\n", msg, block->bbNum);
14328         }
14329 #endif
14330         fgRemoveRestOfBlock = false;
14331     }
14332
14333     return removedStmt;
14334 }
14335
14336 /*****************************************************************************
14337  *
14338  *  Morph the statements of the given block.
14339  *  This function should be called just once for a block. Use fgMorphBlockStmt()
14340  *  for reentrant calls.
14341  */
14342
14343 void                Compiler::fgMorphStmts(BasicBlock * block,
14344                                            bool * mult, bool * lnot, bool * loadw)
14345 {
14346     fgRemoveRestOfBlock = false;
14347
14348     noway_assert(fgExpandInline == false);
14349
14350     /* Make the current basic block address available globally */
14351
14352     compCurBB = block;
14353
14354     *mult = *lnot = *loadw = false;
14355
14356     fgCurrentlyInUseArgTemps = hashBv::Create(this);
14357
14358     GenTreePtr stmt, prev;
14359     for (stmt = block->bbTreeList, prev = NULL;
14360          stmt;
14361          prev = stmt->gtStmt.gtStmtExpr,
14362          stmt = stmt->gtNext)
14363     {
14364         noway_assert(stmt->gtOper == GT_STMT);
14365
14366         if (fgRemoveRestOfBlock)
14367         {
14368             fgRemoveStmt(block, stmt);
14369             continue;
14370         }
14371 #ifdef FEATURE_SIMD
14372         if (!opts.MinOpts()                                 &&
14373             stmt->gtStmt.gtStmtExpr->TypeGet() == TYP_FLOAT &&
14374             stmt->gtStmt.gtStmtExpr->OperGet() == GT_ASG)
14375         {
14376             fgMorphCombineSIMDFieldAssignments(block, stmt);
14377         }
14378 #endif
14379
14380         fgMorphStmt      = stmt;
14381         compCurStmt      = stmt;
14382         GenTreePtr  tree = stmt->gtStmt.gtStmtExpr;
14383
14384 #ifdef DEBUG
14385         compCurStmtNum++;
14386         if (stmt == block->bbTreeList)
14387             block->bbStmtNum = compCurStmtNum;  // Set the block->bbStmtNum
14388
14389         unsigned oldHash = verbose ? gtHashValue(tree) : DUMMY_INIT(~0);
14390
14391         if (verbose)
14392         {
14393             printf("\nfgMorphTree BB%02u, stmt %d (before)\n", block->bbNum, compCurStmtNum);
14394             gtDispTree(tree);
14395         }
14396 #endif
14397
14398         /* Morph this statement tree */
14399
14400         GenTreePtr  morph = fgMorphTree(tree);
14401
14402         // mark any outgoing arg temps as free so we can reuse them in the next statement.
14403         
14404         fgCurrentlyInUseArgTemps->ZeroAll();
14405
14406         // Has fgMorphStmt been sneakily changed ?
14407
14408         if (stmt->gtStmt.gtStmtExpr != tree)
14409         {
14410             /* This must be tailcall. Ignore 'morph' and carry on with
14411                the tail-call node */
14412
14413             morph = stmt->gtStmt.gtStmtExpr;
14414             noway_assert(compTailCallUsed);
14415             noway_assert((morph->gtOper == GT_CALL) && morph->AsCall()->IsTailCall());
14416             noway_assert(stmt->gtNext == NULL);
14417
14418             GenTreeCall* call = morph->AsCall();
14419             // Could either be 
14420             //   - a tail call dispatched via helper in which case block will be ending with BBJ_THROW or
14421             //   - a fast call made as jmp in which case block will be ending with BBJ_RETURN and marked as containing a jmp.
14422             noway_assert((call->IsTailCallViaHelper() && (compCurBB->bbJumpKind == BBJ_THROW)) || 
14423                          (call->IsFastTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN) && (compCurBB->bbFlags &  BBF_HAS_JMP)));
14424         }
14425         else if (block != compCurBB)
14426         {
14427             /* This must be a tail call that caused a GCPoll to get
14428                injected.  We haven't actually morphed the call yet
14429                but the flag still got set, clear it here...  */
14430
14431 #ifdef DEBUG
14432             tree->gtFlags &= ~GTF_MORPHED;
14433 #endif
14434             noway_assert(compTailCallUsed);
14435             noway_assert((tree->gtOper == GT_CALL) && tree->AsCall()->IsTailCall());
14436             noway_assert(stmt->gtNext == NULL);
14437
14438             GenTreeCall* call = morph->AsCall();
14439
14440             // Could either be 
14441             //   - a tail call dispatched via helper in which case block will be ending with BBJ_THROW or
14442             //   - a fast call made as jmp in which case block will be ending with BBJ_RETURN and marked as containing a jmp.
14443             noway_assert((call->IsTailCallViaHelper() && (compCurBB->bbJumpKind == BBJ_THROW)) || 
14444                          (call->IsFastTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN) && (compCurBB->bbFlags &  BBF_HAS_JMP)));
14445         }
14446
14447 #ifdef DEBUG
14448         if (compStressCompile(STRESS_CLONE_EXPR, 30))
14449         {
14450             // Clone all the trees to stress gtCloneExpr()
14451
14452             if (verbose)
14453             {
14454                 printf("\nfgMorphTree (stressClone from):\n");
14455                 gtDispTree(morph);
14456             }
14457
14458             morph = gtCloneExpr(morph);
14459             noway_assert(morph);
14460
14461             if (verbose)
14462             {
14463                 printf("\nfgMorphTree (stressClone to):\n");
14464                 gtDispTree(morph);
14465             }
14466         }
14467
14468         /* If the hash value changes. we modified the tree during morphing */
14469         if (verbose)
14470         {
14471             unsigned newHash = gtHashValue(morph);
14472             if (newHash != oldHash)
14473             {
14474                 printf("\nfgMorphTree BB%02u, stmt %d (after)\n", block->bbNum, compCurStmtNum);
14475                 gtDispTree(morph);
14476             }
14477         }
14478 #endif
14479
14480         /* Check for morph as a GT_COMMA with an unconditional throw */
14481         if (!gtIsActiveCSE_Candidate(morph) && fgIsCommaThrow(morph, true))
14482         {
14483             /* Use the call as the new stmt */
14484             morph = morph->gtOp.gtOp1;
14485             noway_assert(morph->gtOper == GT_CALL);
14486             noway_assert((morph->gtFlags & GTF_COLON_COND) == 0);
14487
14488             fgRemoveRestOfBlock = true;
14489         }
14490
14491         stmt->gtStmt.gtStmtExpr = tree = morph;
14492
14493         noway_assert(fgPtrArgCntCur == 0);
14494
14495         if (fgRemoveRestOfBlock)
14496             continue;
14497
14498         /* Has the statement been optimized away */
14499
14500         if (fgCheckRemoveStmt(block, stmt))
14501             continue;
14502
14503         /* Check if this block ends with a conditional branch that can be folded */
14504
14505         if (fgFoldConditional(block))
14506             continue;
14507
14508         if  (ehBlockHasExnFlowDsc(block))
14509             continue;
14510
14511 #if OPT_MULT_ADDSUB
14512
14513         /* Note whether we have two or more +=/-= operators in a row */
14514
14515         if  (tree->gtOper == GT_ASG_ADD ||
14516              tree->gtOper == GT_ASG_SUB)
14517         {
14518             if  (prev && prev->gtOper == tree->gtOper)
14519                 *mult = true;
14520         }
14521
14522 #endif
14523
14524         /* Note "x = a[i] & icon" followed by "x |= a[i] << 8" */
14525
14526         if  (tree->gtOper == GT_ASG_OR &&
14527              prev &&
14528              prev->gtOper == GT_ASG)
14529         {
14530             *loadw = true;
14531         }
14532     }
14533
14534     if (fgRemoveRestOfBlock)
14535     {
14536         if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH))
14537         {
14538             GenTreePtr first = block->bbTreeList; noway_assert(first);
14539             GenTreePtr last  = first->gtPrev;     noway_assert(last && last->gtNext == NULL);
14540             GenTreePtr lastStmt = last->gtStmt.gtStmtExpr;
14541
14542             if (((block->bbJumpKind == BBJ_COND  ) && (lastStmt->gtOper == GT_JTRUE )) ||
14543                 ((block->bbJumpKind == BBJ_SWITCH) && (lastStmt->gtOper == GT_SWITCH))   )
14544             {
14545                 GenTreePtr op1  = lastStmt->gtOp.gtOp1;
14546
14547                 if (op1->OperKind() & GTK_RELOP)
14548                 {
14549                     /* Unmark the comparison node with GTF_RELOP_JMP_USED */
14550                     op1->gtFlags &= ~GTF_RELOP_JMP_USED;
14551                 }
14552
14553                 last->gtStmt.gtStmtExpr = fgMorphTree(op1);
14554             }
14555         }
14556
14557         /* Mark block as a BBJ_THROW block */
14558         fgConvertBBToThrowBB(block);
14559     }
14560
14561     noway_assert(fgExpandInline == false);
14562
14563 #if FEATURE_FASTTAILCALL
14564     GenTreePtr recursiveTailCall = nullptr;
14565     if (block->endsWithTailCallConvertibleToLoop(this, &recursiveTailCall))
14566     {
14567         fgMorphRecursiveFastTailCallIntoLoop(block, recursiveTailCall->AsCall());
14568     }
14569 #endif
14570
14571 #ifdef DEBUG
14572     compCurBB = (BasicBlock*)INVALID_POINTER_VALUE;
14573 #endif
14574
14575     // Reset this back so that it doesn't leak out impacting other blocks
14576     fgRemoveRestOfBlock = false;
14577 }
14578
14579 /*****************************************************************************
14580  *
14581  *  Morph the blocks of the method.
14582  *  Returns true if the basic block list is modified.
14583  *  This function should be called just once.
14584  */
14585
14586 void                Compiler::fgMorphBlocks()
14587 {
14588 #ifdef DEBUG
14589     if  (verbose)
14590         printf("\n*************** In fgMorphBlocks()\n");
14591 #endif
14592
14593     /* Since fgMorphTree can be called after various optimizations to re-arrange
14594      * the nodes we need a global flag to signal if we are during the one-pass
14595      * global morphing */
14596
14597     fgGlobalMorph   = true;
14598
14599 #if LOCAL_ASSERTION_PROP
14600     //
14601     // Local assertion prop is enabled if we are optimized
14602     //
14603     optLocalAssertionProp = (!opts.compDbgCode && !opts.MinOpts());
14604
14605     if (optLocalAssertionProp)
14606     {
14607         //
14608         // Initialize for local assertion prop
14609         //
14610         optAssertionInit(true);
14611     }
14612 #elif ASSERTION_PROP
14613     //
14614     // If LOCAL_ASSERTION_PROP is not set
14615     // and we have global assertion prop
14616     // then local assertion prop is always off
14617     //
14618     optLocalAssertionProp = false;
14619
14620 #endif
14621
14622     /*-------------------------------------------------------------------------
14623      * Process all basic blocks in the function
14624      */
14625
14626     BasicBlock *    block       = fgFirstBB; noway_assert(block);
14627
14628 #ifdef DEBUG
14629     compCurStmtNum = 0;
14630 #endif
14631
14632     do
14633     {
14634 #if OPT_MULT_ADDSUB
14635         bool            mult  = false;
14636 #endif
14637
14638 #if OPT_BOOL_OPS
14639         bool            lnot  = false;
14640 #endif
14641
14642         bool            loadw = false;
14643
14644 #ifdef DEBUG
14645         if (verbose)
14646             printf("\nMorphing BB%02u of '%s'\n", block->bbNum, info.compFullName);
14647 #endif
14648
14649 #if LOCAL_ASSERTION_PROP
14650         if (optLocalAssertionProp)
14651         {
14652             //
14653             // Clear out any currently recorded assertion candidates
14654             // before processing each basic block,
14655             // also we must  handle QMARK-COLON specially
14656             //
14657             optAssertionReset(0);
14658         }
14659 #endif
14660
14661         /* Process all statement trees in the basic block */
14662
14663         GenTreePtr      tree;
14664
14665         fgMorphStmts(block, &mult, &lnot, &loadw);
14666
14667 #if OPT_MULT_ADDSUB
14668
14669         if  (mult && (opts.compFlags & CLFLG_TREETRANS) &&
14670              !opts.compDbgCode && !opts.MinOpts())
14671         {
14672             for (tree = block->bbTreeList; tree; tree = tree->gtNext)
14673             {
14674                 noway_assert(tree->gtOper == GT_STMT);
14675                 GenTreePtr last = tree->gtStmt.gtStmtExpr;
14676
14677                 if  (last->gtOper == GT_ASG_ADD ||
14678                      last->gtOper == GT_ASG_SUB)
14679                 {
14680                     GenTreePtr      temp;
14681                     GenTreePtr      next;
14682
14683                     GenTreePtr      dst1 = last->gtOp.gtOp1;
14684                     GenTreePtr      src1 = last->gtOp.gtOp2;
14685
14686                     if  (!last->IsCnsIntOrI())
14687                         goto NOT_CAFFE;
14688
14689                     if  (dst1->gtOper != GT_LCL_VAR)
14690                         goto NOT_CAFFE;
14691                     if  (!src1->IsCnsIntOrI())
14692                         goto NOT_CAFFE;
14693
14694                     for (;;)
14695                     {
14696                         GenTreePtr      dst2;
14697                         GenTreePtr      src2;
14698
14699                         /* Look at the next statement */
14700
14701                         temp = tree->gtNext;
14702                         if  (!temp)
14703                             goto NOT_CAFFE;
14704
14705                         noway_assert(temp->gtOper == GT_STMT);
14706                         next = temp->gtStmt.gtStmtExpr;
14707
14708                         if  (next->gtOper != last->gtOper)
14709                             goto NOT_CAFFE;
14710                         if  (next->gtType != last->gtType)
14711                             goto NOT_CAFFE;
14712
14713                         dst2 = next->gtOp.gtOp1;
14714                         src2 = next->gtOp.gtOp2;
14715
14716                         if  (dst2->gtOper != GT_LCL_VAR)
14717                             goto NOT_CAFFE;
14718                         if  (dst2->gtLclVarCommon.gtLclNum != dst1->gtLclVarCommon.gtLclNum)
14719                             goto NOT_CAFFE;
14720
14721                         if  (!src2->IsCnsIntOrI())
14722                             goto NOT_CAFFE;
14723
14724                         if  (last->gtOverflow() != next->gtOverflow())
14725                             goto NOT_CAFFE;
14726
14727                         const ssize_t i1 = src1->gtIntCon.gtIconVal;
14728                         const ssize_t i2 = src2->gtIntCon.gtIconVal;
14729                         const ssize_t itemp = i1 + i2;
14730
14731                         /* if the operators are checking for overflow, check for overflow of the operands */
14732
14733                         if  (next->gtOverflow())
14734                         {
14735                             if (next->TypeGet() == TYP_LONG)
14736                             {
14737                                 if (next->gtFlags & GTF_UNSIGNED)
14738                                 {
14739                                     ClrSafeInt<UINT64> si1(i1);
14740                                     if ((si1 + ClrSafeInt<UINT64>(i2)).IsOverflow())
14741                                         goto NOT_CAFFE;
14742                                 }
14743                                 else
14744                                 {
14745                                     ClrSafeInt<INT64> si1(i1);
14746                                     if ((si1 + ClrSafeInt<INT64>(i2)).IsOverflow())
14747                                         goto NOT_CAFFE;
14748                                 }
14749                             }
14750                             else if (next->gtFlags & GTF_UNSIGNED)
14751                             {
14752                                 ClrSafeInt<UINT32> si1(i1);
14753                                 if ((si1 + ClrSafeInt<UINT32>(i2)).IsOverflow())
14754                                     goto NOT_CAFFE;
14755                             }
14756                             else
14757                             {
14758                                 ClrSafeInt<INT32> si1(i1);
14759                                 if ((si1 + ClrSafeInt<INT32>(i2)).IsOverflow())
14760                                     goto NOT_CAFFE;
14761                             }
14762                         }
14763
14764                         /* Fold the two increments/decrements into one */
14765
14766                         src1->gtIntCon.gtIconVal = itemp;
14767 #ifdef _TARGET_64BIT_
14768                         if (src1->gtType == TYP_INT)
14769                         {
14770                             src1->AsIntCon()->TruncateOrSignExtend32();
14771                         }
14772 #endif //_TARGET_64BIT_
14773
14774                         /* Remove the second statement completely */
14775
14776                         noway_assert(tree->gtNext == temp);
14777                         noway_assert(temp->gtPrev == tree);
14778
14779                         if  (temp->gtNext)
14780                         {
14781                             noway_assert(temp->gtNext->gtPrev == temp);
14782
14783                             temp->gtNext->gtPrev = tree;
14784                             tree->gtNext         = temp->gtNext;
14785                         }
14786                         else
14787                         {
14788                             tree->gtNext = 0;
14789
14790                             noway_assert(block->bbTreeList->gtPrev == temp);
14791
14792                             block->bbTreeList->gtPrev = tree;
14793                         }
14794                     }
14795                 }
14796
14797             NOT_CAFFE:;
14798
14799             }
14800
14801         }
14802
14803 #endif
14804
14805         /* Are we using a single return block? */
14806
14807         if (block->bbJumpKind == BBJ_RETURN)
14808         {
14809              if ((genReturnBB != nullptr)  &&
14810                  (genReturnBB != block) &&
14811                  ((block->bbFlags & BBF_HAS_JMP) == 0))
14812              {
14813                 /* We'll jump to the genReturnBB */
14814
14815 #if !defined(_TARGET_X86_)
14816                 if (info.compFlags & CORINFO_FLG_SYNCH)
14817                 {
14818                     fgConvertSyncReturnToLeave(block);
14819                 }
14820                 else
14821 #endif // !_TARGET_X86_
14822                 {
14823                     block->bbJumpKind = BBJ_ALWAYS;
14824                     block->bbJumpDest = genReturnBB;
14825                     fgReturnCount--;
14826                 }
14827
14828                 // Note 1: A block is not guaranteed to have a last stmt if its jump kind is BBJ_RETURN.
14829                 // For example a method returning void could have an empty block with jump kind BBJ_RETURN.
14830                 // Such blocks do materialize as part of in-lining.
14831                 //
14832                 // Note 2: A block with jump kind BBJ_RETURN does not necessarily need to end with GT_RETURN.
14833                 // It could end with a tail call or rejected tail call or monitor.exit or a GT_INTRINSIC.
14834                 // For now it is safe to explicitly check whether last stmt is GT_RETURN if genReturnLocal
14835                 // is BAD_VAR_NUM.
14836                 // 
14837                 // TODO: Need to characterize the last top level stmt of a block ending with BBJ_RETURN.
14838
14839                 GenTreePtr last = (block->bbTreeList != nullptr) ? block->bbTreeList->gtPrev : nullptr;
14840                 GenTreePtr ret = (last != nullptr) ? last->gtStmt.gtStmtExpr : nullptr;
14841                 
14842                 //replace the GT_RETURN node to be a GT_ASG that stores the return value into genReturnLocal.
14843                 if (genReturnLocal != BAD_VAR_NUM)
14844                 {
14845                     // Method must be returning a value other than TYP_VOID.
14846                     noway_assert(compMethodHasRetVal());
14847
14848                     // This block must be ending with a GT_RETURN
14849                     noway_assert(last != nullptr);
14850                     noway_assert(last->gtOper == GT_STMT);
14851                     noway_assert(last->gtNext == nullptr);                    
14852                     noway_assert(ret != nullptr);
14853
14854                     // GT_RETURN must have non-null operand as the method is returning the value assigned to genReturnLocal
14855                     noway_assert(ret->OperGet() == GT_RETURN);
14856                     noway_assert(ret->gtGetOp1() != nullptr);
14857                     noway_assert(ret->gtGetOp2() == nullptr);
14858
14859                     last->gtStmt.gtStmtExpr = gtNewTempAssign(genReturnLocal, ret->gtGetOp1());
14860
14861                     //make sure that copy-prop ignores this assignment.
14862                     last->gtStmt.gtStmtExpr->gtFlags |= GTF_DONT_CSE;
14863                 }
14864                 else if (ret != nullptr && ret->OperGet() == GT_RETURN)
14865                 {
14866                     // This block ends with a GT_RETURN
14867                     noway_assert(last != nullptr);
14868                     noway_assert(last->gtOper == GT_STMT);
14869                     noway_assert(last->gtNext == nullptr);
14870                     
14871                     // Must be a void GT_RETURN with null operand; delete it as this block branches to oneReturn block
14872                     noway_assert(ret->TypeGet() == TYP_VOID);
14873                     noway_assert(ret->gtGetOp1() == nullptr);
14874                     noway_assert(ret->gtGetOp2() == nullptr);
14875
14876                     fgRemoveStmt(block, last);
14877                 }
14878
14879 #ifdef DEBUG
14880                 if (verbose)
14881                 {
14882                     printf("morph BB%02u to point at onereturn.  New block is\n",
14883                         block->bbNum);
14884                     fgTableDispBasicBlock(block);
14885                 }
14886 #endif
14887              }
14888         }
14889
14890         block       = block->bbNext;
14891     }
14892     while (block);
14893
14894     /* We are done with the global morphing phase */
14895
14896     fgGlobalMorph   = false;
14897
14898
14899 #ifdef DEBUG
14900     if  (verboseTrees)
14901         fgDispBasicBlocks(true);
14902 #endif
14903
14904 }
14905
14906
14907 /*****************************************************************************
14908  *
14909  *  Make some decisions about the kind of code to generate.
14910  */
14911
14912 void                Compiler::fgSetOptions()
14913 {
14914
14915     /* Should we force fully interruptible code ? */
14916
14917 #ifdef DEBUG
14918     if (JitConfig.JitFullyInt() ||
14919         compStressCompile(STRESS_GENERIC_VARN, 30))
14920     {
14921         noway_assert(!codeGen->isGCTypeFixed());
14922         genInterruptible = true;
14923     }
14924 #endif
14925
14926 #ifdef DEBUGGING_SUPPORT
14927     if (opts.compDbgCode)
14928     {
14929         assert(!codeGen->isGCTypeFixed());
14930         genInterruptible = true;        // debugging is easier this way ...
14931     }
14932 #endif
14933
14934     /* Assume we won't need an explicit stack frame if this is allowed */
14935
14936
14937     // CORINFO_HELP_TAILCALL won't work with localloc because of the restoring of
14938     // the callee-saved registers.
14939     noway_assert(!compTailCallUsed || !compLocallocUsed);
14940
14941     if (compLocallocUsed)
14942         codeGen->setFramePointerRequired(true);
14943
14944 #ifdef _TARGET_X86_
14945
14946     if (compTailCallUsed)
14947         codeGen->setFramePointerRequired(true);
14948
14949 #endif // _TARGET_X86_
14950
14951     if (!opts.genFPopt)
14952         codeGen->setFramePointerRequired(true);
14953
14954     // Assert that the EH table has been initialized by now. Note that
14955     // compHndBBtabAllocCount never decreases; it is a high-water mark
14956     // of table allocation. In contrast, compHndBBtabCount does shrink
14957     // if we delete a dead EH region, and if it shrinks to zero, the
14958     // table pointer compHndBBtab is unreliable.
14959     assert(compHndBBtabAllocCount >= info.compXcptnsCount);
14960
14961 #ifdef _TARGET_X86_
14962
14963     // Note: this case, and the !X86 case below, should both use the
14964     // !X86 path. This would require a few more changes for X86 to use
14965     // compHndBBtabCount (the current number of EH clauses) instead of
14966     // info.compXcptnsCount (the number of EH clauses in IL), such as
14967     // in ehNeedsShadowSPslots(). This is because sometimes the IL has
14968     // an EH clause that we delete as statically dead code before we
14969     // get here, leaving no EH clauses left, and thus no requirement
14970     // to use a frame pointer because of EH. But until all the code uses
14971     // the same test, leave info.compXcptnsCount here.
14972     if (info.compXcptnsCount > 0)
14973         codeGen->setFramePointerRequiredEH(true);
14974
14975 #else // !_TARGET_X86_
14976
14977     if (compHndBBtabCount > 0)
14978         codeGen->setFramePointerRequiredEH(true);
14979
14980 #endif // _TARGET_X86_
14981
14982     //  fpPtrArgCntMax records the maximum number of pushed arguments
14983     //  Depending upon this value of the maximum number of pushed arguments
14984     //  we may need to use an EBP frame or be partially interuptible
14985     //
14986
14987     if (!compCanEncodePtrArgCntMax())
14988     {
14989 #ifdef DEBUG
14990         if (verbose)
14991             printf("Too many pushed arguments for fully interruptible encoding, marking method as partially interruptible\n");
14992 #endif
14993         genInterruptible = false;
14994     }
14995     if (fgPtrArgCntMax >= sizeof(unsigned))
14996     {
14997 #ifdef DEBUG
14998         if (verbose)
14999             printf("Too many pushed arguments for an ESP based encoding, forcing an EBP frame\n");
15000 #endif
15001         codeGen->setFramePointerRequiredGCInfo(true);
15002     }
15003
15004     if (info.compCallUnmanaged)
15005     {
15006         codeGen->setFramePointerRequired(true);  // Setup of Pinvoke frame currently requires an EBP style frame
15007     }
15008
15009     if (info.compPublishStubParam)
15010     {
15011         codeGen->setFramePointerRequiredGCInfo(true);
15012     }
15013
15014     if  (opts.compNeedSecurityCheck)
15015     {
15016         codeGen->setFramePointerRequiredGCInfo(true);
15017
15018 #ifndef JIT32_GCENCODER
15019
15020         // The decoder only reports objects in frames with exceptions if the frame
15021         // is fully interruptible.
15022         // Even if there is no catch or other way to resume execution in this frame
15023         // the VM requires the security object to remain alive until later, so
15024         // Frames with security objects must be fully interruptible.
15025         genInterruptible = true;
15026
15027 #endif // JIT32_GCENCODER
15028     }
15029
15030     if (compIsProfilerHookNeeded())
15031     {
15032         codeGen->setFramePointerRequired(true);
15033     }
15034
15035     if (info.compIsVarArgs)
15036     {
15037         // Code that initializes lvaVarargsBaseOfStkArgs requires this to be EBP relative.
15038         codeGen->setFramePointerRequiredGCInfo(true);
15039     }
15040
15041     if (lvaReportParamTypeArg())
15042     {
15043         codeGen->setFramePointerRequiredGCInfo(true);
15044     }
15045
15046 //  printf("method will %s be fully interruptible\n", genInterruptible ? "   " : "not");
15047 }
15048
15049
15050 /*****************************************************************************/
15051
15052 GenTreePtr          Compiler::fgInitThisClass()
15053 {
15054     noway_assert(!compIsForInlining());
15055
15056     CORINFO_LOOKUP_KIND kind = info.compCompHnd->getLocationOfThisType(info.compMethodHnd);
15057
15058     if (!kind.needsRuntimeLookup)
15059     {
15060         return fgGetSharedCCtor(info.compClassHnd);
15061     }
15062     else
15063     {
15064         // Collectible types requires that for shared generic code, if we use the generic context paramter
15065         // that we report it. (This is a conservative approach, we could detect some cases particularly when the
15066         // context parameter is this that we don't need the eager reporting logic.)
15067         lvaGenericsContextUsed = true;
15068
15069         switch (kind.runtimeLookupKind)
15070         {
15071         case CORINFO_LOOKUP_THISOBJ :
15072         // This code takes a this pointer; but we need to pass the static method desc to get the right point in the hierarchy
15073         {
15074             GenTreePtr vtTree = gtNewLclvNode(info.compThisArg, TYP_REF);
15075             // Vtable pointer of this object
15076             vtTree = gtNewOperNode(GT_IND, TYP_I_IMPL, vtTree);
15077             vtTree->gtFlags |= GTF_EXCEPT; // Null-pointer exception
15078             GenTreePtr methodHnd = gtNewIconEmbMethHndNode(info.compMethodHnd);
15079
15080             return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS,
15081                                        TYP_VOID, 0,
15082                                        gtNewArgList(vtTree, methodHnd));
15083
15084         }
15085
15086         case CORINFO_LOOKUP_CLASSPARAM :
15087         {
15088             GenTreePtr vtTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
15089             return gtNewHelperCallNode(CORINFO_HELP_INITCLASS,
15090                                        TYP_VOID, 0,
15091                                        gtNewArgList(vtTree));
15092         }
15093
15094         case CORINFO_LOOKUP_METHODPARAM :
15095         {
15096             GenTreePtr methHndTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
15097             return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS,
15098                                        TYP_VOID, 0,
15099                                        gtNewArgList(gtNewIconNode(0),methHndTree));
15100         }
15101         }
15102
15103     }
15104
15105     noway_assert(!"Unknown LOOKUP_KIND");
15106     UNREACHABLE();
15107 }
15108
15109
15110 #ifdef DEBUG
15111 /*****************************************************************************
15112  *
15113  *  Tree walk callback to make sure no GT_QMARK nodes are present in the tree,
15114  *  except for the allowed ? 1 : 0; pattern.
15115  */
15116 Compiler::fgWalkResult Compiler::fgAssertNoQmark(GenTreePtr* tree, fgWalkData* data)
15117 {
15118     if ((*tree)->OperGet() == GT_QMARK)
15119     {
15120         fgCheckQmarkAllowedForm(*tree);
15121     }
15122     return WALK_CONTINUE;
15123 }
15124
15125 void Compiler::fgCheckQmarkAllowedForm(GenTree* tree)
15126 {
15127     assert(tree->OperGet() == GT_QMARK);
15128 #ifndef LEGACY_BACKEND
15129     assert(!"Qmarks beyond morph disallowed.");
15130 #else // LEGACY_BACKEND
15131     GenTreePtr colon = tree->gtOp.gtOp2;
15132
15133     assert(colon->gtOp.gtOp1->gtOper == GT_CNS_INT);
15134     assert(colon->gtOp.gtOp1->AsIntCon()->IconValue() == 0);
15135
15136     assert(colon->gtOp.gtOp2->gtOper == GT_CNS_INT);
15137     assert(colon->gtOp.gtOp2->AsIntCon()->IconValue() == 1);
15138 #endif // LEGACY_BACKEND
15139 }
15140
15141 /*****************************************************************************
15142  *
15143  *  Verify that the importer has created GT_QMARK nodes in a way we can
15144  *  process them. The following is allowed:
15145  *
15146  *  1. A top level qmark. Top level qmark is of the form:
15147  *      a) (bool) ? (void) : (void) OR
15148  *      b) V0N = (bool) ? (type) : (type)
15149  *
15150  *  2. Recursion is allowed at the top level, i.e., a GT_QMARK can be a child
15151  *     of either op1 of colon or op2 of colon but not a child of any other
15152  *     operator.
15153  */
15154 void Compiler::fgPreExpandQmarkChecks(GenTreePtr expr)
15155 {
15156     GenTreePtr topQmark = fgGetTopLevelQmark(expr);
15157
15158     // If the top level Qmark is null, then scan the tree to make sure
15159     // there are no qmarks within it.
15160     if (topQmark == NULL)
15161     {
15162         fgWalkTreePre(&expr, Compiler::fgAssertNoQmark, NULL);
15163     }
15164     else
15165     {
15166         // We could probably expand the cond node also, but don't think the extra effort is necessary,
15167         // so let's just assert the cond node of a top level qmark doesn't have further top level qmarks.
15168         fgWalkTreePre(&topQmark->gtOp.gtOp1, Compiler::fgAssertNoQmark, NULL);
15169
15170         fgPreExpandQmarkChecks(topQmark->gtOp.gtOp2->gtOp.gtOp1);
15171         fgPreExpandQmarkChecks(topQmark->gtOp.gtOp2->gtOp.gtOp2);
15172     }
15173 }
15174 #endif // DEBUG
15175
15176 /*****************************************************************************
15177  *
15178  *  Get the top level GT_QMARK node in a given "expr", return NULL if such a
15179  *  node is not present. If the top level GT_QMARK node is assigned to a
15180  *  GT_LCL_VAR, then return the lcl node in ppDst.
15181  *
15182  */
15183 GenTreePtr Compiler::fgGetTopLevelQmark(GenTreePtr expr, GenTreePtr* ppDst /* = NULL */)
15184 {
15185     if (ppDst != NULL)
15186     {
15187         *ppDst = NULL;
15188     }
15189
15190     GenTreePtr topQmark = NULL;
15191     if (expr->gtOper == GT_QMARK)
15192     {
15193         topQmark = expr;
15194     }
15195     else if (expr->gtOper == GT_ASG &&
15196              expr->gtOp.gtOp2->gtOper == GT_QMARK &&
15197              expr->gtOp.gtOp1->gtOper == GT_LCL_VAR)
15198     {
15199         topQmark = expr->gtOp.gtOp2;
15200         if (ppDst != NULL)
15201         {
15202             *ppDst = expr->gtOp.gtOp1;
15203         }
15204     }
15205     return topQmark;
15206 }
15207
15208
15209 /*********************************************************************************
15210  *
15211  *  For a castclass helper call,
15212  *  Importer creates the following tree:
15213  *      tmp = (op1 == null) ? op1 : ((*op1 == (cse = op2, cse)) ? op1 : helper());
15214  *
15215  *  This method splits the qmark expression created by the importer into the
15216  *  following blocks: (block, asg, cond1, cond2, helper, remainder)
15217  *  Notice that op1 is the result for both the conditions. So we coalesce these
15218  *  assignments into a single block instead of two blocks resulting a nested diamond.
15219  *
15220  *                       +---------->-----------+
15221  *                       |          |           |
15222  *                       ^          ^           v
15223  *                       |          |           |
15224  *  block-->asg-->cond1--+-->cond2--+-->helper--+-->remainder
15225  *
15226  *  We expect to achieve the following codegen:
15227  *     mov      rsi, rdx                           tmp = op1                  // asgBlock
15228  *     test     rsi, rsi                           goto skip if tmp == null ? // cond1Block
15229  *     je       SKIP
15230  *     mov      rcx, 0x76543210                    cns = op2                  // cond2Block
15231  *     cmp      qword ptr [rsi], rcx               goto skip if *tmp == op2
15232  *     je       SKIP
15233  *     call     CORINFO_HELP_CHKCASTCLASS_SPECIAL  tmp = helper(cns, tmp)     // helperBlock
15234  *     mov      rsi, rax
15235  *  SKIP:                                                                     // remainderBlock
15236  *     tmp has the result.
15237  *
15238  */
15239 void Compiler::fgExpandQmarkForCastInstOf(BasicBlock* block, GenTreePtr stmt)
15240 {
15241 #ifdef DEBUG
15242     if (verbose)
15243     {
15244         printf("\nExpanding CastInstOf qmark in BB%02u (before)\n", block->bbNum);
15245         fgDispBasicBlocks(block, block, true);
15246     }
15247 #endif // DEBUG
15248
15249     GenTreePtr expr = stmt->gtStmt.gtStmtExpr;
15250
15251     GenTreePtr dst = nullptr;
15252     GenTreePtr qmark = fgGetTopLevelQmark(expr, &dst);
15253     noway_assert(dst != nullptr);
15254
15255     assert(qmark->gtFlags & GTF_QMARK_CAST_INSTOF);
15256
15257     // Get cond, true, false exprs for the qmark.
15258     GenTreePtr condExpr  = qmark->gtGetOp1();
15259     GenTreePtr trueExpr  = qmark->gtGetOp2()->AsColon()->ThenNode();
15260     GenTreePtr falseExpr = qmark->gtGetOp2()->AsColon()->ElseNode();
15261
15262     // Get cond, true, false exprs for the nested qmark.
15263     GenTreePtr nestedQmark = falseExpr;
15264     GenTreePtr cond2Expr;
15265     GenTreePtr true2Expr;
15266     GenTreePtr false2Expr;
15267
15268     if (nestedQmark->gtOper == GT_QMARK)
15269     {
15270         cond2Expr  = nestedQmark->gtGetOp1();
15271         true2Expr  = nestedQmark->gtGetOp2()->AsColon()->ThenNode();
15272         false2Expr = nestedQmark->gtGetOp2()->AsColon()->ElseNode();
15273
15274         assert(cond2Expr->gtFlags & GTF_RELOP_QMARK);
15275         cond2Expr->gtFlags &= ~GTF_RELOP_QMARK;
15276     }
15277     else
15278     {
15279         // This is a rare case that arises when we are doing minopts and encounter isinst of null
15280         // gtFoldExpr was still is able to optimize away part of the tree (but not all).
15281         // That means it does not match our pattern.
15282         
15283         // Rather than write code to handle this case, just fake up some nodes to make it match the common 
15284         // case.  Synthesize a comparison that is always true, and for the result-on-true, use the
15285         // entire subtree we expected to be the nested question op.
15286
15287         cond2Expr  = gtNewOperNode(GT_EQ, TYP_INT, gtNewIconNode(0, TYP_I_IMPL), gtNewIconNode(0, TYP_I_IMPL));
15288         true2Expr  = nestedQmark;
15289         false2Expr = gtNewIconNode(0, TYP_I_IMPL);
15290     }
15291     assert(false2Expr->OperGet() == trueExpr->OperGet());
15292
15293     // Clear flags as they are now going to be part of JTRUE.
15294     assert(condExpr->gtFlags  & GTF_RELOP_QMARK);
15295     condExpr->gtFlags  &= ~GTF_RELOP_QMARK;
15296
15297     // Create the chain of blocks. See method header comment.
15298     // The order of blocks after this is the following:
15299     //     block ... asgBlock ... cond1Block ... cond2Block ... helperBlock ... remainderBlock
15300     //
15301     // We need to remember flags that exist on 'block' that we want to propagate to 'remainderBlock',
15302     // if they are going to be cleared by fgSplitBlockAfterStatement(). We currently only do this only
15303     // for the GC safe point bit, the logic being that if 'block' was marked gcsafe, then surely
15304     // remainderBlock will still be GC safe.
15305     unsigned propagateFlags = block->bbFlags & BBF_GC_SAFE_POINT;
15306     BasicBlock* remainderBlock = fgSplitBlockAfterStatement(block, stmt);
15307     fgRemoveRefPred(remainderBlock, block); // We're going to put more blocks between block and remainderBlock.
15308
15309     BasicBlock* helperBlock    = fgNewBBafter(BBJ_NONE, block, true);
15310     BasicBlock* cond2Block     = fgNewBBafter(BBJ_COND, block, true);
15311     BasicBlock* cond1Block     = fgNewBBafter(BBJ_COND, block, true);
15312     BasicBlock* asgBlock       = fgNewBBafter(BBJ_NONE, block, true);
15313
15314     remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | propagateFlags;
15315
15316     // These blocks are only internal if 'block' is (but they've been set as internal by fgNewBBafter).
15317     // If they're not internal, mark them as imported to avoid asserts about un-imported blocks.
15318     if ((block->bbFlags & BBF_INTERNAL) == 0)
15319     {
15320         helperBlock->bbFlags &= ~BBF_INTERNAL;
15321         cond2Block->bbFlags  &= ~BBF_INTERNAL;
15322         cond1Block->bbFlags  &= ~BBF_INTERNAL;
15323         asgBlock->bbFlags    &= ~BBF_INTERNAL;
15324         helperBlock->bbFlags |=  BBF_IMPORTED;
15325         cond2Block->bbFlags  |=  BBF_IMPORTED;
15326         cond1Block->bbFlags  |=  BBF_IMPORTED;
15327         asgBlock->bbFlags    |=  BBF_IMPORTED;
15328     }
15329
15330     // Chain the flow correctly.
15331     fgAddRefPred(asgBlock, block);
15332     fgAddRefPred(cond1Block, asgBlock);
15333     fgAddRefPred(cond2Block, cond1Block);
15334     fgAddRefPred(helperBlock, cond2Block);
15335     fgAddRefPred(remainderBlock, helperBlock);
15336     fgAddRefPred(remainderBlock, cond1Block);
15337     fgAddRefPred(remainderBlock, cond2Block);
15338
15339     cond1Block->bbJumpDest = remainderBlock;
15340     cond2Block->bbJumpDest = remainderBlock;
15341
15342     // Set the weights; some are guesses.
15343     asgBlock->inheritWeight(block);
15344     cond1Block->inheritWeight(block);
15345     cond2Block->inheritWeightPercentage(cond1Block, 50);
15346     helperBlock->inheritWeightPercentage(cond2Block, 50);
15347
15348     // Append cond1 as JTRUE to cond1Block
15349     GenTreePtr jmpTree = gtNewOperNode(GT_JTRUE, TYP_VOID, condExpr);
15350     GenTreePtr jmpStmt = fgNewStmtFromTree(jmpTree, stmt->gtStmt.gtStmtILoffsx);
15351     fgInsertStmtAtEnd(cond1Block, jmpStmt);
15352
15353     // Append cond2 as JTRUE to cond2Block
15354     jmpTree = gtNewOperNode(GT_JTRUE, TYP_VOID, cond2Expr);
15355     jmpStmt = fgNewStmtFromTree(jmpTree, stmt->gtStmt.gtStmtILoffsx);
15356     fgInsertStmtAtEnd(cond2Block, jmpStmt);
15357
15358     // AsgBlock should get tmp = op1 assignment.
15359     trueExpr = gtNewTempAssign(dst->AsLclVarCommon()->GetLclNum(), trueExpr);
15360     GenTreePtr trueStmt = fgNewStmtFromTree(trueExpr, stmt->gtStmt.gtStmtILoffsx);
15361     fgInsertStmtAtEnd(asgBlock, trueStmt);
15362
15363     // Since we are adding helper in the JTRUE false path, reverse the cond2 and add the helper.
15364     gtReverseCond(cond2Expr);
15365     GenTreePtr helperExpr = gtNewTempAssign(dst->AsLclVarCommon()->GetLclNum(), true2Expr);
15366     GenTreePtr helperStmt = fgNewStmtFromTree(helperExpr, stmt->gtStmt.gtStmtILoffsx);
15367     fgInsertStmtAtEnd(helperBlock, helperStmt);
15368
15369     // Finally remove the nested qmark stmt.
15370     fgRemoveStmt(block, stmt);
15371
15372 #ifdef DEBUG
15373     if (verbose)
15374     {
15375         printf("\nExpanding CastInstOf qmark in BB%02u (after)\n", block->bbNum);
15376         fgDispBasicBlocks(block, remainderBlock, true);
15377     }
15378 #endif // DEBUG
15379 }
15380
15381 /*****************************************************************************
15382  *
15383  *  Expand a statement with a top level qmark node. There are three cases, based
15384  *  on whether the qmark has both "true" and "false" arms, or just one of them.
15385  *
15386  *     S0;
15387  *     C ? T : F;
15388  *     S1;
15389  *
15390  *     Generates ===>
15391  *
15392  *                       bbj_always
15393  *                       +---->------+
15394  *                 false |           |
15395  *     S0 -->-- ~C -->-- T   F -->-- S1
15396  *              |            |
15397  *              +--->--------+
15398  *              bbj_cond(true)
15399  *
15400  *     -----------------------------------------
15401  *
15402  *     S0;
15403  *     C ? T : NOP;
15404  *     S1;
15405  *
15406  *     Generates ===>
15407  *
15408  *                 false
15409  *     S0 -->-- ~C -->-- T -->-- S1
15410  *              |                |
15411  *              +-->-------------+
15412  *              bbj_cond(true)
15413  *
15414  *     -----------------------------------------
15415  *
15416  *     S0;
15417  *     C ? NOP : F;
15418  *     S1;
15419  *
15420  *     Generates ===>
15421  *
15422  *                false
15423  *     S0 -->-- C -->-- F -->-- S1
15424  *              |               |
15425  *              +-->------------+
15426  *              bbj_cond(true)
15427  *
15428  *  If the qmark assigns to a variable, then create tmps for "then"
15429  *  and "else" results and assign the temp to the variable as a writeback step.
15430  */
15431 void Compiler::fgExpandQmarkStmt(BasicBlock* block, GenTreePtr stmt)
15432 {
15433     GenTreePtr expr = stmt->gtStmt.gtStmtExpr;
15434
15435     // Retrieve the Qmark node to be expanded.
15436     GenTreePtr dst = nullptr;
15437     GenTreePtr qmark = fgGetTopLevelQmark(expr, &dst);
15438     if (qmark == nullptr)
15439     {
15440         return;
15441     }
15442
15443     if (qmark->gtFlags & GTF_QMARK_CAST_INSTOF)
15444     {
15445         fgExpandQmarkForCastInstOf(block, stmt);
15446         return;
15447     }
15448
15449 #ifdef DEBUG
15450     if (verbose)
15451     {
15452         printf("\nExpanding top-level qmark in BB%02u (before)\n", block->bbNum);
15453         fgDispBasicBlocks(block, block, true);
15454     }
15455 #endif // DEBUG
15456
15457     // Retrieve the operands.
15458     GenTreePtr condExpr  = qmark->gtGetOp1();
15459     GenTreePtr trueExpr  = qmark->gtGetOp2()->AsColon()->ThenNode();
15460     GenTreePtr falseExpr = qmark->gtGetOp2()->AsColon()->ElseNode();
15461
15462     assert(condExpr->gtFlags & GTF_RELOP_QMARK);
15463     condExpr->gtFlags &= ~GTF_RELOP_QMARK;
15464
15465     assert(!varTypeIsFloating(condExpr->TypeGet()));
15466
15467     bool hasTrueExpr  = (trueExpr->OperGet()  != GT_NOP);
15468     bool hasFalseExpr = (falseExpr->OperGet() != GT_NOP);
15469     assert(hasTrueExpr || hasFalseExpr); // We expect to have at least one arm of the qmark!
15470
15471     // Create remainder, cond and "else" blocks. After this, the blocks are in this order:
15472     //     block ... condBlock ... elseBlock ... remainderBlock
15473     //
15474     // We need to remember flags that exist on 'block' that we want to propagate to 'remainderBlock',
15475     // if they are going to be cleared by fgSplitBlockAfterStatement(). We currently only do this only
15476     // for the GC safe point bit, the logic being that if 'block' was marked gcsafe, then surely
15477     // remainderBlock will still be GC safe.
15478     unsigned propagateFlags = block->bbFlags & BBF_GC_SAFE_POINT;
15479     BasicBlock* remainderBlock = fgSplitBlockAfterStatement(block, stmt);
15480     fgRemoveRefPred(remainderBlock, block); // We're going to put more blocks between block and remainderBlock.
15481
15482     BasicBlock* condBlock      = fgNewBBafter(BBJ_COND, block, true);
15483     BasicBlock* elseBlock      = fgNewBBafter(BBJ_NONE, condBlock, true);
15484
15485     // These blocks are only internal if 'block' is (but they've been set as internal by fgNewBBafter).
15486     // If they're not internal, mark them as imported to avoid asserts about un-imported blocks.
15487     if ((block->bbFlags & BBF_INTERNAL) == 0)
15488     {
15489         condBlock->bbFlags &= ~BBF_INTERNAL;
15490         elseBlock->bbFlags &= ~BBF_INTERNAL;
15491         condBlock->bbFlags |=  BBF_IMPORTED;
15492         elseBlock->bbFlags |=  BBF_IMPORTED;
15493     }
15494
15495     remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | propagateFlags;
15496
15497     condBlock->inheritWeight(block);
15498
15499     fgAddRefPred(condBlock, block);
15500     fgAddRefPred(elseBlock, condBlock);
15501     fgAddRefPred(remainderBlock, elseBlock);
15502
15503     BasicBlock* thenBlock = nullptr;
15504     if (hasTrueExpr && hasFalseExpr)
15505     {
15506         //                       bbj_always
15507         //                       +---->------+
15508         //                 false |           |
15509         //     S0 -->-- ~C -->-- T   F -->-- S1
15510         //              |            |
15511         //              +--->--------+
15512         //              bbj_cond(true)
15513         //
15514         gtReverseCond(condExpr);
15515         condBlock->bbJumpDest = elseBlock;
15516
15517         thenBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true);
15518         thenBlock->bbJumpDest = remainderBlock;
15519         if ((block->bbFlags & BBF_INTERNAL) == 0)
15520         {
15521             thenBlock->bbFlags &= ~BBF_INTERNAL;
15522             thenBlock->bbFlags |=  BBF_IMPORTED;
15523         }
15524
15525         elseBlock->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
15526
15527         fgAddRefPred(thenBlock, condBlock);
15528         fgAddRefPred(remainderBlock, thenBlock);
15529
15530         thenBlock->inheritWeightPercentage(condBlock, 50);
15531         elseBlock->inheritWeightPercentage(condBlock, 50);
15532     }
15533     else if (hasTrueExpr)
15534     {
15535         //                 false
15536         //     S0 -->-- ~C -->-- T -->-- S1
15537         //              |                |
15538         //              +-->-------------+
15539         //              bbj_cond(true)
15540         //
15541         gtReverseCond(condExpr);
15542         condBlock->bbJumpDest = remainderBlock;
15543         fgAddRefPred(remainderBlock, condBlock);
15544         // Since we have no false expr, use the one we'd already created.
15545         thenBlock = elseBlock;
15546         elseBlock = nullptr;
15547
15548         thenBlock->inheritWeightPercentage(condBlock, 50);
15549     }
15550     else if (hasFalseExpr)
15551     {
15552         //                false
15553         //     S0 -->-- C -->-- F -->-- S1
15554         //              |               |
15555         //              +-->------------+
15556         //              bbj_cond(true)
15557         //
15558         condBlock->bbJumpDest = remainderBlock;
15559         fgAddRefPred(remainderBlock, condBlock);
15560
15561         elseBlock->inheritWeightPercentage(condBlock, 50);
15562     }
15563
15564     GenTreePtr jmpTree = gtNewOperNode(GT_JTRUE, TYP_VOID, qmark->gtGetOp1());
15565     GenTreePtr jmpStmt = fgNewStmtFromTree(jmpTree, stmt->gtStmt.gtStmtILoffsx);
15566     fgInsertStmtAtEnd(condBlock, jmpStmt);
15567
15568     // Remove the original qmark statement.
15569     fgRemoveStmt(block, stmt);
15570
15571     // Since we have top level qmarks, we either have a dst for it in which case
15572     // we need to create tmps for true and falseExprs, else just don't bother
15573     // assigning.
15574     unsigned lclNum = BAD_VAR_NUM;
15575     if (dst != nullptr)
15576     {
15577         assert(dst->gtOper == GT_LCL_VAR);
15578         lclNum = dst->gtLclVar.gtLclNum;
15579     }
15580     else
15581     {
15582         assert(qmark->TypeGet() == TYP_VOID);
15583     }
15584
15585     if (hasTrueExpr)
15586     {
15587         if (dst != nullptr)
15588         {
15589             trueExpr = gtNewTempAssign(lclNum, trueExpr);
15590         }
15591         GenTreePtr trueStmt = fgNewStmtFromTree(trueExpr, stmt->gtStmt.gtStmtILoffsx);
15592         fgInsertStmtAtEnd(thenBlock, trueStmt);
15593     }
15594
15595     // Assign the falseExpr into the dst or tmp, insert in elseBlock
15596     if (hasFalseExpr)
15597     {
15598         if (dst != nullptr)
15599         {
15600             falseExpr = gtNewTempAssign(lclNum, falseExpr);
15601         }
15602         GenTreePtr falseStmt = fgNewStmtFromTree(falseExpr, stmt->gtStmt.gtStmtILoffsx);
15603         fgInsertStmtAtEnd(elseBlock, falseStmt);
15604     }
15605
15606 #ifdef DEBUG
15607     if (verbose)
15608     {
15609         printf("\nExpanding top-level qmark in BB%02u (after)\n", block->bbNum);
15610         fgDispBasicBlocks(block, remainderBlock, true);
15611     }
15612 #endif // DEBUG
15613 }
15614
15615 /*****************************************************************************
15616  *
15617  *  Expand GT_QMARK nodes from the flow graph into basic blocks.
15618  *
15619  */
15620
15621 void Compiler::fgExpandQmarkNodes()
15622 {
15623     if (compQmarkUsed)
15624     {
15625         for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
15626         {
15627             for (GenTreePtr stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
15628             {
15629                 GenTreePtr expr = stmt->gtStmt.gtStmtExpr;
15630 #ifdef DEBUG
15631                 fgPreExpandQmarkChecks(expr);
15632 #endif
15633                 fgExpandQmarkStmt(block, stmt);
15634             }
15635         }
15636 #ifdef DEBUG
15637         fgPostExpandQmarkChecks();
15638 #endif
15639     }
15640     compQmarkRationalized = true;
15641 }
15642
15643 #ifdef DEBUG
15644 /*****************************************************************************
15645  *
15646  *  Make sure we don't have any more GT_QMARK nodes.
15647  *
15648  */
15649 void Compiler::fgPostExpandQmarkChecks()
15650 {
15651     for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
15652     {
15653         for (GenTreePtr stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
15654         {
15655             GenTreePtr expr = stmt->gtStmt.gtStmtExpr;
15656             fgWalkTreePre(&expr, Compiler::fgAssertNoQmark, NULL);
15657         }
15658     }
15659 }
15660 #endif
15661
15662 /*****************************************************************************
15663  *
15664  *  Transform all basic blocks for codegen.
15665  */
15666
15667 void                Compiler::fgMorph()
15668 {
15669     noway_assert(!compIsForInlining()); // Inlinee's compiler should never reach here.
15670
15671     fgOutgoingArgTemps = nullptr;
15672
15673 #ifdef DEBUG
15674     if  (verbose)
15675         printf("*************** In fgMorph()\n");
15676     if  (verboseTrees)
15677         fgDispBasicBlocks(true);
15678 #endif // DEBUG
15679
15680     // Insert call to class constructor as the first basic block if
15681     // we were asked to do so.
15682     if (info.compCompHnd->initClass(NULL /* field */, info.compMethodHnd /* method */,
15683             impTokenLookupContextHandle /* context */) & CORINFO_INITCLASS_USE_HELPER)
15684     {
15685         fgEnsureFirstBBisScratch();
15686         fgInsertStmtAtBeg(fgFirstBB, fgInitThisClass());
15687     }
15688
15689 #ifdef DEBUG
15690     if (opts.compGcChecks)
15691     {
15692         for (unsigned i = 0; i < info.compArgsCount; i++)
15693         {
15694             if (lvaTable[i].TypeGet() == TYP_REF)
15695             {
15696                 // confirm that the argument is a GC pointer (for debugging (GC stress))
15697                 GenTreePtr op = gtNewLclvNode(i, TYP_REF);
15698                 GenTreeArgList* args = gtNewArgList(op);
15699                 op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, 0, args);
15700
15701                 fgEnsureFirstBBisScratch();
15702                 fgInsertStmtAtEnd(fgFirstBB, op);
15703             }
15704         }
15705     }
15706
15707     if (opts.compStackCheckOnRet)
15708     {
15709         lvaReturnEspCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("ReturnEspCheck"));
15710         lvaTable[lvaReturnEspCheck].lvType = TYP_INT;
15711     }
15712
15713     if (opts.compStackCheckOnCall)
15714     {
15715         lvaCallEspCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("CallEspCheck"));
15716         lvaTable[lvaCallEspCheck].lvType = TYP_INT;
15717     }
15718 #endif // DEBUG
15719
15720     /* Filter out unimported BBs */
15721
15722     fgRemoveEmptyBlocks();
15723
15724     /* Add any internal blocks/trees we may need */
15725
15726     fgAddInternal();
15727
15728 #if OPT_BOOL_OPS
15729     fgMultipleNots = false;
15730 #endif
15731
15732 #ifdef DEBUG
15733     /* Inliner could add basic blocks. Check that the flowgraph data is up-to-date */
15734     fgDebugCheckBBlist(false, false);
15735 #endif // DEBUG
15736
15737     /* Inline */
15738     fgInline();
15739 #if 0
15740     JITDUMP("trees after inlining\n");
15741     DBEXEC(VERBOSE, fgDispBasicBlocks(true));
15742 #endif
15743
15744     RecordStateAtEndOfInlining();  // Record "start" values for post-inlining cycles and elapsed time.
15745
15746 #ifdef DEBUG
15747     /* Inliner could add basic blocks. Check that the flowgraph data is up-to-date */
15748     fgDebugCheckBBlist(false, false);
15749 #endif // DEBUG
15750
15751     /* For x64 and ARM64 we need to mark irregular parameters early so that they don't get promoted */
15752     fgMarkImplicitByRefArgs();
15753
15754     /* Promote struct locals if necessary */
15755     fgPromoteStructs();
15756
15757     /* Now it is the time to figure out what locals have address-taken. */
15758     fgMarkAddressExposedLocals();
15759
15760 #ifdef DEBUG
15761     /* Now that locals have address-taken marked, we can safely apply stress. */
15762     lvaStressLclFld();
15763     fgStress64RsltMul();
15764 #endif // DEBUG
15765
15766     /* Morph the trees in all the blocks of the method */
15767
15768     fgMorphBlocks();
15769
15770 #if 0
15771     JITDUMP("trees after fgMorphBlocks\n");
15772     DBEXEC(VERBOSE, fgDispBasicBlocks(true));
15773 #endif
15774
15775     /* Decide the kind of code we want to generate */
15776
15777     fgSetOptions();
15778
15779     fgExpandQmarkNodes();
15780
15781 #ifdef DEBUG
15782     compCurBB = 0;
15783 #endif // DEBUG
15784 }
15785
15786
15787 /*****************************************************************************
15788  *
15789  *  Promoting struct locals
15790  */
15791 void                Compiler::fgPromoteStructs()
15792 {
15793 #ifdef DEBUG
15794     if  (verbose)
15795         printf("*************** In fgPromoteStructs()\n");
15796 #endif // DEBUG
15797
15798     if (!opts.OptEnabled(CLFLG_STRUCTPROMOTE))
15799         return;
15800
15801     if (fgNoStructPromotion)
15802         return;
15803
15804 #if 0
15805     // The code in this #if has been useful in debugging struct promotion issues, by
15806     // enabling selective enablement of the struct promotion optimization according to
15807     // method hash.
15808 #ifdef DEBUG
15809     unsigned methHash = info.compMethodHash();
15810     char* lostr = getenv("structpromohashlo");
15811     unsigned methHashLo = 0;
15812     if (lostr != NULL)
15813     {
15814         sscanf_s(lostr, "%x", &methHashLo);
15815     }
15816     char* histr = getenv("structpromohashhi");
15817     unsigned methHashHi = UINT32_MAX;
15818     if (histr != NULL)
15819     {
15820         sscanf_s(histr, "%x", &methHashHi);
15821     }
15822     if (methHash < methHashLo || methHash > methHashHi)
15823     {
15824         return;
15825     }
15826     else
15827     {
15828         printf("Promoting structs for method %s, hash = 0x%x.\n",
15829                info.compFullName, info.compMethodHash());
15830         printf("");         // in our logic this causes a flush
15831     }
15832 #endif // DEBUG
15833 #endif // 0
15834
15835     if (info.compIsVarArgs)
15836         return;
15837
15838     if (getNeedsGSSecurityCookie())
15839         return;
15840
15841     // The lvaTable might grow as we grab temps. Make a local copy here.
15842
15843     unsigned        startLvaCount = lvaCount;
15844
15845     //
15846     // Loop through the original lvaTable. Looking for struct locals to be promoted.
15847     //
15848
15849     lvaStructPromotionInfo structPromotionInfo;
15850     bool tooManyLocals = false;
15851
15852     for (unsigned lclNum = 0;
15853          lclNum < startLvaCount;
15854          lclNum++)
15855     {
15856         // Whether this var got promoted
15857         bool promotedVar = false;
15858         LclVarDsc*  varDsc = &lvaTable[lclNum];
15859
15860 #ifdef FEATURE_SIMD
15861         if (varDsc->lvSIMDType && varDsc->lvUsedInSIMDIntrinsic)
15862         {
15863             // If we have marked this as lvUsedInSIMDIntrinsic, then we do not want to promote
15864             // its fields.  Instead, we will attempt to enregister the entire struct.
15865             varDsc->lvRegStruct = true;
15866         }
15867         else
15868 #endif //FEATURE_SIMD
15869         // Don't promote if we have reached the tracking limit.
15870         if (lvaHaveManyLocals())
15871         {
15872             // Print the message first time when we detected this condition
15873             if (!tooManyLocals)
15874             {
15875                 JITDUMP("Stopped promoting struct fields, due to too many locals.\n");
15876             }
15877             tooManyLocals = true;
15878         }
15879 #if !FEATURE_MULTIREG_STRUCT_PROMOTE
15880         else if (varDsc->lvIsMultiRegArgOrRet)
15881         {
15882             JITDUMP("Skipping V%02u: marked lvIsMultiRegArgOrRet.\n", lclNum);
15883         }
15884 #endif // !FEATURE_MULTIREG_STRUCT_PROMOTE
15885         else if (varTypeIsStruct(varDsc))
15886         {
15887             lvaCanPromoteStructVar(lclNum, &structPromotionInfo);
15888             bool canPromote = structPromotionInfo.canPromote;            
15889
15890             // We start off with shouldPromote same as canPromote.
15891             // Based on further profitablity checks done below, shouldPromote
15892             // could be set to false.
15893             bool shouldPromote = canPromote;
15894
15895             if (canPromote)
15896             {
15897                 
15898                 // We *can* promote; *should* we promote?
15899                 // We should only do so if promotion has potential savings.  One source of savings
15900                 // is if a field of the struct is accessed, since this access will be turned into
15901                 // an access of the corresponding promoted field variable.  Even if there are no
15902                 // field accesses, but only block-level operations on the whole struct, if the struct
15903                 // has only one or two fields, then doing those block operations field-wise is probably faster
15904                 // than doing a whole-variable block operation (e.g., a hardware "copy loop" on x86).
15905                 // So if no fields are accessed independently, and there are three or more fields, 
15906                 // then do not promote.
15907                 if (structPromotionInfo.fieldCnt > 2 && !varDsc->lvFieldAccessed)
15908                 {
15909                     JITDUMP("Not promoting promotable struct local V%02u: #fields = %d, fieldAccessed = %d.\n",
15910                         lclNum, structPromotionInfo.fieldCnt, varDsc->lvFieldAccessed);
15911                     shouldPromote = false;
15912                 }
15913 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
15914                 // TODO-PERF - Only do this when the LclVar is used in an argument context
15915                 // TODO-ARM64 - HFA support should also eliminate the need for this.
15916                 // TODO-LSRA - Currently doesn't support the passing of floating point LCL_VARS in the integer registers
15917                 //
15918                 // For now we currently don't promote structs with a single float field
15919                 // Promoting it can cause us to shuffle it back and forth between the int and 
15920                 //  the float regs when it is used as a argument, which is very expensive for XARCH
15921                 //
15922                 else if ((structPromotionInfo.fieldCnt == 1) &&
15923                           varTypeIsFloating(structPromotionInfo.fields[0].fldType))
15924                 {
15925                     JITDUMP("Not promoting promotable struct local V%02u: #fields = %d because it is a struct with single float field.\n",
15926                             lclNum, structPromotionInfo.fieldCnt);
15927                     shouldPromote = false;
15928                 }
15929 #endif // _TARGET_AMD64_ || _TARGET_ARM64_
15930
15931 #if !FEATURE_MULTIREG_STRUCT_PROMOTE
15932 #if defined(_TARGET_ARM64_)
15933                 //
15934                 // For now we currently don't promote structs that could be passed in registers
15935                 //
15936                 else if (varDsc->lvIsMultiregStruct())
15937                 {
15938                     JITDUMP("Not promoting promotable struct local V%02u (size==%d): ",
15939                             lclNum, lvaLclExactSize(lclNum));
15940                     shouldPromote = false;
15941                 }
15942 #endif // _TARGET_ARM64_
15943 #endif // !FEATURE_MULTIREG_STRUCT_PROMOTE
15944                 else if (varDsc->lvIsParam)
15945                 {
15946 #if FEATURE_MULTIREG_STRUCT_PROMOTE                   
15947                     if (varDsc->lvIsMultiregStruct() &&         // Is this a variable holding a value that is passed in multiple registers?
15948                         (structPromotionInfo.fieldCnt != 2))    // Does it have exactly two fields
15949                     {
15950                         JITDUMP("Not promoting multireg struct local V%02u, because lvIsParam is true and #fields != 2\n",
15951                                 lclNum);
15952                         shouldPromote = false;
15953                     }
15954                     else
15955 #endif  // !FEATURE_MULTIREG_STRUCT_PROMOTE
15956
15957                     // TODO-PERF - Implement struct promotion for incoming multireg structs
15958                     //             Currently it hits assert(lvFieldCnt==1) in lclvar.cpp line 4417  
15959
15960                     if (structPromotionInfo.fieldCnt != 1)
15961                     {
15962                         JITDUMP("Not promoting promotable struct local V%02u, because lvIsParam is true and #fields = %d.\n",
15963                                 lclNum, structPromotionInfo.fieldCnt);
15964                         shouldPromote = false;
15965                     }
15966                 }
15967
15968                 // 
15969                 // If the lvRefCnt is zero and we have a struct promoted parameter we can end up with an extra store of the the 
15970                 // incoming register into the stack frame slot.
15971                 // In that case, we would like to avoid promortion.
15972                 // However we haven't yet computed the lvRefCnt values so we can't do that.
15973                 // 
15974
15975 #if 0
15976                 // Often-useful debugging code: if you've narrowed down a struct-promotion problem to a single
15977                 // method, this allows you to select a subset of the vars to promote (by 1-based ordinal number).
15978                 static int structPromoVarNum = 0;
15979                 structPromoVarNum++;
15980                 if (atoi(getenv("structpromovarnumlo")) <= structPromoVarNum && structPromoVarNum <= atoi(getenv("structpromovarnumhi")))
15981 #endif // 0
15982
15983                 if (shouldPromote)
15984                 {
15985                     assert(canPromote);
15986
15987                     // Promote the this struct local var.
15988                     lvaPromoteStructVar(lclNum, &structPromotionInfo);
15989                     promotedVar = true;
15990
15991 #ifdef _TARGET_ARM_
15992                     if (structPromotionInfo.requiresScratchVar)
15993                     {
15994                         // Ensure that the scratch variable is allocated, in case we
15995                         // pass a promoted struct as an argument.
15996                         if (lvaPromotedStructAssemblyScratchVar == BAD_VAR_NUM)
15997                         {
15998                             lvaPromotedStructAssemblyScratchVar =
15999                                 lvaGrabTempWithImplicitUse(false DEBUGARG("promoted struct assembly scratch var."));
16000                             lvaTable[lvaPromotedStructAssemblyScratchVar].lvType = TYP_I_IMPL;
16001                         }
16002                     }
16003 #endif // _TARGET_ARM_
16004                 }
16005             }
16006         }
16007
16008 #ifdef FEATURE_SIMD
16009         if (!promotedVar && varDsc->lvSIMDType && !varDsc->lvFieldAccessed)
16010         {
16011             // Even if we have not used this in a SIMD intrinsic, if it is not being promoted,
16012             // we will treat it as a reg struct.
16013             varDsc->lvRegStruct = true;
16014         }
16015 #endif // FEATURE_SIMD
16016
16017     }
16018 }
16019
16020
16021 Compiler::fgWalkResult      Compiler::fgMorphStructField(GenTreePtr tree, fgWalkData* fgWalkPre)
16022 {
16023     noway_assert(tree->OperGet() == GT_FIELD);
16024     noway_assert(tree->gtFlags & GTF_GLOB_REF);
16025
16026     GenTreePtr objRef    = tree->gtField.gtFldObj;
16027
16028     /* Is this an instance data member? */
16029
16030     if  (objRef)
16031     {
16032         if (objRef->gtOper == GT_ADDR)
16033         {
16034             GenTreePtr obj =  objRef->gtOp.gtOp1;
16035
16036             if (obj->gtOper == GT_LCL_VAR)
16037             {
16038                 unsigned    lclNum = obj->gtLclVarCommon.gtLclNum;
16039                 LclVarDsc*  varDsc = &lvaTable[lclNum];
16040
16041                 if (varTypeIsStruct(obj))
16042                 {
16043                     if (varDsc->lvPromoted)
16044                     {
16045                         // Promoted struct
16046                         unsigned fldOffset     = tree->gtField.gtFldOffset;
16047                         unsigned fieldLclIndex = lvaGetFieldLocal(varDsc, fldOffset);
16048                         noway_assert(fieldLclIndex != BAD_VAR_NUM);
16049
16050                         tree->SetOper(GT_LCL_VAR);
16051                         tree->gtLclVarCommon.SetLclNum(fieldLclIndex);
16052                         tree->gtType   = lvaTable[fieldLclIndex].TypeGet();
16053                         tree->gtFlags &= GTF_NODE_MASK;
16054                         tree->gtFlags &= ~GTF_GLOB_REF;
16055
16056                         GenTreePtr parent = fgWalkPre->parentStack->Index(1);
16057                         if ((parent->gtOper == GT_ASG) &&  (parent->gtOp.gtOp1 == tree))
16058                         {
16059                             tree->gtFlags |= GTF_VAR_DEF;
16060                             tree->gtFlags |= GTF_DONT_CSE;
16061                         }
16062 #ifdef DEBUG
16063                         if (verbose)
16064                         {
16065                             printf("Replacing the field in promoted struct with a local var:\n");
16066                             fgWalkPre->printModified = true;
16067                         }
16068 #endif // DEBUG
16069                         return WALK_SKIP_SUBTREES;
16070                     }
16071                 }
16072                 else
16073                 {
16074                     // Normed struct
16075                     // A "normed struct" is a struct that the VM tells us is a basic type. This can only happen if
16076                     // the struct contains a single element, and that element is 4 bytes (on x64 it can also be 8 bytes).
16077                     // Normally, the type of the local var and the type of GT_FIELD are equivalent. However, there
16078                     // is one extremely rare case where that won't be true. An enum type is a special value type
16079                     // that contains exactly one element of a primitive integer type (that, for CLS programs is named "value__").
16080                     // The VM tells us that a local var of that enum type is the primitive type of the enum's single field.
16081                     // It turns out that it is legal for IL to access this field using ldflda or ldfld. For example:
16082                     //
16083                     //  .class public auto ansi sealed mynamespace.e_t extends [mscorlib]System.Enum
16084                     //  {
16085                     //    .field public specialname rtspecialname int16 value__
16086                     //    .field public static literal valuetype mynamespace.e_t one = int16(0x0000)
16087                     //  }
16088                     //  .method public hidebysig static void  Main() cil managed
16089                     //  {
16090                     //     .locals init (valuetype mynamespace.e_t V_0)
16091                     //     ...
16092                     //     ldloca.s   V_0
16093                     //     ldflda     int16 mynamespace.e_t::value__
16094                     //     ...
16095                     //  }
16096                     //
16097                     // Normally, compilers will not generate the ldflda, since it is superfluous.
16098                     //
16099                     // In the example, the lclVar is short, but the JIT promotes all trees using this local to the
16100                     // "actual type", that is, INT. But the GT_FIELD is still SHORT. So, in the case of a type
16101                     // mismatch like this, don't do this morphing. The local var may end up getting marked as
16102                     // address taken, and the appropriate SHORT load will be done from memory in that case.
16103
16104                     if (tree->TypeGet() == obj->TypeGet())
16105                     {
16106                         tree->ChangeOper(GT_LCL_VAR);
16107                         tree->gtLclVarCommon.SetLclNum(lclNum);
16108                         tree->gtFlags &= GTF_NODE_MASK;
16109
16110                         GenTreePtr parent = fgWalkPre->parentStack->Index(1);
16111                         if ((parent->gtOper == GT_ASG) && (parent->gtOp.gtOp1 == tree))
16112                         {
16113                             tree->gtFlags |= GTF_VAR_DEF;
16114                             tree->gtFlags |= GTF_DONT_CSE;
16115                         }
16116 #ifdef DEBUG
16117                         if (verbose)
16118                         {
16119                             printf("Replacing the field in normed struct with the local var:\n");
16120                             fgWalkPre->printModified = true;
16121                         }
16122 #endif // DEBUG
16123                         return WALK_SKIP_SUBTREES;
16124                     }
16125                 }
16126             }
16127         }
16128     }
16129
16130     return WALK_CONTINUE;
16131 }
16132
16133 Compiler::fgWalkResult      Compiler::fgMorphLocalField(GenTreePtr tree, fgWalkData* fgWalkPre)
16134 {
16135     noway_assert(tree->OperGet() == GT_LCL_FLD);
16136
16137     unsigned    lclNum = tree->gtLclFld.gtLclNum;
16138     LclVarDsc*  varDsc = &lvaTable[lclNum];
16139
16140     if (varTypeIsStruct(varDsc) && (varDsc->lvPromoted))
16141     {
16142         // Promoted struct
16143         unsigned    fldOffset = tree->gtLclFld.gtLclOffs;
16144         unsigned    fieldLclIndex = 0;
16145         LclVarDsc*  fldVarDsc = NULL;
16146
16147         if (fldOffset != BAD_VAR_NUM)
16148         {
16149             fieldLclIndex = lvaGetFieldLocal(varDsc, fldOffset);
16150             noway_assert(fieldLclIndex != BAD_VAR_NUM);
16151             fldVarDsc = &lvaTable[fieldLclIndex];
16152         }
16153
16154         if (fldOffset != BAD_VAR_NUM && genTypeSize(fldVarDsc->TypeGet()) == genTypeSize(tree->gtType)
16155 #ifdef _TARGET_X86_
16156             && varTypeIsFloating(fldVarDsc->TypeGet()) == varTypeIsFloating(tree->gtType)
16157 #endif
16158             )
16159         {
16160             // There is an existing sub-field we can use
16161             tree->gtLclFld.SetLclNum(fieldLclIndex);
16162
16163             // We need to keep the types 'compatible'.  If we can switch back to a GT_LCL_VAR
16164             assert(varTypeIsIntegralOrI(tree->TypeGet()));
16165             if (varTypeCanReg(fldVarDsc->TypeGet()))
16166             {
16167                 // If the type is integer-ish, then we can use it as-is
16168                 tree->ChangeOper(GT_LCL_VAR);
16169                 assert(tree->gtLclVarCommon.gtLclNum == fieldLclIndex);
16170                 tree->gtType = fldVarDsc->TypeGet();
16171 #ifdef DEBUG
16172                 if (verbose)
16173                 {
16174                     printf("Replacing the GT_LCL_FLD in promoted struct with a local var:\n");
16175                     fgWalkPre->printModified = true;
16176                 }
16177 #endif // DEBUG
16178             }
16179
16180             GenTreePtr parent = fgWalkPre->parentStack->Index(1);
16181             if ((parent->gtOper == GT_ASG) &&  (parent->gtOp.gtOp1 == tree))
16182             {
16183                 tree->gtFlags |= GTF_VAR_DEF;
16184                 tree->gtFlags |= GTF_DONT_CSE;
16185             }
16186         }
16187         else
16188         {
16189             // There is no existing field that has all the parts that we need
16190             // So we must ensure that the struct lives in memory.
16191             lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
16192
16193 #ifdef DEBUG
16194             // We can't convert this guy to a float because he really does have his
16195             // address taken..
16196             varDsc->lvKeepType = 1;
16197 #endif // DEBUG
16198         }
16199
16200         return WALK_SKIP_SUBTREES;
16201     }
16202
16203     return WALK_CONTINUE;
16204 }
16205
16206 /*****************************************************************************
16207  *
16208  *  Mark irregular parameters.  For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
16209  *  For ARM64, this is structs larger than 16 bytes that are also not HFAs that are passed by reference.
16210  */
16211 void                Compiler::fgMarkImplicitByRefArgs()
16212 {
16213 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
16214 #ifdef DEBUG
16215     if  (verbose)
16216         printf("\n*************** In fgMarkImplicitByRefs()\n");
16217 #endif // DEBUG
16218
16219     for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
16220     {
16221         LclVarDsc* varDsc = &lvaTable[lclNum];
16222
16223         assert(!varDsc->lvPromoted);     // Called in the wrong order?
16224
16225         if (varDsc->lvIsParam && varTypeIsStruct(varDsc))
16226         {
16227             size_t size;
16228
16229             if (varDsc->lvSize() > REGSIZE_BYTES)
16230             {
16231                 size = varDsc->lvSize();
16232             }
16233             else
16234             {
16235                 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
16236                 size = info.compCompHnd->getClassSize(typeHnd);
16237             }
16238
16239
16240 #if !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
16241 #if defined(_TARGET_AMD64_)
16242             if (size > REGSIZE_BYTES || (size & (size - 1)) != 0)
16243 #elif defined(_TARGET_ARM64_)
16244             if ((size > TARGET_POINTER_SIZE) && !varDsc->lvIsMultiregStruct())
16245
16246 #endif
16247             {
16248                 // Previously nobody was ever setting lvIsParam and lvIsTemp on the same local
16249                 // So I am now using it to indicate that this is one of the weird implicit
16250                 // by ref locals.
16251                 // The address taken cleanup will look for references to locals marked like
16252                 // this, and transform them appropriately.
16253                 varDsc->lvIsTemp = 1;
16254
16255                 // Also marking them as BYREF will hide them from struct promotion.
16256                 varDsc->lvType = TYP_BYREF;
16257                 varDsc->lvRefCnt = 0;
16258
16259                 // Since this previously was a TYP_STRUCT and we have changed it to a TYP_BYREF
16260                 // make sure that the following flag is not set as these will force SSA to
16261                 // exclude tracking/enregistering these LclVars. (see fgExcludeFromSsa)
16262                 //                
16263                 varDsc->lvOverlappingFields = 0;    // This flag could have been set, clear it.
16264
16265 #ifdef DEBUG
16266                 // This should not be converted to a double in stress mode,
16267                 // because it is really a pointer
16268                 varDsc->lvKeepType = 1;
16269
16270                 if (verbose)
16271                 {
16272                     printf("Changing the lvType for struct parameter V%02d to TYP_BYREF.\n", lclNum);
16273                 }
16274 #endif // DEBUG
16275             }
16276 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
16277         }
16278     }
16279
16280 #endif // _TARGET_AMD64_ || _TARGET_ARM64_
16281 }
16282
16283 /*****************************************************************************
16284  *
16285  *  Morph irregular parameters
16286  *    for x64 and ARM64 this means turning them into byrefs, adding extra indirs.
16287  */
16288 bool Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, fgWalkData* fgWalkPre)
16289 {
16290 #if !defined(_TARGET_AMD64_) && !defined(_TARGET_ARM64_)
16291
16292     return false;
16293
16294 #else // _TARGET_AMD64_ || _TARGET_ARM64_
16295
16296     assert((tree->gtOper == GT_LCL_VAR) ||
16297            ((tree->gtOper == GT_ADDR) && (tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)));
16298
16299     bool        isAddr     = (tree->gtOper == GT_ADDR);
16300     GenTreePtr  lclVarTree = isAddr ? tree->gtOp.gtOp1 : tree;
16301     unsigned    lclNum     = lclVarTree->gtLclVarCommon.gtLclNum;
16302     LclVarDsc*  lclVarDsc  = &lvaTable[lclNum];
16303
16304     if (!lvaIsImplicitByRefLocal(lclNum))
16305     {
16306         // We only need to tranform the 'marked' implicit by ref parameters
16307         return false;
16308     }
16309
16310     // The SIMD transformation to coalesce contiguous references to SIMD vector fields will
16311     // re-invoke the traversal to mark address-taken locals.
16312     // So, we may encounter a tree that has already been transformed to TYP_BYREF.
16313     // If we do, leave it as-is.
16314     if (!varTypeIsStruct(lclVarTree))
16315     {
16316         assert(lclVarTree->TypeGet() == TYP_BYREF);
16317         return false;
16318     }
16319
16320     // We are overloading the lvRefCnt field here because real ref counts have not been set.
16321     lclVarDsc->lvRefCnt++;
16322
16323     if (isAddr)
16324     {
16325         // change &X into just plain X
16326         tree->CopyFrom(lclVarTree, this);
16327         tree->gtType = TYP_BYREF;
16328
16329 #ifdef DEBUG
16330         if (verbose)
16331         {
16332             printf("Replacing address of implicit by ref struct parameter with byref:\n");
16333             fgWalkPre->printModified = true;
16334         }
16335 #endif // DEBUG
16336     }
16337     else
16338     {
16339         // Change X into *X
16340         // First, save the original type, then change the tree type to TYP_BYREF (otherwise we
16341         // will get an assert when we try to clone the lclVar node because the lclVar is now TYP_BYREF
16342         // and the types have to match). The reason we clone the lclVar is that we don't pass a
16343         // possible-modified tree back to the caller, so we modify the original lclVar node in-place
16344         // to the GT_IND.
16345         var_types structType = tree->gtType;
16346         lclVarTree = gtClone(tree);
16347         // Now, set the types appropriately.
16348         lclVarTree->gtType = TYP_BYREF;
16349         tree->gtType = structType;
16350         // Now, "insert" the GT_IND by changing the oper of the original node and setting its op1.
16351         tree->SetOper(GT_IND);
16352         tree->gtOp.gtOp1 = lclVarTree;
16353         // TODO-CQ: If the VM ever stops violating the ABI and passing heap references
16354         // we could remove TGTANYWHERE
16355         tree->gtFlags = ((tree->gtFlags & GTF_COMMON_MASK) | GTF_IND_TGTANYWHERE);
16356
16357 #ifdef DEBUG
16358         if (verbose)
16359         {
16360             printf("Replacing value of implicit by ref struct parameter with indir of parameter:\n");
16361             gtDispTree(tree, nullptr, nullptr, true);
16362             fgWalkPre->printModified = true;
16363         }
16364 #endif // DEBUG
16365     }
16366
16367     return true;
16368
16369 #endif // _TARGET_AMD64_ || _TARGET_ARM64_
16370
16371 }
16372
16373
16374 // An "AddrExposedContext" expresses the calling context in which an address expression occurs.
16375 enum AddrExposedContext
16376 {
16377     AXC_None,     // None of the below seen yet.
16378     AXC_Ind,      // The address being computed is to be dereferenced.
16379     AXC_Addr,     // We're computing a raw address (not dereferenced, at least not immediately).
16380     AXC_IndWide,  // A block operation dereferenced an address referencing more bytes than the address
16381                   // addresses -- if the address addresses a field of a struct local, we need to consider
16382                   // the entire local address taken (not just the field).
16383     AXC_AddrWide, // The address being computed will be dereferenced by a block operation that operates
16384                   // on more bytes than the width of the storage location addressed.  If this is a
16385                   // field of a promoted struct local, declare the entire struct local address-taken.
16386     AXC_InitBlk,  // An GT_INITBLK is the immediate parent.  The first argument is in an IND context.
16387     AXC_CopyBlk,  // An GT_COPYBLK is the immediate parent.  The first argument is in a GT_LIST, whose
16388                   // args should be evaluated in an IND context.
16389     AXC_IndAdd,   // A GT_ADD is the immediate parent, and it was evaluated in an IND contxt.
16390                   // If one arg is a constant int, evaluate the other in an IND context.  Otherwise, none.
16391 };
16392
16393 typedef ArrayStack<AddrExposedContext> AXCStack;
16394
16395 // We use pre-post to simulate passing an argument in a recursion, via a stack.
16396 Compiler::fgWalkResult      Compiler::fgMarkAddrTakenLocalsPostCB(GenTreePtr* pTree,
16397                                                                   fgWalkData* fgWalkPre)
16398 {
16399     AXCStack* axcStack = reinterpret_cast<AXCStack*>(fgWalkPre->pCallbackData);
16400     (void)axcStack->Pop();
16401     return WALK_CONTINUE;
16402 }
16403
16404 Compiler::fgWalkResult      Compiler::fgMarkAddrTakenLocalsPreCB(GenTreePtr* pTree,
16405                                                                  fgWalkData* fgWalkPre)
16406 {
16407     GenTreePtr tree = *pTree;
16408     Compiler*  comp = fgWalkPre->compiler;
16409     AXCStack*  axcStack = reinterpret_cast<AXCStack*>(fgWalkPre->pCallbackData);
16410     AddrExposedContext axc = axcStack->Top();
16411
16412     // In some situations, we have to figure out what the effective context is in which to
16413     // evaluate the current tree, depending on which argument position it is in its parent.
16414
16415     // If the parent was an initblock, and this is its first argument, we're in
16416     // and "ind" context.
16417     switch (axc)
16418     {
16419     case AXC_InitBlk:
16420     case AXC_CopyBlk:
16421         {
16422             // In both cases, the second argument is an integer struct size.  That should have a "none" context.
16423             // The first argument is a GT_LIST.  For GT_COPYBLK, both args of the list are addresses
16424             // that are dereferenced; for GT_INITBLK, the first is.  We pass "axc" to the GT_LIST;
16425             // which will pass it to its arguments; these will decide whether they're in an Ind context
16426             // depending on "axc" and which argument they are.
16427             // A GT_INITBLK's first argument is a GT_LIST, whose first argument is an address
16428             // that should be considered to be dereferenced, and whose second argument the integer
16429             // (byte) value to fill the block with.  The second argument of the GT_INITBLK is also
16430             // an integer, the block size.
16431             GenTreePtr parent = fgWalkPre->parentStack->Index(1);
16432             if (parent->gtOp.gtOp2 == tree &&
16433                 parent->OperIsBlkOp())
16434             {
16435                 axc = AXC_None;
16436             }
16437             else if (parent->OperGet() == GT_LIST)
16438             {
16439                 genTreeOps axcOper = fgWalkPre->parentStack->Index(2)->OperGet();
16440                 assert((axc == AXC_InitBlk && axcOper == GT_INITBLK) ||
16441                        (axc == AXC_CopyBlk && GenTree::OperIsCopyBlkOp(axcOper)));
16442
16443                 // The block operation will derefence its argument(s) -- usually.  If the size of the initblk
16444                 // or copyblk exceeds the size of a storage location whose address is used as one of the
16445                 // arguments, then we have to consider that storage location (indeed, it's underlying containing
16446                 // location) to be address taken.  So get the width of the initblk or copyblk.
16447                 GenTreePtr widthNode = fgWalkPre->parentStack->Index(2)->gtOp.gtOp2;
16448                 unsigned width = UINT_MAX;  // If it's not a constant, assume it's maximally big.
16449                 if (widthNode->IsCnsIntOrI())
16450                 {
16451                     if (widthNode->IsIconHandle())
16452                     {
16453                         // If it's a handle, it must be a class handle.  We only create such block operations
16454                         // for initialization of struct types, so the type of the argument(s) will match this
16455                         // type, by construction.  Set the width to zero to make sure nothing fits in it.
16456                         assert(widthNode->IsIconHandle(GTF_ICON_CLASS_HDL));
16457                         width = 0;
16458                     }
16459                     else
16460                     {
16461                         ssize_t swidth = widthNode->gtIntConCommon.IconValue();
16462                         assert(swidth > 0); // Well-formedness of the block operation node...
16463                         width = unsigned(swidth);
16464                     }
16465                 }
16466
16467                 if (parent->gtOp.gtOp1 == tree)
16468                 {
16469                     // First argument is (potentially) dereferenced by both kinds of block operations.
16470                     if (tree->OperGet() == GT_ADDR && !comp->fgFitsInOrNotLoc(tree->gtOp.gtOp1, width))
16471                     {
16472                         axc = AXC_IndWide;
16473                     }
16474                     else
16475                     {
16476                         axc = AXC_Ind;
16477                     }
16478                 }
16479                 else if (axc == AXC_CopyBlk)
16480                 {
16481                     assert(parent->gtOp.gtOp2 == tree);
16482                     if (tree->OperGet() == GT_ADDR && !comp->fgFitsInOrNotLoc(tree->gtOp.gtOp1, width))
16483                     {
16484                         axc = AXC_IndWide;
16485                     }
16486                     else
16487                     {
16488                         axc = AXC_Ind;
16489                     }
16490                 }
16491                 else
16492                 {
16493                     axc = AXC_None;
16494                 }
16495             }
16496         }
16497         break;
16498
16499     case AXC_IndAdd:
16500         {
16501             GenTreePtr parent = fgWalkPre->parentStack->Index(1);
16502             assert(parent->OperGet() == GT_ADD);
16503             // Is one of the args a constant representing a field offset,
16504             // and is this the other?  If so, Ind context.
16505             if (parent->gtOp.gtOp1->IsCnsIntOrI() && parent->gtOp.gtOp2 == tree)
16506             {
16507                 axc = AXC_Ind;
16508             }
16509             else if (parent->gtOp.gtOp2->IsCnsIntOrI() && parent->gtOp.gtOp1 == tree)
16510             {
16511                 axc = AXC_Ind;
16512             }
16513             else
16514             {
16515                 axc = AXC_None;
16516             }
16517         }
16518         break;
16519
16520     default:
16521         break;
16522     }
16523
16524     // Now recurse properly for the tree.
16525     switch (tree->gtOper)
16526     {
16527     case GT_IND:
16528     case GT_OBJ:
16529         if (axc != AXC_Addr)
16530         {
16531             axcStack->Push(AXC_Ind);
16532         }
16533         else
16534         {
16535             axcStack->Push(AXC_None);
16536         }
16537         return WALK_CONTINUE;
16538
16539     case GT_INITBLK:
16540         axcStack->Push(AXC_InitBlk);
16541         return WALK_CONTINUE;
16542
16543     case GT_COPYOBJ:
16544     case GT_COPYBLK:
16545         axcStack->Push(AXC_CopyBlk);
16546         return WALK_CONTINUE;
16547
16548     case GT_LIST:
16549         if (axc == AXC_InitBlk || axc == AXC_CopyBlk)
16550         {
16551             axcStack->Push(axc);
16552         }
16553         else
16554         {
16555             axcStack->Push(AXC_None);
16556         }
16557         return WALK_CONTINUE;
16558
16559     case GT_INDEX:
16560         // Taking the address of an array element never takes the address of a local.
16561         axcStack->Push(AXC_None);
16562         return WALK_CONTINUE;
16563
16564     case GT_ADDR:
16565         // If we have ADDR(lcl), and "lcl" is an implicit byref parameter, fgMorphImplicitByRefArgs will
16566         // convert to just "lcl".  This is never an address-context use, since the local is already a
16567         // byref after this transformation.
16568         if (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR && comp->fgMorphImplicitByRefArgs(tree, fgWalkPre))
16569         {
16570             // Push something to keep the PostCB, which will pop it, happy.
16571             axcStack->Push(AXC_None);
16572             // In the first case, tree may no longer be a leaf, but we're done with it; is a leaf in the second case.
16573             return WALK_SKIP_SUBTREES;
16574         }
16575         // Otherwise...
16576 #ifdef FEATURE_SIMD
16577         if (tree->gtOp.gtOp1->OperGet() == GT_SIMD)
16578         {
16579             axcStack->Push(AXC_None);
16580         }
16581         else
16582 #endif // FEATURE_SIMD
16583         if (axc == AXC_Ind)
16584         {
16585             axcStack->Push(AXC_None);
16586         }
16587         else if (axc == AXC_IndWide)
16588         {
16589             axcStack->Push(AXC_AddrWide);
16590         }
16591         else
16592         {
16593             assert(axc == AXC_None);
16594             axcStack->Push(AXC_Addr);
16595         }
16596         return WALK_CONTINUE;
16597
16598     case GT_FIELD:
16599         // First, handle a couple of special cases: field of promoted struct local, field
16600         // of "normed" struct.
16601         if (comp->fgMorphStructField(tree, fgWalkPre) == WALK_SKIP_SUBTREES)
16602         {
16603             // It (may have) replaced the field with a local var or local field.  If we're in an addr context,
16604             // label it addr-taken.
16605             if (tree->OperIsLocal() && (axc == AXC_Addr || axc == AXC_AddrWide))
16606             {
16607                 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
16608                 comp->lvaSetVarAddrExposed(lclNum);
16609                 if (axc == AXC_AddrWide)
16610                 {
16611                     LclVarDsc* varDsc = &comp->lvaTable[lclNum];
16612                     if (varDsc->lvIsStructField)
16613                     {
16614                         comp->lvaSetVarAddrExposed(varDsc->lvParentLcl);
16615                     }
16616                 }
16617             }
16618             // Push something to keep the PostCB, which will pop it, happy.
16619             axcStack->Push(AXC_None);
16620             return WALK_SKIP_SUBTREES;
16621         }
16622         else
16623         {
16624             // GT_FIELD is an implicit deref.
16625             if (axc == AXC_Addr)
16626             {
16627                 axcStack->Push(AXC_None);
16628             }
16629             else if (axc == AXC_AddrWide)
16630             {
16631                 axcStack->Push(AXC_IndWide);
16632             }
16633             else
16634             {
16635                 axcStack->Push(AXC_Ind);
16636             }
16637             return WALK_CONTINUE;
16638         }
16639
16640     case GT_LCL_FLD:
16641         {
16642             assert(axc != AXC_Addr);
16643             // This recognizes certain forms, and does all the work.  In that case, returns WALK_SKIP_SUBTREES,
16644             // else WALK_CONTINUE.  We do the same here.
16645             fgWalkResult res = comp->fgMorphLocalField(tree, fgWalkPre);
16646             if (res == WALK_SKIP_SUBTREES && tree->OperGet() == GT_LCL_VAR && (axc == AXC_Addr || axc == AXC_AddrWide))
16647             {
16648                 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
16649                 comp->lvaSetVarAddrExposed(lclNum);
16650                 if (axc == AXC_AddrWide)
16651                 {
16652                     LclVarDsc* varDsc = &comp->lvaTable[lclNum];
16653                     if (varDsc->lvIsStructField)
16654                     {
16655                         comp->lvaSetVarAddrExposed(varDsc->lvParentLcl);
16656                     }
16657                 }
16658             }
16659             // Must push something; if res is WALK_SKIP_SUBTREES, doesn't matter
16660             // what, but something to be popped by the post callback.  If we're going
16661             // to analyze children, the LCL_FLD creates an Ind context, so use that.
16662             axcStack->Push(AXC_Ind);
16663             return res;
16664         }
16665
16666     case GT_LCL_VAR:
16667         // On some architectures, some arguments are passed implicitly by reference.
16668         // Modify the trees to reflect that, if this local is one of those.
16669         if (comp->fgMorphImplicitByRefArgs(tree, fgWalkPre))
16670         {
16671             // We can't be in an address context; the ADDR(lcl), where lcl is an implicit byref param, was
16672             // handled earlier.  (And we can't have added anything to this address, since it was implicit.)
16673             assert(axc != AXC_Addr);
16674         }
16675         else
16676         {
16677             if (axc == AXC_Addr || axc == AXC_AddrWide)
16678             {
16679                 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
16680                 comp->lvaSetVarAddrExposed(lclNum);
16681                 if (axc == AXC_AddrWide)
16682                 {
16683                     LclVarDsc* varDsc = &comp->lvaTable[lclNum];
16684                     if (varDsc->lvIsStructField)
16685                     {
16686                         comp->lvaSetVarAddrExposed(varDsc->lvParentLcl);
16687                     }
16688                 }
16689
16690                 // We may need to Quirk the storage size for this LCL_VAR
16691                 // some PInvoke signatures incorrectly specify a ByRef to an INT32
16692                 // when they actually write a SIZE_T or INT64
16693                 if (axc == AXC_Addr)
16694                 {
16695                     comp->gtCheckQuirkAddrExposedLclVar(tree, fgWalkPre->parentStack); 
16696                 }
16697             }
16698         }
16699         // Push something to keep the PostCB, which will pop it, happy.
16700         axcStack->Push(AXC_None);
16701         // In the first case, tree may no longer be a leaf, but we're done with it; is a leaf in the second case.
16702         return WALK_SKIP_SUBTREES;
16703
16704     case GT_ADD:
16705         assert(axc != AXC_Addr);
16706         // See below about treating pointer operations as wider indirection.
16707         if (tree->gtOp.gtOp1->gtType == TYP_BYREF || tree->gtOp.gtOp2->gtType == TYP_BYREF)
16708         {
16709             axcStack->Push(AXC_IndWide);
16710         }
16711         else if (axc == AXC_Ind)
16712         {
16713             // Let the children know that the parent was a GT_ADD, to be evaluated in an IND context.
16714             // If it's an add of a constant and an address, and the constant represents a field,
16715             // then we'll evaluate the address argument in an Ind context; otherwise, the None context.
16716             axcStack->Push(AXC_IndAdd);
16717         }
16718         else
16719         {
16720             axcStack->Push(axc);
16721         }
16722         return WALK_CONTINUE;
16723
16724     // !!! Treat Pointer Operations as Wider Indirection
16725     //
16726     // If we are performing pointer operations, make sure we treat that as equivalent to a wider
16727     // indirection. This is because the pointers could be pointing to the address of struct fields
16728     // and could be used to perform operations on the whole struct or passed to another method.
16729     // 
16730     // When visiting a node in this pre-order walk, we do not know if we would in the future
16731     // encounter a GT_ADDR of a GT_FIELD below.
16732     //
16733     // Note: GT_ADDR of a GT_FIELD is always a TYP_BYREF.
16734     // So let us be conservative and treat TYP_BYREF operations as AXC_IndWide and propagate a
16735     // wider indirection context down the expr tree.
16736     //
16737     // Example, in unsafe code,
16738     //
16739     //   IL_000e  12 00             ldloca.s     0x0
16740     //   IL_0010  7c 02 00 00 04    ldflda       0x4000002
16741     //   IL_0015  12 00             ldloca.s     0x0
16742     //   IL_0017  7c 01 00 00 04    ldflda       0x4000001
16743     //   IL_001c  59                sub
16744     //
16745     // When visiting the GT_SUB node, if the types of either of the GT_SUB's operand are BYREF, then
16746     // consider GT_SUB to be equivalent of an AXC_IndWide.
16747     //
16748     // Similarly for pointer comparisons and pointer escaping as integers through conversions, treat
16749     // them as AXC_IndWide.
16750     //
16751     
16752     // BINOP
16753     case GT_SUB:
16754     case GT_MUL:
16755     case GT_DIV:
16756     case GT_UDIV:
16757     case GT_OR:
16758     case GT_XOR:
16759     case GT_AND:
16760     case GT_LSH:
16761     case GT_RSH:
16762     case GT_RSZ:
16763     case GT_ROL:
16764     case GT_ROR:
16765     case GT_EQ:
16766     case GT_NE:
16767     case GT_LT:
16768     case GT_LE:
16769     case GT_GT:
16770     case GT_GE:
16771     // UNOP
16772     case GT_CAST:
16773         if ((tree->gtOp.gtOp1->gtType == TYP_BYREF) || (tree->OperIsBinary() && (tree->gtOp.gtOp2->gtType == TYP_BYREF)))
16774         {
16775             axcStack->Push(AXC_IndWide);
16776             return WALK_CONTINUE;
16777         }
16778         __fallthrough;
16779
16780     default:
16781         // To be safe/conservative: pass Addr through, but not Ind -- otherwise, revert to "None".  We must
16782         // handle the "Ind" propogation explicitly above.
16783         if (axc == AXC_Addr || axc == AXC_AddrWide)
16784         {
16785             axcStack->Push(axc);
16786         }
16787         else
16788         {
16789             axcStack->Push(AXC_None);
16790         }
16791         return WALK_CONTINUE;
16792     }
16793 }
16794
16795 bool Compiler::fgFitsInOrNotLoc(GenTreePtr tree, unsigned width)
16796 {
16797     if (tree->TypeGet() != TYP_STRUCT)
16798     {
16799         return width <= genTypeSize(tree->TypeGet());
16800     }
16801     else if (tree->OperGet() == GT_LCL_VAR)
16802     {
16803         assert(tree->TypeGet() == TYP_STRUCT);
16804         unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
16805         return width <= lvaTable[lclNum].lvExactSize;
16806     }
16807     else if (tree->OperGet() == GT_FIELD)
16808     {
16809         CORINFO_CLASS_HANDLE fldClass = info.compCompHnd->getFieldClass (tree->gtField.gtFldHnd);
16810         return width <= info.compCompHnd->getClassSize(fldClass);
16811     }
16812     else
16813     {
16814         return false;
16815     }
16816 }
16817
16818
16819 void Compiler::fgAddFieldSeqForZeroOffset(GenTreePtr op1, FieldSeqNode* fieldSeq)
16820 {
16821     assert(op1->TypeGet() == TYP_BYREF || op1->TypeGet() == TYP_I_IMPL || op1->TypeGet() == TYP_REF);
16822
16823     switch (op1->OperGet())
16824     {
16825     case GT_ADDR:
16826         if (op1->gtOp.gtOp1->OperGet() == GT_LCL_FLD)
16827         {
16828             GenTreeLclFld* lclFld = op1->gtOp.gtOp1->AsLclFld();
16829             lclFld->gtFieldSeq = GetFieldSeqStore()->Append(lclFld->gtFieldSeq, fieldSeq);
16830         }
16831         break;
16832
16833     case GT_ADD:
16834         if (op1->gtOp.gtOp1->OperGet() == GT_CNS_INT)
16835         {
16836             FieldSeqNode* op1Fs = op1->gtOp.gtOp1->gtIntCon.gtFieldSeq;
16837             if (op1Fs != NULL)
16838             {
16839                 op1Fs = GetFieldSeqStore()->Append(op1Fs, fieldSeq);
16840                 op1->gtOp.gtOp1->gtIntCon.gtFieldSeq = op1Fs;
16841             }
16842         }
16843         else if (op1->gtOp.gtOp2->OperGet() == GT_CNS_INT)
16844         {
16845             FieldSeqNode* op2Fs = op1->gtOp.gtOp2->gtIntCon.gtFieldSeq;
16846             if (op2Fs != NULL)
16847             {
16848                 op2Fs = GetFieldSeqStore()->Append(op2Fs, fieldSeq);
16849                 op1->gtOp.gtOp2->gtIntCon.gtFieldSeq = op2Fs;
16850             }
16851         }
16852         break;
16853
16854     case GT_CNS_INT:
16855         {
16856             FieldSeqNode* op1Fs = op1->gtIntCon.gtFieldSeq;
16857             if (op1Fs != NULL)
16858             {
16859                 op1Fs = GetFieldSeqStore()->Append(op1Fs, fieldSeq);
16860                 op1->gtIntCon.gtFieldSeq = op1Fs;
16861             }
16862         }
16863         break;
16864
16865     default:
16866         // Record in the general zero-offset map.
16867         GetZeroOffsetFieldMap()->Set(op1, fieldSeq);
16868         break;
16869     }
16870 }
16871
16872 /*****************************************************************************
16873  *
16874  *  Mark address-taken locals.
16875  */
16876
16877 void                Compiler::fgMarkAddressExposedLocals()
16878 {
16879 #ifdef DEBUG
16880     if  (verbose)
16881         printf("\n*************** In fgMarkAddressExposedLocals()\n");
16882 #endif // DEBUG
16883
16884     BasicBlock* block = fgFirstBB;
16885     noway_assert(block);
16886
16887     do
16888     {
16889         /* Make the current basic block address available globally */
16890
16891         compCurBB = block;
16892
16893         GenTreePtr stmt;
16894
16895         for (stmt = block->bbTreeList;
16896              stmt;
16897              stmt = stmt->gtNext)
16898         {
16899             // Call Compiler::fgMarkAddrTakenLocalsCB on each node
16900             AXCStack stk(this);
16901             stk.Push(AXC_None); // We start in neither an addr or ind context.
16902             fgWalkTree(&stmt->gtStmt.gtStmtExpr,
16903                        fgMarkAddrTakenLocalsPreCB,
16904                        fgMarkAddrTakenLocalsPostCB,
16905                        &stk);
16906         }
16907
16908         block = block->bbNext;
16909
16910     } while (block);
16911 }
16912
16913
16914 // fgNodesMayInterfere:
16915 //   return true if moving nodes relative to each other can change the result of a computation
16916 //
16917 // args:
16918 //   read: a node which reads
16919 //   
16920
16921 bool Compiler::fgNodesMayInterfere(GenTree* write, GenTree* read)
16922 {
16923     LclVarDsc* srcVar = nullptr;
16924     bool srcAliased = false;
16925     bool dstAliased = false;
16926
16927     bool readIsIndir  = read->OperIsIndir()  || read->OperIsImplicitIndir();
16928     bool writeIsIndir = write->OperIsIndir() || write->OperIsImplicitIndir();
16929
16930     if (read->OperIsLocal())
16931         srcVar = &lvaTable[read->gtLclVarCommon.gtLclNum];
16932     
16933     if (writeIsIndir)
16934     {
16935         if (srcVar && srcVar->lvAddrExposed)
16936             return true;
16937         else if (readIsIndir)
16938             return true;
16939         return false;
16940     }
16941     else if (write->OperIsLocal())
16942     {
16943         LclVarDsc* dstVar = &lvaTable[write->gtLclVarCommon.gtLclNum];
16944         if (readIsIndir)
16945         {
16946             return dstVar->lvAddrExposed;
16947         }
16948         else if (read->OperIsLocal())
16949         {
16950             if (read->gtLclVarCommon.gtLclNum == write->gtLclVarCommon.gtLclNum)
16951                 return true;
16952             return false;
16953         }
16954         else
16955         {
16956             return false;
16957         }
16958     }
16959     else
16960     {
16961         return false;
16962     }
16963 }
16964
16965 /** This predicate decides whether we will fold a tree with the structure:
16966  *  x = x <op> y where x could be any arbitrary expression into
16967  *  x <op>= y.
16968  *
16969  *  This modification is only performed when the target architecture supports
16970  *  complex addressing modes.  In the case of ARM for example, this transformation
16971  *  yields no benefit.
16972  *
16973  *  In case this functions decides we can proceed to fold into an assignment operator
16974  *  we need to inspect whether the operator is commutative to tell fgMorph whether we need to
16975  *  reverse the tree due to the fact we saw x = y <op> x and we want to fold that into
16976  *  x <op>= y because the operator property.
16977  */
16978 bool                Compiler::fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse)
16979 {
16980 #if CPU_LOAD_STORE_ARCH
16981     /* In the case of a load/store architecture, there's no gain by doing any of this, we bail. */
16982     return false;
16983 #elif !defined(LEGACY_BACKEND)
16984     return false;
16985 #else // defined(LEGACY_BACKEND)
16986
16987
16988     GenTreePtr op1 = tree->gtOp.gtOp1;
16989     GenTreePtr op2 = tree->gtGetOp2();
16990     genTreeOps cmop = op2->OperGet();
16991
16992     /* Is the destination identical to the first RHS sub-operand? */
16993     if  (GenTree::Compare(op1, op2->gtOp.gtOp1))
16994     {
16995         /*
16996         Do not transform the following tree
16997
16998         [0024CFA4] -----------               const     int    1
16999         [0024CFDC] ----G------               |         int
17000         [0024CF5C] -----------               lclVar    ubyte  V01 tmp0
17001         [0024D05C] -A--G------               =         ubyte
17002         [0024D014] D------N---               lclVar    ubyte  V01 tmp0
17003
17004         to
17005
17006         [0024CFA4] -----------               const     int    1
17007         [0024D05C] -A--G------               |=        ubyte
17008         [0024D014] U------N---               lclVar    ubyte  V01 tmp0
17009
17010         , when V01 is a struct field local.
17011         */
17012
17013         if (op1->gtOper == GT_LCL_VAR       &&
17014             varTypeIsSmall(op1->TypeGet())  &&
17015             op1->TypeGet() != op2->gtOp.gtOp2->TypeGet())
17016         {
17017             unsigned     lclNum = op1->gtLclVarCommon.gtLclNum;
17018             LclVarDsc*   varDsc = lvaTable + lclNum;
17019
17020             if (varDsc->lvIsStructField)
17021             {
17022                 return false;
17023             }
17024         }
17025
17026         *bReverse = false;
17027         return true;
17028     }
17029     else if (GenTree::OperIsCommutative(cmop))
17030     {
17031         /* For commutative ops only, check for "a = x <op> a" */
17032
17033         /* Should we be doing this at all? */
17034         if  ((opts.compFlags & CLFLG_TREETRANS) == 0)
17035         {
17036             return false;
17037         }
17038
17039         /* Can we swap the operands to cmop ... */
17040         if ((op2->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT) &&
17041             (op2->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT)    )
17042         {
17043             // Both sides must have side effects to prevent swap */
17044             return false;
17045         }
17046
17047         /* Is the destination identical to the second RHS sub-operand? */
17048         if  (GenTree::Compare(op1, op2->gtOp.gtOp2))
17049         {
17050             *bReverse = true;
17051             return true;
17052         }
17053     }
17054     return false;
17055 #endif // defined(LEGACY_BACKEND)
17056 }
17057
17058 // Static variables.
17059 Compiler::MorphAddrContext Compiler::s_CopyBlockMAC(Compiler::MACK_CopyBlock);
17060
17061 #ifdef FEATURE_SIMD
17062
17063 //-----------------------------------------------------------------------------------
17064 // fgMorphCombineSIMDFieldAssignments:
17065 //  If the RHS of the input stmt is a read for simd vector X Field, then this function
17066 //  will keep reading next few stmts based on the vector size(2, 3, 4). 
17067 //  If the next stmts LHS are located contiguous and RHS are also located 
17068 //  contiguous, then we replace those statements with a copyblk.
17069 //
17070 // Argument:
17071 //  block - BasicBlock*. block which stmt belongs to
17072 //  stmt  - GenTreeStmt*. the stmt node we want to check
17073 //
17074 // return value:
17075 //  if this funciton successfully optimized the stmts, then return true. Otherwise 
17076 //  return false;
17077
17078 bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreePtr stmt)
17079 {
17080
17081     noway_assert(stmt->gtOper == GT_STMT);
17082     GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
17083     assert(tree->OperGet() == GT_ASG);
17084
17085     GenTreePtr originalLHS = tree->gtOp.gtOp1;
17086     GenTreePtr prevLHS = tree->gtOp.gtOp1;
17087     GenTreePtr prevRHS = tree->gtOp.gtOp2;
17088     unsigned index = 0;
17089     var_types baseType = TYP_UNKNOWN;
17090     unsigned simdSize = 0;
17091     GenTreePtr simdStructNode = getSIMDStructFromField(prevRHS, &baseType, &index, &simdSize, true);
17092
17093     if (simdStructNode == nullptr ||
17094         index != 0                ||
17095         baseType != TYP_FLOAT)
17096     {
17097         // if the RHS is not from a SIMD vector field X, then there is no need to check further.
17098         return false;
17099     }
17100
17101     int assignmentsCount = simdSize / genTypeSize(baseType) - 1;
17102     int remainingAssignments = assignmentsCount;
17103     GenTreePtr curStmt = stmt->gtNext;
17104     GenTreePtr lastStmt = stmt;
17105
17106     while (curStmt != nullptr && remainingAssignments > 0)
17107     {
17108         GenTreePtr exp = curStmt->gtStmt.gtStmtExpr;
17109         if (exp->OperGet() != GT_ASG)
17110         {
17111             break;
17112         }
17113         GenTreePtr curLHS = exp->gtGetOp1();
17114         GenTreePtr curRHS = exp->gtGetOp2();
17115
17116         if (!areArgumentsContiguous(prevLHS, curLHS) ||
17117             !areArgumentsContiguous(prevRHS, curRHS))
17118         {
17119             break;
17120         }
17121
17122         remainingAssignments--;
17123         prevLHS = curLHS;
17124         prevRHS = curRHS;
17125
17126         lastStmt = curStmt;
17127         curStmt = curStmt->gtNext;
17128     }
17129
17130     if (remainingAssignments > 0)
17131     {
17132         // if the left assignments number is bigger than zero, then this means 
17133         // that the assignments are not assgining to the contiguously memory 
17134         // locations from same vector. 
17135         return false; 
17136     }
17137 #ifdef DEBUG
17138     if (verbose)
17139     {
17140         printf("\nFound contiguous assignments from a SIMD vector to memory.\n");
17141         printf("From BB%02u, stmt", block->bbNum);
17142         printTreeID(stmt);
17143         printf(" to stmt");
17144         printTreeID(lastStmt);
17145         printf("\n");
17146     }
17147 #endif  
17148
17149
17150     for (int i = 0; i < assignmentsCount; i++)
17151     {
17152         fgRemoveStmt(block, stmt->gtNext);
17153     }
17154     
17155     GenTree* copyBlkDst = createAddressNodeForSIMDInit(originalLHS, simdSize);
17156     if (simdStructNode->OperIsLocal())
17157     {
17158         setLclRelatedToSIMDIntrinsic(simdStructNode);
17159     }
17160     GenTree* copyBlkAddr = copyBlkDst;
17161     if (copyBlkAddr->gtOper == GT_LEA)
17162     {
17163         copyBlkAddr = copyBlkAddr->AsAddrMode()->Base();
17164     }
17165     GenTreeLclVarCommon* localDst = nullptr;
17166     if (copyBlkAddr->IsLocalAddrExpr(this, &localDst, nullptr))
17167     {
17168         setLclRelatedToSIMDIntrinsic(localDst);
17169     }
17170
17171     GenTree* simdStructAddr;
17172     if (simdStructNode->TypeGet() == TYP_BYREF)
17173     {
17174         assert(simdStructNode->OperIsLocal());
17175         assert(lvaIsImplicitByRefLocal(simdStructNode->AsLclVarCommon()->gtLclNum));
17176         simdStructAddr = simdStructNode;
17177     }
17178     else
17179     {
17180         assert(varTypeIsSIMD(simdStructNode));
17181         simdStructAddr = gtNewOperNode(GT_ADDR, TYP_BYREF, simdStructNode);
17182     }
17183
17184 #ifdef DEBUG
17185     if (verbose)
17186     {
17187         printf("\nBB%02u stmt", block->bbNum);
17188         printTreeID(stmt);
17189         printf("(before)\n");
17190         gtDispTree(stmt);
17191     }
17192 #endif   
17193
17194     tree = gtNewBlkOpNode(GT_COPYBLK,
17195                         copyBlkDst,
17196                         simdStructAddr,
17197                         gtNewIconNode(simdSize),
17198                         false);
17199
17200     stmt->gtStmt.gtStmtExpr = tree;
17201     
17202     // Since we generated a new address node which didn't exist before,
17203     // we should expose this address manually here.
17204     AXCStack stk(this);
17205     stk.Push(AXC_None); 
17206     fgWalkTree(&stmt->gtStmt.gtStmtExpr,
17207         fgMarkAddrTakenLocalsPreCB,
17208         fgMarkAddrTakenLocalsPostCB,
17209         &stk);
17210
17211 #ifdef DEBUG
17212     if (verbose)
17213     {
17214         printf("\nReplaced BB%02u stmt", block->bbNum);
17215         printTreeID(stmt);
17216         printf("(after)\n");
17217         gtDispTree(stmt);
17218     }
17219 #endif    
17220     return true;
17221 }
17222
17223 #endif //FEATURE_SIMD