Commit d70dc1ac authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Initial version of the new LoadElimination.

This adds a new optimization phase to the TurboFan pipeline, which walks
over the effect chain and tries to eliminate redundant loads (and even
some stores) of object fields. We currently ignore element access, but
that will probably need to be handled as well at some point. We also
don't have any special treatment to properly track object maps, which is
also on the list of things that will happen afterwards.

The implementation is pretty simple currently, and probably way to
inefficient. It's meant to be a proof-of-concept to iterate on.

R=jarin@chromium.org
BUG=v8:4930,v8:5141

Review-Url: https://codereview.chromium.org/2120253002
Cr-Commit-Position: refs/heads/master@{#37528}
parent 65415ca7
This diff is collapsed.
// Copyright 2014 the V8 project authors. All rights reserved.
// Copyright 2016 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 {
// Forward declarations.
class Zone;
namespace compiler {
// Forward declarations.
class Graph;
class SimplifiedOperatorBuilder;
class LoadElimination final : public AdvancedReducer {
// Eliminates redundant loads via scalar replacement of aggregates.
class LoadElimination final {
public:
explicit LoadElimination(Editor* editor, Graph* graph,
SimplifiedOperatorBuilder* simplified)
: AdvancedReducer(editor), graph_(graph), simplified_(simplified) {}
~LoadElimination() final;
LoadElimination(Graph* graph, Zone* zone) : graph_(graph), zone_(zone) {}
Reduction Reduce(Node* node) final;
void Run();
private:
SimplifiedOperatorBuilder* simplified() const { return simplified_; }
Graph* graph() const { return graph_; }
Reduction ReduceLoadField(Node* node);
Zone* zone() const { return zone_; }
Graph* const graph_;
SimplifiedOperatorBuilder* const simplified_;
Zone* const zone_;
};
} // namespace compiler
......
......@@ -872,8 +872,6 @@ struct TypedLoweringPhase {
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common());
LoadElimination load_elimination(&graph_reducer, data->graph(),
data->jsgraph()->simplified());
JSBuiltinReducer builtin_reducer(&graph_reducer, data->jsgraph());
MaybeHandle<LiteralsArray> literals_array =
data->info()->is_native_context_specializing()
......@@ -912,7 +910,6 @@ struct TypedLoweringPhase {
}
AddReducer(data, &graph_reducer, &typed_lowering);
AddReducer(data, &graph_reducer, &intrinsic_lowering);
AddReducer(data, &graph_reducer, &load_elimination);
AddReducer(data, &graph_reducer, &value_numbering);
AddReducer(data, &graph_reducer, &simple_reducer);
AddReducer(data, &graph_reducer, &checkpoint_elimination);
......@@ -1043,6 +1040,22 @@ struct StoreStoreEliminationPhase {
}
};
struct LoadEliminationPhase {
static const char* phase_name() { return "load elimination"; }
void Run(PipelineData* data, Zone* temp_zone) {
// The memory optimizer requires the graphs to be trimmed, so trim now.
GraphTrimmer trimmer(temp_zone, data->graph());
NodeVector roots(temp_zone);
data->jsgraph()->GetCachedNodes(&roots);
trimmer.TrimGraph(roots.begin(), roots.end());
// Eliminate redundant loads.
LoadElimination load_elimination(data->graph(), temp_zone);
load_elimination.Run();
}
};
struct MemoryOptimizationPhase {
static const char* phase_name() { return "memory optimization"; }
......@@ -1446,6 +1459,11 @@ bool PipelineImpl::CreateGraph() {
Run<EscapeAnalysisPhase>();
RunPrintAndVerify("Escape Analysed");
}
if (FLAG_turbo_load_elimination) {
Run<LoadEliminationPhase>();
RunPrintAndVerify("Load eliminated");
}
}
// Select representations. This has to run w/o the Typer decorator, because
......
......@@ -462,6 +462,9 @@ DEFINE_BOOL(native_context_specialization, true,
"enable native context specialization in TurboFan")
DEFINE_BOOL(turbo_inlining, true, "enable inlining in TurboFan")
DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
DEFINE_BOOL(turbo_load_elimination, true, "enable load elimination in TurboFan")
DEFINE_BOOL(trace_turbo_load_elimination, false,
"trace TurboFan load elimination")
DEFINE_BOOL(loop_assignment_analysis, true, "perform loop assignment analysis")
DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
DEFINE_BOOL(turbo_verify_allocation, DEBUG_BOOL,
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Copyright 2016 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/access-builder.h"
#include "src/compiler/node.h"
#include "src/compiler/simplified-operator.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
......@@ -18,11 +19,9 @@ class LoadEliminationTest : public TypedGraphTest {
~LoadEliminationTest() override {}
protected:
Reduction Reduce(Node* node) {
// TODO(titzer): mock the GraphReducer here for better unit testing.
GraphReducer graph_reducer(zone(), graph());
LoadElimination reducer(&graph_reducer, graph(), simplified());
return reducer.Reduce(node);
void Run() {
LoadElimination load_elimination(graph(), zone());
load_elimination.Run();
}
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
......@@ -31,42 +30,49 @@ class LoadEliminationTest : public TypedGraphTest {
SimplifiedOperatorBuilder simplified_;
};
TEST_F(LoadEliminationTest, LoadFieldWithStoreField) {
Node* object1 = Parameter(Type::Any(), 0);
Node* object2 = Parameter(Type::Any(), 1);
Node* value = Parameter(Type::Any(), 2);
TEST_F(LoadEliminationTest, LoadFieldAndLoadField) {
Node* object = Parameter(Type::Any(), 0);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
kNoWriteBarrier};
Node* load1 = effect = graph()->NewNode(simplified()->LoadField(access),
object, effect, control);
Node* load2 = effect = graph()->NewNode(simplified()->LoadField(access),
object, effect, control);
control = graph()->NewNode(common()->Return(), load2, effect, control);
graph()->end()->ReplaceInput(0, control);
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());
Run();
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());
EXPECT_THAT(graph()->end(), IsEnd(IsReturn(load1, load1, graph()->start())));
}
Node* store3 = graph()->NewNode(
simplified()->StoreBuffer(BufferAccess(kExternalInt8Array)), object2,
value, Int32Constant(10), object1, store2, control);
TEST_F(LoadEliminationTest, StoreFieldAndLoadField) {
Node* object = Parameter(Type::Any(), 0);
Node* value = Parameter(Type::Any(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
kNoWriteBarrier};
Node* store = effect = graph()->NewNode(simplified()->StoreField(access),
object, value, effect, control);
Node* load = effect = graph()->NewNode(simplified()->LoadField(access),
object, effect, control);
control = graph()->NewNode(common()->Return(), load, effect, control);
graph()->end()->ReplaceInput(0, control);
Reduction r3 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
object2, store3, control));
ASSERT_FALSE(r3.Changed());
Run();
Reduction r4 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
object1, store3, control));
ASSERT_TRUE(r4.Changed());
EXPECT_EQ(value, r4.replacement());
EXPECT_THAT(graph()->end(), IsEnd(IsReturn(value, store, graph()->start())));
}
} // namespace compiler
......
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