[turbofan] Redundant load elimination.
This is an initial version of redundant load elimination, currently limited to LoadField operators, and implemented by walking the effect chain. TEST=unittests R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/782473002 Cr-Commit-Position: refs/heads/master@{#25673}
This commit is contained in:
parent
c174d14578
commit
b3ace35209
2
BUILD.gn
2
BUILD.gn
@ -537,6 +537,8 @@ source_set("v8_base") {
|
||||
"src/compiler/linkage-impl.h",
|
||||
"src/compiler/linkage.cc",
|
||||
"src/compiler/linkage.h",
|
||||
"src/compiler/load-elimination.cc",
|
||||
"src/compiler/load-elimination.h",
|
||||
"src/compiler/machine-operator-reducer.cc",
|
||||
"src/compiler/machine-operator-reducer.h",
|
||||
"src/compiler/machine-operator.cc",
|
||||
|
76
src/compiler/load-elimination.cc
Normal file
76
src/compiler/load-elimination.cc
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/load-elimination.h"
|
||||
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
LoadElimination::~LoadElimination() {}
|
||||
|
||||
|
||||
Reduction LoadElimination::Reduce(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kLoadField:
|
||||
return ReduceLoadField(node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
Reduction LoadElimination::ReduceLoadField(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kLoadField, node->opcode());
|
||||
FieldAccess const access = FieldAccessOf(node->op());
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
for (Node* effect = NodeProperties::GetEffectInput(node);;
|
||||
effect = NodeProperties::GetEffectInput(effect)) {
|
||||
switch (effect->opcode()) {
|
||||
case IrOpcode::kLoadField: {
|
||||
if (object == NodeProperties::GetValueInput(effect, 0) &&
|
||||
access == FieldAccessOf(effect->op())) {
|
||||
Node* const value = effect;
|
||||
NodeProperties::ReplaceWithValue(node, value);
|
||||
return Replace(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kStoreField: {
|
||||
if (access == FieldAccessOf(effect->op())) {
|
||||
if (object == NodeProperties::GetValueInput(effect, 0)) {
|
||||
Node* const value = NodeProperties::GetValueInput(effect, 1);
|
||||
NodeProperties::ReplaceWithValue(node, value);
|
||||
return Replace(value);
|
||||
}
|
||||
// TODO(turbofan): Alias analysis to the rescue?
|
||||
return NoChange();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kStoreBuffer:
|
||||
case IrOpcode::kStoreElement: {
|
||||
// These can never interfere with field loads.
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!effect->op()->HasProperty(Operator::kNoWrite) ||
|
||||
effect->op()->EffectInputCount() != 1) {
|
||||
return NoChange();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
29
src/compiler/load-elimination.h
Normal file
29
src/compiler/load-elimination.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_LOAD_ELIMINATION_H_
|
||||
#define V8_COMPILER_LOAD_ELIMINATION_H_
|
||||
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class LoadElimination FINAL : public Reducer {
|
||||
public:
|
||||
LoadElimination() {}
|
||||
~LoadElimination() FINAL;
|
||||
|
||||
Reduction Reduce(Node* node) FINAL;
|
||||
|
||||
private:
|
||||
Reduction ReduceLoadField(Node* node);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_LOAD_ELIMINATION_H_
|
@ -22,6 +22,7 @@
|
||||
#include "src/compiler/js-inlining.h"
|
||||
#include "src/compiler/js-typed-lowering.h"
|
||||
#include "src/compiler/jump-threading.h"
|
||||
#include "src/compiler/load-elimination.h"
|
||||
#include "src/compiler/machine-operator-reducer.h"
|
||||
#include "src/compiler/move-optimizer.h"
|
||||
#include "src/compiler/pipeline-statistics.h"
|
||||
@ -392,11 +393,13 @@ struct TypedLoweringPhase {
|
||||
SourcePositionTable::Scope pos(data->source_positions(),
|
||||
SourcePosition::Unknown());
|
||||
ValueNumberingReducer vn_reducer(temp_zone);
|
||||
LoadElimination load_elimination;
|
||||
JSTypedLowering lowering(data->jsgraph());
|
||||
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
|
||||
GraphReducer graph_reducer(data->graph(), temp_zone);
|
||||
graph_reducer.AddReducer(&vn_reducer);
|
||||
graph_reducer.AddReducer(&lowering);
|
||||
graph_reducer.AddReducer(&load_elimination);
|
||||
graph_reducer.AddReducer(&simple_reducer);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
|
72
test/unittests/compiler/load-elimination-unittest.cc
Normal file
72
test/unittests/compiler/load-elimination-unittest.cc
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/load-elimination.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "test/unittests/compiler/graph-unittest.h"
|
||||
#include "test/unittests/compiler/node-test-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class LoadEliminationTest : public GraphTest {
|
||||
public:
|
||||
LoadEliminationTest() : GraphTest(3), simplified_(zone()) {}
|
||||
~LoadEliminationTest() OVERRIDE {}
|
||||
|
||||
protected:
|
||||
Reduction Reduce(Node* node) {
|
||||
LoadElimination reducer;
|
||||
return reducer.Reduce(node);
|
||||
}
|
||||
|
||||
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
||||
|
||||
private:
|
||||
SimplifiedOperatorBuilder simplified_;
|
||||
};
|
||||
|
||||
|
||||
TEST_F(LoadEliminationTest, LoadFieldWithStoreField) {
|
||||
Node* object1 = Parameter(0);
|
||||
Node* object2 = Parameter(1);
|
||||
Node* value = Parameter(2);
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
|
||||
FieldAccess access1 = AccessBuilder::ForContextSlot(42);
|
||||
Node* store1 = graph()->NewNode(simplified()->StoreField(access1), object1,
|
||||
value, effect, control);
|
||||
Reduction r1 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
|
||||
object1, store1, control));
|
||||
ASSERT_TRUE(r1.Changed());
|
||||
EXPECT_EQ(value, r1.replacement());
|
||||
|
||||
FieldAccess access2 = AccessBuilder::ForMap();
|
||||
Node* store2 = graph()->NewNode(simplified()->StoreField(access2), object1,
|
||||
object2, store1, control);
|
||||
Reduction r2 = Reduce(graph()->NewNode(simplified()->LoadField(access2),
|
||||
object1, store2, control));
|
||||
ASSERT_TRUE(r2.Changed());
|
||||
EXPECT_EQ(object2, r2.replacement());
|
||||
|
||||
Node* store3 = graph()->NewNode(
|
||||
simplified()->StoreBuffer(BufferAccess(kExternalInt8Array)), object2,
|
||||
value, Int32Constant(10), object1, store2, control);
|
||||
|
||||
Reduction r3 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
|
||||
object2, store3, control));
|
||||
ASSERT_FALSE(r3.Changed());
|
||||
|
||||
Reduction r4 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
|
||||
object1, store3, control));
|
||||
ASSERT_TRUE(r4.Changed());
|
||||
EXPECT_EQ(value, r4.replacement());
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -51,6 +51,7 @@
|
||||
'compiler/js-builtin-reducer-unittest.cc',
|
||||
'compiler/js-operator-unittest.cc',
|
||||
'compiler/js-typed-lowering-unittest.cc',
|
||||
'compiler/load-elimination-unittest.cc',
|
||||
'compiler/machine-operator-reducer-unittest.cc',
|
||||
'compiler/move-optimizer-unittest.cc',
|
||||
'compiler/node-matchers-unittest.cc',
|
||||
|
@ -469,6 +469,8 @@
|
||||
'../../src/compiler/linkage-impl.h',
|
||||
'../../src/compiler/linkage.cc',
|
||||
'../../src/compiler/linkage.h',
|
||||
'../../src/compiler/load-elimination.cc',
|
||||
'../../src/compiler/load-elimination.h',
|
||||
'../../src/compiler/machine-operator-reducer.cc',
|
||||
'../../src/compiler/machine-operator-reducer.h',
|
||||
'../../src/compiler/machine-operator.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user