Commit a07e129e authored by danno@chromium.org's avatar danno@chromium.org

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.

R=fschneider@chromium.org

Review URL: https://chromiumcodereview.appspot.com/9365057

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10731 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0ee19e40
...@@ -4191,17 +4191,8 @@ class HTransitionElementsKind: public HTemplateInstruction<1> { ...@@ -4191,17 +4191,8 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
transitioned_map_(transitioned_map) { transitioned_map_(transitioned_map) {
SetOperandAt(0, object); SetOperandAt(0, object);
SetFlag(kUseGVN); SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kChangesElementsKind); SetGVNFlag(kChangesElementsKind);
if (original_map->has_fast_double_elements()) { SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kDependsOnElementsPointer);
SetGVNFlag(kDependsOnDoubleArrayElements);
} else if (transitioned_map->has_fast_double_elements()) {
SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kDependsOnElementsPointer);
SetGVNFlag(kDependsOnArrayElements);
}
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
} }
......
...@@ -1431,7 +1431,8 @@ class HGlobalValueNumberer BASE_EMBEDDED { ...@@ -1431,7 +1431,8 @@ class HGlobalValueNumberer BASE_EMBEDDED {
void ProcessLoopBlock(HBasicBlock* block, void ProcessLoopBlock(HBasicBlock* block,
HBasicBlock* before_loop, HBasicBlock* before_loop,
GVNFlagSet loop_kills, GVNFlagSet loop_kills,
GVNFlagSet* accumulated_first_time_depends); GVNFlagSet* accumulated_first_time_depends,
GVNFlagSet* accumulated_first_time_changes);
bool AllowCodeMotion(); bool AllowCodeMotion();
bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
...@@ -1512,10 +1513,12 @@ void HGlobalValueNumberer::LoopInvariantCodeMotion() { ...@@ -1512,10 +1513,12 @@ void HGlobalValueNumberer::LoopInvariantCodeMotion() {
side_effects.ToIntegral()); side_effects.ToIntegral());
GVNFlagSet accumulated_first_time_depends; GVNFlagSet accumulated_first_time_depends;
GVNFlagSet accumulated_first_time_changes;
HBasicBlock* last = block->loop_information()->GetLastBackEdge(); HBasicBlock* last = block->loop_information()->GetLastBackEdge();
for (int j = block->block_id(); j <= last->block_id(); ++j) { for (int j = block->block_id(); j <= last->block_id(); ++j) {
ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects, ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
&accumulated_first_time_depends); &accumulated_first_time_depends,
&accumulated_first_time_changes);
} }
} }
} }
...@@ -1526,7 +1529,8 @@ void HGlobalValueNumberer::ProcessLoopBlock( ...@@ -1526,7 +1529,8 @@ void HGlobalValueNumberer::ProcessLoopBlock(
HBasicBlock* block, HBasicBlock* block,
HBasicBlock* loop_header, HBasicBlock* loop_header,
GVNFlagSet loop_kills, GVNFlagSet loop_kills,
GVNFlagSet* accumulated_first_time_depends) { GVNFlagSet* first_time_depends,
GVNFlagSet* first_time_changes) {
HBasicBlock* pre_header = loop_header->predecessors()->at(0); HBasicBlock* pre_header = loop_header->predecessors()->at(0);
GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
...@@ -1544,28 +1548,47 @@ void HGlobalValueNumberer::ProcessLoopBlock( ...@@ -1544,28 +1548,47 @@ void HGlobalValueNumberer::ProcessLoopBlock(
instr->gvn_flags().ToIntegral(), instr->gvn_flags().ToIntegral(),
depends_flags.ToIntegral()); depends_flags.ToIntegral());
bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
if (!can_hoist && instr->IsTransitionElementsKind()) { if (instr->IsTransitionElementsKind()) {
// It's only possible to hoist one time side effects if there are no // It's possible to hoist transitions out of a loop as long as the
// dependencies on their changes from the loop header to the current // hoisting wouldn't move the transition past a DependsOn of one of it's
// instruction. // changes or any instructions that might change an objects map or
GVNFlagSet converted_changes = // elements contents.
HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); GVNFlagSet changes = instr->ChangesFlags();
TraceGVN("Checking dependencies on one-time instruction %d (%s) " GVNFlagSet hoist_depends_blockers =
"converted changes 0x%X, accumulated depends 0x%X\n", 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->id(),
instr->Mnemonic(), instr->Mnemonic(),
converted_changes.ToIntegral(), hoist_depends_blockers.ToIntegral(),
accumulated_first_time_depends->ToIntegral()); hoist_change_blockers.ToIntegral(),
// It's possible to hoist one-time side effects from the current loop first_time_depends->ToIntegral(),
// loop only if they dominate all of the successor blocks in the same first_time_changes->ToIntegral());
// loop and there are not any instructions that have Changes/DependsOn // It's possible to hoist transition from the current loop loop only if
// that intervene between it and the beginning of the loop header. // 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 && bool in_nested_loop = block != loop_header &&
((block->parent_loop_header() != loop_header) || ((block->parent_loop_header() != loop_header) ||
block->IsLoopHeader()); block->IsLoopHeader());
can_hoist = !in_nested_loop && can_hoist = !in_nested_loop &&
block->IsLoopSuccessorDominator() && 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) { if (can_hoist) {
...@@ -1589,10 +1612,8 @@ void HGlobalValueNumberer::ProcessLoopBlock( ...@@ -1589,10 +1612,8 @@ void HGlobalValueNumberer::ProcessLoopBlock(
if (!hoisted) { if (!hoisted) {
// If an instruction is not hoisted, we have to account for its side // If an instruction is not hoisted, we have to account for its side
// effects when hoisting later HTransitionElementsKind instructions. // effects when hoisting later HTransitionElementsKind instructions.
accumulated_first_time_depends->Add(instr->DependsOnFlags()); first_time_depends->Add(instr->DependsOnFlags());
GVNFlagSet converted_changes = first_time_changes->Add(instr->ChangesFlags());
HValue::ConvertChangesToDependsFlags(instr->SideEffectFlags());
accumulated_first_time_depends->Add(converted_changes);
} }
instr = next; instr = next;
} }
...@@ -4454,7 +4475,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, ...@@ -4454,7 +4475,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
Handle<Map> map = maps->at(i); Handle<Map> map = maps->at(i);
ASSERT(map->IsMap()); ASSERT(map->IsMap());
if (!transition_target.at(i).is_null()) { if (!transition_target.at(i).is_null()) {
object = AddInstruction(new(zone()) HTransitionElementsKind( AddInstruction(new(zone()) HTransitionElementsKind(
object, map, transition_target.at(i))); object, map, transition_target.at(i)));
} else { } else {
type_todo[map->elements_kind()] = true; type_todo[map->elements_kind()] = true;
......
...@@ -170,4 +170,42 @@ if (support_smi_only_arrays) { ...@@ -170,4 +170,42 @@ if (support_smi_only_arrays) {
testHoistingWithSideEffect(new Array(5)); testHoistingWithSideEffect(new Array(5));
testHoistingWithSideEffect(new Array(5)); testHoistingWithSideEffect(new Array(5));
assertTrue(2 != %GetOptimizationStatus(testHoistingWithSideEffect)); 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));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment