Recognize mod-free helper calls in loop hoisting
authorJoseph Tremoulet <jotrem@microsoft.com>
Thu, 25 Aug 2016 17:45:20 +0000 (13:45 -0400)
committerJoseph Tremoulet <jotrem@microsoft.com>
Thu, 15 Sep 2016 17:51:31 +0000 (13:51 -0400)
Update the code in `optHoistLoopExprsForTree` that identifies exprs with
memory side-effects to recognize helper calls that don't mutate the heap;
this allows hoisting invariant exprs past such helper calls.

Fixes #6901.

src/jit/optimizer.cpp

index 0fbdb27..50ed62c 100644 (file)
@@ -6226,9 +6226,28 @@ bool Compiler::optHoistLoopExprsForTree(
         // be hoisted so that they are evaluated in the same order as they would have been in the loop,
         // and therefore throw exceptions in the same order.  (So we don't use GTF_GLOBALLY_VISIBLE_SIDE_EFFECTS
         // here, since that includes exceptions.)
-        if (tree->gtFlags & GTF_CALL)
+        if (tree->IsCall())
         {
-            *pFirstBlockAndBeforeSideEffect = false;
+            // If it's a call, it must be a helper call that does not mutate the heap.
+            // Further, if it may run a cctor, it must be labeled as "Hoistable"
+            // (meaning it won't run a cctor because the class is not precise-init).
+            GenTreeCall* call = tree->AsCall();
+            if (call->gtCallType != CT_HELPER)
+            {
+                *pFirstBlockAndBeforeSideEffect = false;
+            }
+            else
+            {
+                CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
+                if (s_helperCallProperties.MutatesHeap(helpFunc))
+                {
+                    *pFirstBlockAndBeforeSideEffect = false;
+                }
+                else if (s_helperCallProperties.MayRunCctor(helpFunc) && (call->gtFlags & GTF_CALL_HOISTABLE) == 0)
+                {
+                    *pFirstBlockAndBeforeSideEffect = false;
+                }
+            }
         }
         else if (tree->OperIsAssignment())
         {