Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / earlyprop.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 //                                    Early Value Propagation
6 //
7 // This phase performs an SSA-based value propagation optimization that currently only applies to array
8 // lengths, runtime type handles, and explicit null checks. An SSA-based backwards tracking of local variables
9 // is performed at each point of interest, e.g., an array length reference site, a method table reference site, or
10 // an indirection.
11 // The tracking continues until an interesting value is encountered. The value is then used to rewrite
12 // the source site or the value.
13 //
14 ///////////////////////////////////////////////////////////////////////////////////////
15
16 #include "jitpch.h"
17 #include "ssabuilder.h"
18
19 bool Compiler::optDoEarlyPropForFunc()
20 {
21     bool propArrayLen  = (optMethodFlags & OMF_HAS_NEWARRAY) && (optMethodFlags & OMF_HAS_ARRAYREF);
22     bool propGetType   = (optMethodFlags & OMF_HAS_NEWOBJ) && (optMethodFlags & OMF_HAS_VTABLEREF);
23     bool propNullCheck = (optMethodFlags & OMF_HAS_NULLCHECK) != 0;
24     return propArrayLen || propGetType || propNullCheck;
25 }
26
27 bool Compiler::optDoEarlyPropForBlock(BasicBlock* block)
28 {
29     bool bbHasArrayRef  = (block->bbFlags & BBF_HAS_IDX_LEN) != 0;
30     bool bbHasVtableRef = (block->bbFlags & BBF_HAS_VTABREF) != 0;
31     bool bbHasNullCheck = (block->bbFlags & BBF_HAS_NULLCHECK) != 0;
32     return bbHasArrayRef || bbHasVtableRef || bbHasNullCheck;
33 }
34
35 //--------------------------------------------------------------------
36 // gtIsVtableRef: Return true if the tree is a method table reference.
37 //
38 // Arguments:
39 //    tree           - The input tree.
40 //
41 // Return Value:
42 //    Return true if the tree is a method table reference.
43
44 bool Compiler::gtIsVtableRef(GenTree* tree)
45 {
46     if (tree->OperGet() == GT_IND)
47     {
48         GenTree* addr = tree->AsIndir()->Addr();
49
50         if (addr->OperIsAddrMode())
51         {
52             GenTreeAddrMode* addrMode = addr->AsAddrMode();
53
54             return (!addrMode->HasIndex() && (addrMode->Base()->TypeGet() == TYP_REF));
55         }
56     }
57
58     return false;
59 }
60
61 //------------------------------------------------------------------------------
62 // getArrayLengthFromAllocation: Return the array length for an array allocation
63 //                               helper call.
64 //
65 // Arguments:
66 //    tree           - The array allocation helper call.
67 //
68 // Return Value:
69 //    Return the array length node.
70
71 GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree)
72 {
73     assert(tree != nullptr);
74
75     if (tree->OperGet() == GT_CALL)
76     {
77         GenTreeCall* call = tree->AsCall();
78
79         if (call->gtCallType == CT_HELPER)
80         {
81             if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) ||
82                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_R2R_DIRECT) ||
83                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) ||
84                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_VC) ||
85                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8))
86             {
87                 // This is an array allocation site. Grab the array length node.
88                 return gtArgEntryByArgNum(call, 1)->node;
89             }
90         }
91     }
92
93     return nullptr;
94 }
95
96 //-----------------------------------------------------------------------------
97 // getObjectHandleNodeFromAllocation: Return the type handle for an object allocation
98 //                              helper call.
99 //
100 // Arguments:
101 //    tree           - The object allocation helper call.
102 //
103 // Return Value:
104 //    Return the object type handle node.
105
106 GenTree* Compiler::getObjectHandleNodeFromAllocation(GenTree* tree)
107 {
108     assert(tree != nullptr);
109
110     if (tree->OperGet() == GT_CALL)
111     {
112         GenTreeCall* call = tree->AsCall();
113
114         if (call->gtCallType == CT_HELPER)
115         {
116             if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWFAST) ||
117                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST) ||
118                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8) ||
119                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) ||
120                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_R2R_DIRECT) ||
121                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) ||
122                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_VC) ||
123                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8))
124             {
125                 // This is an object allocation site. Return the runtime type handle node.
126                 fgArgTabEntry* argTabEntry = gtArgEntryByArgNum(call, 0);
127                 return argTabEntry->node;
128             }
129         }
130     }
131
132     return nullptr;
133 }
134
135 //------------------------------------------------------------------------------------------
136 // optEarlyProp: The entry point of the early value propagation.
137 //
138 // Notes:
139 //    This phase performs an SSA-based value propagation, including
140 //      1. Array length propagation.
141 //      2. Runtime type handle propagation.
142 //      3. Null check folding.
143 //
144 //    For array length propagation, a demand-driven SSA-based backwards tracking of constant
145 //    array lengths is performed at each array length reference site which is in form of a
146 //    GT_ARR_LENGTH node. When a GT_ARR_LENGTH node is seen, the array ref pointer which is
147 //    the only child node of the GT_ARR_LENGTH is tracked. This is only done for array ref
148 //    pointers that have valid SSA forms.The tracking is along SSA use-def chain and stops
149 //    at the original array allocation site where we can grab the array length. The
150 //    GT_ARR_LENGTH node will then be rewritten to a GT_CNS_INT node if the array length is
151 //    constant.
152 //
153 //    Similarly, the same algorithm also applies to rewriting a method table (also known as
154 //    vtable) reference site which is in form of GT_INDIR node. The base pointer, which is
155 //    an object reference pointer, is treated in the same way as an array reference pointer.
156 //
157 //    Null check folding tries to find GT_INDIR(obj + const) that GT_NULLCHECK(obj) can be folded into
158 ///   and removed. Currently, the algorithm only matches GT_INDIR and GT_NULLCHECK in the same basic block.
159
160 void Compiler::optEarlyProp()
161 {
162 #ifdef DEBUG
163     if (verbose)
164     {
165         printf("*************** In optEarlyProp()\n");
166     }
167 #endif
168
169     assert(fgSsaPassesCompleted == 1);
170
171     if (!optDoEarlyPropForFunc())
172     {
173         return;
174     }
175
176     for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
177     {
178         if (!optDoEarlyPropForBlock(block))
179         {
180             continue;
181         }
182
183         compCurBB = block;
184
185         for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr;)
186         {
187             // Preserve the next link before the propagation and morph.
188             GenTreeStmt* next = stmt->gtNextStmt;
189
190             compCurStmt = stmt;
191
192             // Walk the stmt tree in linear order to rewrite any array length reference with a
193             // constant array length.
194             bool isRewritten = false;
195             for (GenTree* tree = stmt->gtStmt.gtStmtList; tree != nullptr; tree = tree->gtNext)
196             {
197                 GenTree* rewrittenTree = optEarlyPropRewriteTree(tree);
198                 if (rewrittenTree != nullptr)
199                 {
200                     gtUpdateSideEffects(stmt, rewrittenTree);
201                     isRewritten = true;
202                     tree        = rewrittenTree;
203                 }
204             }
205
206             // Update the evaluation order and the statement info if the stmt has been rewritten.
207             if (isRewritten)
208             {
209                 gtSetStmtInfo(stmt);
210                 fgSetStmtSeq(stmt);
211             }
212
213             stmt = next;
214         }
215     }
216
217 #ifdef DEBUG
218     if (verbose)
219     {
220         JITDUMP("\nAfter optEarlyProp:\n");
221         fgDispBasicBlocks(/*dumpTrees*/ true);
222     }
223 #endif
224 }
225
226 //----------------------------------------------------------------
227 // optEarlyPropRewriteValue: Rewrite a tree to the actual value.
228 //
229 // Arguments:
230 //    tree           - The input tree node to be rewritten.
231 //
232 // Return Value:
233 //    Return a new tree if the original tree was successfully rewritten.
234 //    The containing tree links are updated.
235 //
236 GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree)
237 {
238     GenTree*    objectRefPtr = nullptr;
239     optPropKind propKind     = optPropKind::OPK_INVALID;
240
241     if (tree->OperGet() == GT_ARR_LENGTH)
242     {
243         objectRefPtr = tree->gtOp.gtOp1;
244         propKind     = optPropKind::OPK_ARRAYLEN;
245     }
246     else if (tree->OperIsIndir())
247     {
248         // optFoldNullCheck takes care of updating statement info if a null check is removed.
249         optFoldNullCheck(tree);
250
251         if (gtIsVtableRef(tree))
252         {
253             // Don't propagate type handles that are used as null checks, which are usually in
254             // form of
255             //      *  stmtExpr  void  (top level)
256             //      \--*  indir     int
257             //          \--*  lclVar    ref    V02 loc0
258             if (compCurStmt->gtStmt.gtStmtExpr == tree)
259             {
260                 return nullptr;
261             }
262
263             objectRefPtr = tree->AsIndir()->Addr();
264             propKind     = optPropKind::OPK_OBJ_GETTYPE;
265         }
266         else
267         {
268             return nullptr;
269         }
270     }
271     else
272     {
273         return nullptr;
274     }
275
276     if (!objectRefPtr->OperIsScalarLocal() || fgExcludeFromSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
277
278     {
279         return nullptr;
280     }
281
282     unsigned lclNum    = objectRefPtr->AsLclVarCommon()->GetLclNum();
283     unsigned ssaNum    = objectRefPtr->AsLclVarCommon()->GetSsaNum();
284     GenTree* actualVal = optPropGetValue(lclNum, ssaNum, propKind);
285
286     if (actualVal != nullptr)
287     {
288         assert((propKind == optPropKind::OPK_ARRAYLEN) || (propKind == optPropKind::OPK_OBJ_GETTYPE));
289         assert(actualVal->IsCnsIntOrI());
290 #if SMALL_TREE_NODES
291         assert(actualVal->GetNodeSize() == TREE_NODE_SZ_SMALL);
292 #endif
293
294         ssize_t actualConstVal = actualVal->AsIntCon()->IconValue();
295
296         if (propKind == optPropKind::OPK_ARRAYLEN)
297         {
298             if ((actualConstVal < 0) || (actualConstVal > INT32_MAX))
299             {
300                 // Don't propagate array lengths that are beyond the maximum value of a GT_ARR_LENGTH or negative.
301                 // node. CORINFO_HELP_NEWARR_1_OBJ helper call allows to take a long integer as the
302                 // array length argument, but the type of GT_ARR_LENGTH is always INT32.
303                 return nullptr;
304             }
305
306             // When replacing GT_ARR_LENGTH nodes with constants we can end up with GT_ARR_BOUNDS_CHECK
307             // nodes that have constant operands and thus can be trivially proved to be useless. It's
308             // better to remove these range checks here, otherwise they'll pass through assertion prop
309             // (creating useless (c1 < c2)-like assertions) and reach RangeCheck where they are finally
310             // removed. Common patterns like new int[] { x, y, z } benefit from this.
311
312             if ((tree->gtNext != nullptr) && tree->gtNext->OperIs(GT_ARR_BOUNDS_CHECK))
313             {
314                 GenTreeBoundsChk* check = tree->gtNext->AsBoundsChk();
315
316                 if ((check->gtArrLen == tree) && check->gtIndex->IsCnsIntOrI())
317                 {
318                     ssize_t checkConstVal = check->gtIndex->AsIntCon()->IconValue();
319                     if ((checkConstVal >= 0) && (checkConstVal < actualConstVal))
320                     {
321                         GenTree* comma = check->gtGetParent(nullptr);
322                         if ((comma != nullptr) && comma->OperIs(GT_COMMA) && (comma->gtGetOp1() == check))
323                         {
324                             GenTree* next = check->gtNext;
325                             optRemoveRangeCheck(comma, compCurStmt);
326                             // Both `tree` and `check` have been removed from the statement.
327                             // 'tree' was replaced with 'nop' or side effect list under 'comma'.
328                             return comma->gtGetOp1();
329                         }
330                     }
331                 }
332             }
333         }
334
335 #ifdef DEBUG
336         if (verbose)
337         {
338             printf("optEarlyProp Rewriting BB%02u\n", compCurBB->bbNum);
339             gtDispTree(compCurStmt);
340             printf("\n");
341         }
342 #endif
343
344         GenTree* actualValClone = gtCloneExpr(actualVal);
345
346         if (actualValClone->gtType != tree->gtType)
347         {
348             assert(actualValClone->gtType == TYP_LONG);
349             assert(tree->gtType == TYP_INT);
350             assert((actualConstVal >= 0) && (actualConstVal <= INT32_MAX));
351             actualValClone->gtType = tree->gtType;
352         }
353
354         // Propagating a constant into an array index expression requires calling
355         // LabelIndex to update the FieldSeq annotations.  EarlyProp may replace
356         // array length expressions with constants, so check if this is an array
357         // length operator that is part of an array index expression.
358         bool isIndexExpr = (tree->OperGet() == GT_ARR_LENGTH && ((tree->gtFlags & GTF_ARRLEN_ARR_IDX) != 0));
359         if (isIndexExpr)
360         {
361             actualValClone->LabelIndex(this);
362         }
363
364         DecLclVarRefCountsVisitor::WalkTree(this, tree);
365         // acutalValClone has small tree node size, it is safe to use CopyFrom here.
366         tree->ReplaceWith(actualValClone, this);
367         IncLclVarRefCountsVisitor::WalkTree(this, tree);
368
369 #ifdef DEBUG
370         if (verbose)
371         {
372             printf("to\n");
373             gtDispTree(compCurStmt);
374             printf("\n");
375         }
376 #endif
377         return tree;
378     }
379
380     return nullptr;
381 }
382
383 //-------------------------------------------------------------------------------------------
384 // optPropGetValue: Given an SSA object ref pointer, get the value needed based on valueKind.
385 //
386 // Arguments:
387 //    lclNum         - The local var number of the ref pointer.
388 //    ssaNum         - The SSA var number of the ref pointer.
389 //    valueKind      - The kind of value of interest.
390 //
391 // Return Value:
392 //    Return the corresponding value based on valueKind.
393
394 GenTree* Compiler::optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind)
395 {
396     return optPropGetValueRec(lclNum, ssaNum, valueKind, 0);
397 }
398
399 //-----------------------------------------------------------------------------------
400 // optPropGetValueRec: Given an SSA object ref pointer, get the value needed based on valueKind
401 //                     within a recursion bound.
402 //
403 // Arguments:
404 //    lclNum         - The local var number of the array pointer.
405 //    ssaNum         - The SSA var number of the array pointer.
406 //    valueKind      - The kind of value of interest.
407 //    walkDepth      - Current recursive walking depth.
408 //
409 // Return Value:
410 //    Return the corresponding value based on valueKind.
411
412 GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth)
413 {
414     if (ssaNum == SsaConfig::RESERVED_SSA_NUM)
415     {
416         return nullptr;
417     }
418
419     SSAName  ssaName(lclNum, ssaNum);
420     GenTree* value = nullptr;
421
422     // Bound the recursion with a hard limit.
423     if (walkDepth > optEarlyPropRecurBound)
424     {
425         return nullptr;
426     }
427
428     // Track along the use-def chain to get the array length
429     GenTree* treelhs = lvaTable[lclNum].GetPerSsaData(ssaNum)->m_defLoc.m_tree;
430
431     if (treelhs == nullptr)
432     {
433         // Incoming parameters or live-in variables don't have actual definition tree node
434         // for their FIRST_SSA_NUM. See SsaBuilder::RenameVariables.
435         assert(ssaNum == SsaConfig::FIRST_SSA_NUM);
436     }
437     else
438     {
439         GenTree** lhsPtr;
440         GenTree*  treeDefParent = treelhs->gtGetParent(&lhsPtr);
441
442         if (treeDefParent->OperGet() == GT_ASG)
443         {
444             assert(treelhs == treeDefParent->gtGetOp1());
445             GenTree* treeRhs = treeDefParent->gtGetOp2();
446
447             if (treeRhs->OperIsScalarLocal() && !fgExcludeFromSsa(treeRhs->AsLclVarCommon()->GetLclNum()))
448             {
449                 // Recursively track the Rhs
450                 unsigned rhsLclNum = treeRhs->AsLclVarCommon()->GetLclNum();
451                 unsigned rhsSsaNum = treeRhs->AsLclVarCommon()->GetSsaNum();
452
453                 value = optPropGetValueRec(rhsLclNum, rhsSsaNum, valueKind, walkDepth + 1);
454             }
455             else
456             {
457                 if (valueKind == optPropKind::OPK_ARRAYLEN)
458                 {
459                     value = getArrayLengthFromAllocation(treeRhs);
460                     if (value != nullptr)
461                     {
462                         if (!value->IsCnsIntOrI())
463                         {
464                             // Leave out non-constant-sized array
465                             value = nullptr;
466                         }
467                     }
468                 }
469                 else if (valueKind == optPropKind::OPK_OBJ_GETTYPE)
470                 {
471                     value = getObjectHandleNodeFromAllocation(treeRhs);
472                     if (value != nullptr)
473                     {
474                         if (!value->IsCnsIntOrI())
475                         {
476                             // Leave out non-constant-sized array
477                             value = nullptr;
478                         }
479                     }
480                 }
481             }
482         }
483     }
484
485     return value;
486 }
487
488 //----------------------------------------------------------------
489 // optFoldNullChecks: Try to find a GT_NULLCHECK node that can be folded into the GT_INDIR node.
490 //
491 // Arguments:
492 //    tree           - The input GT_INDIR tree.
493 //
494
495 void Compiler::optFoldNullCheck(GenTree* tree)
496 {
497     //
498     // Check for a pattern like this:
499     //
500     //                         =
501     //                       /   \
502     //                      x    comma
503     //                           /   \
504     //                     nullcheck  +
505     //                         |     / \
506     //                         y    y  const
507     //
508     //
509     //                    some trees in the same
510     //                    basic block with
511     //                    no unsafe side effects
512     //
513     //                           indir
514     //                             |
515     //                             x
516     //
517     // where the const is suitably small
518     // and transform it into
519     //
520     //                         =
521     //                       /   \
522     //                      x     +
523     //                           / \
524     //                          y  const
525     //
526     //
527     //              some trees with no unsafe side effects here
528     //
529     //                           indir
530     //                             |
531     //                             x
532
533     if ((compCurBB->bbFlags & BBF_HAS_NULLCHECK) == 0)
534     {
535         return;
536     }
537
538     assert(tree->OperIsIndir());
539
540     GenTree* const addr = tree->AsIndir()->Addr();
541     if (addr->OperGet() == GT_LCL_VAR)
542     {
543         // Check if we have the pattern above and find the nullcheck node if we do.
544
545         // Find the definition of the indirected local (x in the picture)
546         GenTreeLclVarCommon* const lclVarNode = addr->AsLclVarCommon();
547
548         const unsigned lclNum = lclVarNode->GetLclNum();
549         const unsigned ssaNum = lclVarNode->GetSsaNum();
550
551         if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
552         {
553             DefLoc      defLoc   = lvaTable[lclNum].GetPerSsaData(ssaNum)->m_defLoc;
554             BasicBlock* defBlock = defLoc.m_blk;
555
556             if (compCurBB == defBlock)
557             {
558                 GenTree* defTree   = defLoc.m_tree;
559                 GenTree* defParent = defTree->gtGetParent(nullptr);
560
561                 if ((defParent->OperGet() == GT_ASG) && (defParent->gtNext == nullptr))
562                 {
563                     GenTree* defRHS = defParent->gtGetOp2();
564                     if (defRHS->OperGet() == GT_COMMA)
565                     {
566                         if (defRHS->gtGetOp1()->OperGet() == GT_NULLCHECK)
567                         {
568                             GenTree* nullCheckTree = defRHS->gtGetOp1();
569                             if (nullCheckTree->gtGetOp1()->OperGet() == GT_LCL_VAR)
570                             {
571                                 // We found a candidate for 'y' in the picture
572                                 unsigned nullCheckLclNum = nullCheckTree->gtGetOp1()->AsLclVarCommon()->GetLclNum();
573
574                                 if (defRHS->gtGetOp2()->OperGet() == GT_ADD)
575                                 {
576                                     GenTree* additionNode = defRHS->gtGetOp2();
577                                     if ((additionNode->gtGetOp1()->OperGet() == GT_LCL_VAR) &&
578                                         (additionNode->gtGetOp1()->gtLclVarCommon.gtLclNum == nullCheckLclNum))
579                                     {
580                                         GenTree* offset = additionNode->gtGetOp2();
581                                         if (offset->IsCnsIntOrI())
582                                         {
583                                             if (!fgIsBigOffset(offset->gtIntConCommon.IconValue()))
584                                             {
585                                                 // Walk from the use to the def in reverse execution order to see
586                                                 // if any nodes have unsafe side effects.
587                                                 GenTree*       currentTree        = lclVarNode->gtPrev;
588                                                 bool           isInsideTry        = compCurBB->hasTryIndex();
589                                                 bool           canRemoveNullCheck = true;
590                                                 const unsigned maxNodesWalked     = 25;
591                                                 unsigned       nodesWalked        = 0;
592
593                                                 // First walk the nodes in the statement containing the indirection
594                                                 // in reverse execution order starting with the indirection's
595                                                 // predecessor.
596                                                 while (canRemoveNullCheck && (currentTree != nullptr))
597                                                 {
598                                                     if ((nodesWalked++ > maxNodesWalked) ||
599                                                         !optCanMoveNullCheckPastTree(currentTree, isInsideTry))
600                                                     {
601                                                         canRemoveNullCheck = false;
602                                                     }
603                                                     else
604                                                     {
605                                                         currentTree = currentTree->gtPrev;
606                                                     }
607                                                 }
608
609                                                 // Then walk the statement list in reverse execution order
610                                                 // until we get to the statement containing the null check.
611                                                 // We only need to check the side effects at the root of each statement.
612                                                 GenTree* curStmt = compCurStmt->gtPrev;
613                                                 currentTree      = curStmt->gtStmt.gtStmtExpr;
614                                                 while (canRemoveNullCheck && (currentTree != defParent))
615                                                 {
616                                                     if ((nodesWalked++ > maxNodesWalked) ||
617                                                         !optCanMoveNullCheckPastTree(currentTree, isInsideTry))
618                                                     {
619                                                         canRemoveNullCheck = false;
620                                                     }
621                                                     else
622                                                     {
623                                                         curStmt = curStmt->gtStmt.gtPrevStmt;
624                                                         assert(curStmt != nullptr);
625                                                         currentTree = curStmt->gtStmt.gtStmtExpr;
626                                                     }
627                                                 }
628
629                                                 if (canRemoveNullCheck)
630                                                 {
631                                                     // Remove the null check
632                                                     nullCheckTree->gtFlags &= ~(GTF_EXCEPT | GTF_DONT_CSE);
633
634                                                     // Set this flag to prevent reordering
635                                                     nullCheckTree->gtFlags |= GTF_ORDER_SIDEEFF;
636                                                     nullCheckTree->gtFlags |= GTF_IND_NONFAULTING;
637
638                                                     defRHS->gtFlags &= ~(GTF_EXCEPT | GTF_DONT_CSE);
639                                                     defRHS->gtFlags |=
640                                                         additionNode->gtFlags & (GTF_EXCEPT | GTF_DONT_CSE);
641
642                                                     // Re-morph the statement.
643                                                     fgMorphBlockStmt(compCurBB,
644                                                                      curStmt->AsStmt() DEBUGARG("optFoldNullCheck"));
645                                                 }
646                                             }
647                                         }
648                                     }
649                                 }
650                             }
651                         }
652                     }
653                 }
654             }
655         }
656     }
657 }
658
659 //----------------------------------------------------------------
660 // optCanMoveNullCheckPastTree: Check if GT_NULLCHECK can be folded into a node that
661 //                              is after tree is execution order.
662 //
663 // Arguments:
664 //    tree           - The input GT_INDIR tree.
665 //    isInsideTry    - True if tree is inside try, false otherwise
666 //
667 // Return Value:
668 //    True if GT_NULLCHECK can be folded into a node that is after tree is execution order,
669 //    false otherwise.
670
671 bool Compiler::optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry)
672 {
673     bool result = true;
674     if (isInsideTry)
675     {
676         // We disallow calls, exception sources, and all assignments.
677         // Assignments to locals are disallowed inside try because
678         // they may be live in the handler.
679         if ((tree->gtFlags & GTF_SIDE_EFFECT) != 0)
680         {
681             result = false;
682         }
683     }
684     else
685     {
686         // We disallow calls, exception sources, and assignments to
687         // global memory.
688         if (GTF_GLOBALLY_VISIBLE_SIDE_EFFECTS(tree->gtFlags))
689         {
690             result = false;
691         }
692     }
693     return result;
694 }