Revision: 10731
Author:   [email protected]
Date:     Thu Feb 16 07:37:52 2012
Log:      Relax TransitionElementsKind DependsOn/Changes dependencies.

Ensure that GVN eliminates all transitions that are dominated by an equivalent transition, even if there is a DependsOn-changing instruction in between.

[email protected]

Review URL: https://chromiumcodereview.appspot.com/9365057
http://code.google.com/p/v8/source/detail?r=10731

Modified:
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/test/mjsunit/elements-transition-hoisting.js

=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Feb 14 06:14:51 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Thu Feb 16 07:37:52 2012
@@ -4191,17 +4191,8 @@
         transitioned_map_(transitioned_map) {
     SetOperandAt(0, object);
     SetFlag(kUseGVN);
-    SetGVNFlag(kDependsOnMaps);
     SetGVNFlag(kChangesElementsKind);
-    if (original_map->has_fast_double_elements()) {
-      SetGVNFlag(kChangesElementsPointer);
-      SetGVNFlag(kDependsOnElementsPointer);
-      SetGVNFlag(kDependsOnDoubleArrayElements);
-    } else if (transitioned_map->has_fast_double_elements()) {
-      SetGVNFlag(kChangesElementsPointer);
-      SetGVNFlag(kDependsOnElementsPointer);
-      SetGVNFlag(kDependsOnArrayElements);
-    }
+    SetGVNFlag(kChangesElementsPointer);
     set_representation(Representation::Tagged());
   }

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Feb 14 06:40:58 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Thu Feb 16 07:37:52 2012
@@ -1431,7 +1431,8 @@
   void ProcessLoopBlock(HBasicBlock* block,
                         HBasicBlock* before_loop,
                         GVNFlagSet loop_kills,
-                        GVNFlagSet* accumulated_first_time_depends);
+                        GVNFlagSet* accumulated_first_time_depends,
+                        GVNFlagSet* accumulated_first_time_changes);
   bool AllowCodeMotion();
   bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);

@@ -1512,10 +1513,12 @@
                side_effects.ToIntegral());

       GVNFlagSet accumulated_first_time_depends;
+      GVNFlagSet accumulated_first_time_changes;
       HBasicBlock* last = block->loop_information()->GetLastBackEdge();
       for (int j = block->block_id(); j <= last->block_id(); ++j) {
         ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
-                         &accumulated_first_time_depends);
+                         &accumulated_first_time_depends,
+                         &accumulated_first_time_changes);
       }
     }
   }
@@ -1526,7 +1529,8 @@
     HBasicBlock* block,
     HBasicBlock* loop_header,
     GVNFlagSet loop_kills,
-    GVNFlagSet* accumulated_first_time_depends) {
+    GVNFlagSet* first_time_depends,
+    GVNFlagSet* first_time_changes) {
   HBasicBlock* pre_header = loop_header->predecessors()->at(0);
GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
   TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
@@ -1544,28 +1548,47 @@
                instr->gvn_flags().ToIntegral(),
                depends_flags.ToIntegral());
       bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
-      if (!can_hoist && instr->IsTransitionElementsKind()) {
- // It's only possible to hoist one time side effects if there are no - // dependencies on their changes from the loop header to the current
-        // instruction.
-        GVNFlagSet converted_changes =
-            HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
-        TraceGVN("Checking dependencies on one-time instruction %d (%s) "
-                 "converted changes 0x%X, accumulated depends 0x%X\n",
+      if (instr->IsTransitionElementsKind()) {
+        // It's possible to hoist transitions out of a loop as long as the
+ // hoisting wouldn't move the transition past a DependsOn of one of it's
+        // changes or any instructions that might change an objects map or
+        // elements contents.
+        GVNFlagSet changes = instr->ChangesFlags();
+        GVNFlagSet hoist_depends_blockers =
+            HValue::ConvertChangesToDependsFlags(changes);
+ // In addition to not hoisting transitions above other instructions that
+        // change dependencies that the transition changes, it must not be
+ // hoisted above map changes and stores to an elements backing store
+        // that the transition might change.
+        GVNFlagSet hoist_change_blockers = changes;
+        hoist_change_blockers.Add(kChangesMaps);
+ HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
+        if (trans->original_map()->has_fast_double_elements()) {
+          hoist_change_blockers.Add(kChangesDoubleArrayElements);
+        }
+        if (trans->transitioned_map()->has_fast_double_elements()) {
+          hoist_change_blockers.Add(kChangesArrayElements);
+        }
+ TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) " + "hoist depends blockers 0x%X, hoist change blockers 0x%X, "
+                 "accumulated depends 0x%X, accumulated changes 0x%X\n",
                  instr->id(),
                  instr->Mnemonic(),
-                 converted_changes.ToIntegral(),
-                 accumulated_first_time_depends->ToIntegral());
- // It's possible to hoist one-time side effects from the current loop - // loop only if they dominate all of the successor blocks in the same - // loop and there are not any instructions that have Changes/DependsOn
-        // that intervene between it and the beginning of the loop header.
+                 hoist_depends_blockers.ToIntegral(),
+                 hoist_change_blockers.ToIntegral(),
+                 first_time_depends->ToIntegral(),
+                 first_time_changes->ToIntegral());
+ // It's possible to hoist transition from the current loop loop only if + // they dominate all of the successor blocks in the same loop and there + // are not any instructions that have Changes/DependsOn that intervene
+        // between it and the beginning of the loop header.
         bool in_nested_loop = block != loop_header &&
             ((block->parent_loop_header() != loop_header) ||
              block->IsLoopHeader());
         can_hoist = !in_nested_loop &&
             block->IsLoopSuccessorDominator() &&
-            !accumulated_first_time_depends->ContainsAnyOf(converted_changes);
+            !first_time_depends->ContainsAnyOf(hoist_depends_blockers) &&
+            !first_time_changes->ContainsAnyOf(hoist_change_blockers);
       }

       if (can_hoist) {
@@ -1589,10 +1612,8 @@
     if (!hoisted) {
       // If an instruction is not hoisted, we have to account for its side
       // effects when hoisting later HTransitionElementsKind instructions.
-      accumulated_first_time_depends->Add(instr->DependsOnFlags());
-      GVNFlagSet converted_changes =
-          HValue::ConvertChangesToDependsFlags(instr->SideEffectFlags());
-      accumulated_first_time_depends->Add(converted_changes);
+      first_time_depends->Add(instr->DependsOnFlags());
+      first_time_changes->Add(instr->ChangesFlags());
     }
     instr = next;
   }
@@ -4454,7 +4475,7 @@
     Handle<Map> map = maps->at(i);
     ASSERT(map->IsMap());
     if (!transition_target.at(i).is_null()) {
-      object = AddInstruction(new(zone()) HTransitionElementsKind(
+      AddInstruction(new(zone()) HTransitionElementsKind(
           object, map, transition_target.at(i)));
     } else {
       type_todo[map->elements_kind()] = true;
=======================================
--- /branches/bleeding_edge/test/mjsunit/elements-transition-hoisting.js Thu Feb 9 06:55:32 2012 +++ /branches/bleeding_edge/test/mjsunit/elements-transition-hoisting.js Thu Feb 16 07:37:52 2012
@@ -170,4 +170,42 @@
   testHoistingWithSideEffect(new Array(5));
   testHoistingWithSideEffect(new Array(5));
   assertTrue(2 != %GetOptimizationStatus(testHoistingWithSideEffect));
-}
+
+  function testStraightLineDupeElinination(a,b,c,d,e,f) {
+    var count = 3;
+    do {
+      assertTrue(true);
+      a[0] = b;
+      a[1] = c;
+      a[2] = d;
+      assertTrue(true);
+ a[3] = e; // TransitionElementsKind should be eliminated despite call.
+      a[4] = f;
+    } while (--count > 3);
+  }
+
+  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,0,.5);
+  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,.5,0);
+  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,.5,0,0);
+  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,.5,0,0,0);
+  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),.5,0,0,0,0);
+  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,0,.5);
+  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,.5,0);
+  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,.5,0,0);
+  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,.5,0,0,0);
+  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),.5,0,0,0,0);
+  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
+  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
+  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
+  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
+  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
+  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
+  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
+  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
+  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
+  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
+  %OptimizeFunctionOnNextCall(testStraightLineDupeElinination);
+  testStraightLineDupeElinination(new Array(5));
+  testStraightLineDupeElinination(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testStraightLineDupeElinination));
+}

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to