v8/test/unittests/compiler/dead-code-elimination-unittest.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

376 lines
13 KiB
C++
Raw Normal View History

[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
// Copyright 2015 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/common-operator.h"
#include "src/compiler/dead-code-elimination.h"
#include "test/unittests/compiler/graph-reducer-unittest.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"
using testing::StrictMock;
namespace v8 {
namespace internal {
namespace compiler {
namespace dead_code_elimination_unittest {
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
class DeadCodeEliminationTest : public GraphTest {
public:
explicit DeadCodeEliminationTest(int num_parameters = 4)
: GraphTest(num_parameters) {}
~DeadCodeEliminationTest() override = default;
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
protected:
Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) {
Reland^6 "[turbofan] eagerly prune None types and deadness from the graph" Reland of https://chromium-review.googlesource.com/c/v8/v8/+/727893 The crashes should be fixed by https://chromium-review.googlesource.com/c/v8/v8/+/763531 Original change's description: > Revert "Reland^5 "[turbofan] eagerly prune None types and deadness from the graph"" > > This reverts commit ac0661b358bce7f9af6f23c3e640121f6ca20170. > > Reason for revert: Clusterfuzz unhappy: chromium:783019 chromium:783035 > > Original change's description: > > Reland^5 "[turbofan] eagerly prune None types and deadness from the graph" > > > > This gives up on earlier attempts to interpret DeadValue as a signal of > > unreachable code. This does not work because free-floating dead value > > nodes, and even pure branch nodes that use them, can get scheduled so > > early that they get reachable. Instead, we now eagerly remove branches > > that use DeadValue in DeadCodeElimination and replace DeadValue inputs > > to value phi nodes with dummy values. > > > > Reland of https://chromium-review.googlesource.com/715716 > > > > Bug: chromium:741225 chromium:776256 > > Change-Id: I251efd507c967d4a8882ad8fd2fd96c4185781fe > > Reviewed-on: https://chromium-review.googlesource.com/727893 > > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#49188} > > TBR=jarin@chromium.org,tebbi@chromium.org > > Bug: chromium:741225 chromium:776256 chromium:783019 chromium:783035 > Change-Id: I6a8fa3a08ce2824a858ae01817688e63ed1f442e > Reviewed-on: https://chromium-review.googlesource.com/758770 > Reviewed-by: Tobias Tebbi <tebbi@chromium.org> > Commit-Queue: Tobias Tebbi <tebbi@chromium.org> > Cr-Commit-Position: refs/heads/master@{#49262} TBR=jarin@chromium.org,tebbi@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: chromium:741225 chromium:776256 chromium:783019 chromium:783035 Change-Id: I6c02b4beb02997ec34015ed2f6791a93c70f5e36 Reviewed-on: https://chromium-review.googlesource.com/772150 Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#49429}
2017-11-15 18:39:07 +00:00
DeadCodeElimination reducer(editor, graph(), common(), zone());
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
return reducer.Reduce(node);
}
Reduction Reduce(Node* node) {
StrictMock<MockAdvancedReducerEditor> editor;
return Reduce(&editor, node);
}
};
namespace {
const MachineRepresentation kMachineRepresentations[] = {
MachineRepresentation::kBit, MachineRepresentation::kWord8,
MachineRepresentation::kWord16, MachineRepresentation::kWord32,
MachineRepresentation::kWord64, MachineRepresentation::kFloat32,
MachineRepresentation::kFloat64, MachineRepresentation::kTagged};
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
const int kMaxInputs = 16;
const Operator kOp0(0, Operator::kNoProperties, "Op0", 1, 1, 1, 1, 1, 1);
} // namespace
// -----------------------------------------------------------------------------
// General dead propagation
TEST_F(DeadCodeEliminationTest, GeneralDeadPropagation) {
Node* const value = Parameter(0);
Node* const effect = graph()->start();
Node* const dead = graph()->NewNode(common()->Dead());
Node* const node = graph()->NewNode(&kOp0, value, effect, dead);
Reduction const r = Reduce(node);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
// -----------------------------------------------------------------------------
// Branch
TEST_F(DeadCodeEliminationTest, BranchWithDeadControlInput) {
BranchHint const kHints[] = {BranchHint::kNone, BranchHint::kTrue,
BranchHint::kFalse};
TRACED_FOREACH(BranchHint, hint, kHints) {
Reduction const r =
Reduce(graph()->NewNode(common()->Branch(hint), Parameter(0),
graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
// -----------------------------------------------------------------------------
// IfTrue
TEST_F(DeadCodeEliminationTest, IfTrueWithDeadInput) {
Reduction const r = Reduce(
graph()->NewNode(common()->IfTrue(), graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
// -----------------------------------------------------------------------------
// IfFalse
TEST_F(DeadCodeEliminationTest, IfFalseWithDeadInput) {
Reduction const r = Reduce(graph()->NewNode(
common()->IfFalse(), graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
// -----------------------------------------------------------------------------
// IfSuccess
TEST_F(DeadCodeEliminationTest, IfSuccessWithDeadInput) {
Reduction const r = Reduce(graph()->NewNode(
common()->IfSuccess(), graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
// -----------------------------------------------------------------------------
// IfException
TEST_F(DeadCodeEliminationTest, IfExceptionWithDeadControlInput) {
Reduction const r =
Reduce(graph()->NewNode(common()->IfException(), graph()->start(),
graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
}
// -----------------------------------------------------------------------------
// End
TEST_F(DeadCodeEliminationTest, EndWithDeadAndStart) {
Node* const dead = graph()->NewNode(common()->Dead());
Node* const start = graph()->start();
Reduction const r = Reduce(graph()->NewNode(common()->End(2), dead, start));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsEnd(start));
}
TEST_F(DeadCodeEliminationTest, EndWithOnlyDeadInputs) {
Node* inputs[kMaxInputs];
TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) {
for (int i = 0; i < input_count; ++i) {
inputs[i] = graph()->NewNode(common()->Dead());
}
Reduction const r = Reduce(
graph()->NewNode(common()->End(input_count), input_count, inputs));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
// -----------------------------------------------------------------------------
// Merge
TEST_F(DeadCodeEliminationTest, MergeWithOnlyDeadInputs) {
Node* inputs[kMaxInputs + 1];
TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) {
for (int i = 0; i < input_count; ++i) {
inputs[i] = graph()->NewNode(common()->Dead());
}
Reduction const r = Reduce(
graph()->NewNode(common()->Merge(input_count), input_count, inputs));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
TEST_F(DeadCodeEliminationTest, MergeWithOneLiveAndOneDeadInput) {
Node* const v0 = Parameter(0);
Node* const v1 = Parameter(1);
Node* const c0 =
graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start());
Node* const c1 = graph()->NewNode(common()->Dead());
Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0);
Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1);
Node* const merge = graph()->NewNode(common()->Merge(2), c0, c1);
Node* const phi = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2), v0, v1, merge);
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, merge);
StrictMock<MockAdvancedReducerEditor> editor;
EXPECT_CALL(editor, Replace(phi, v0));
EXPECT_CALL(editor, Replace(ephi, e0));
Reduction const r = Reduce(&editor, merge);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(c0, r.replacement());
}
TEST_F(DeadCodeEliminationTest, MergeWithTwoLiveAndTwoDeadInputs) {
Node* const v0 = Parameter(0);
Node* const v1 = Parameter(1);
Node* const v2 = Parameter(2);
Node* const v3 = Parameter(3);
Node* const c0 =
graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start());
Node* const c1 = graph()->NewNode(common()->Dead());
Node* const c2 = graph()->NewNode(common()->Dead());
Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0);
Node* const e0 = graph()->start();
Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0);
Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0);
Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3);
Node* const merge = graph()->NewNode(common()->Merge(4), c0, c1, c2, c3);
Node* const phi = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 4), v0, v1, v2, v3, merge);
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
Node* const ephi =
graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, merge);
StrictMock<MockAdvancedReducerEditor> editor;
EXPECT_CALL(editor, Revisit(phi));
EXPECT_CALL(editor, Revisit(ephi));
Reduction const r = Reduce(&editor, merge);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsMerge(c0, c3));
EXPECT_THAT(phi,
IsPhi(MachineRepresentation::kTagged, v0, v3, r.replacement()));
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement()));
}
// -----------------------------------------------------------------------------
// Loop
TEST_F(DeadCodeEliminationTest, LoopWithDeadFirstInput) {
Node* inputs[kMaxInputs + 1];
TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) {
inputs[0] = graph()->NewNode(common()->Dead());
for (int i = 1; i < input_count; ++i) {
inputs[i] = graph()->start();
}
Reduction const r = Reduce(
graph()->NewNode(common()->Loop(input_count), input_count, inputs));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
TEST_F(DeadCodeEliminationTest, LoopWithOnlyDeadInputs) {
Node* inputs[kMaxInputs + 1];
TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) {
for (int i = 0; i < input_count; ++i) {
inputs[i] = graph()->NewNode(common()->Dead());
}
Reduction const r = Reduce(
graph()->NewNode(common()->Loop(input_count), input_count, inputs));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
TEST_F(DeadCodeEliminationTest, LoopWithOneLiveAndOneDeadInput) {
Node* const v0 = Parameter(0);
Node* const v1 = Parameter(1);
Node* const c0 =
graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start());
Node* const c1 = graph()->NewNode(common()->Dead());
Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0);
Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1);
Node* const loop = graph()->NewNode(common()->Loop(2), c0, c1);
Node* const phi = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2), v0, v1, loop);
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, loop);
Node* const terminate = graph()->NewNode(common()->Terminate(), ephi, loop);
StrictMock<MockAdvancedReducerEditor> editor;
EXPECT_CALL(editor, Replace(phi, v0));
EXPECT_CALL(editor, Replace(ephi, e0));
EXPECT_CALL(editor, Replace(terminate, IsDead()));
Reduction const r = Reduce(&editor, loop);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(c0, r.replacement());
}
TEST_F(DeadCodeEliminationTest, LoopWithTwoLiveAndTwoDeadInputs) {
Node* const v0 = Parameter(0);
Node* const v1 = Parameter(1);
Node* const v2 = Parameter(2);
Node* const v3 = Parameter(3);
Node* const c0 =
graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start());
Node* const c1 = graph()->NewNode(common()->Dead());
Node* const c2 = graph()->NewNode(common()->Dead());
Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0);
Node* const e0 = graph()->start();
Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0);
Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0);
Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3);
Node* const loop = graph()->NewNode(common()->Loop(4), c0, c1, c2, c3);
Node* const phi = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 4), v0, v1, v2, v3, loop);
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
Node* const ephi =
graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, loop);
StrictMock<MockAdvancedReducerEditor> editor;
EXPECT_CALL(editor, Revisit(phi));
EXPECT_CALL(editor, Revisit(ephi));
Reduction const r = Reduce(&editor, loop);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsLoop(c0, c3));
EXPECT_THAT(phi,
IsPhi(MachineRepresentation::kTagged, v0, v3, r.replacement()));
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement()));
}
// -----------------------------------------------------------------------------
// Phi
TEST_F(DeadCodeEliminationTest, PhiWithDeadControlInput) {
Node* inputs[kMaxInputs + 1];
TRACED_FOREACH(MachineRepresentation, rep, kMachineRepresentations) {
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
TRACED_FORRANGE(int, input_count, 1, kMaxInputs) {
for (int i = 0; i < input_count; ++i) {
inputs[i] = Parameter(i);
}
inputs[input_count] = graph()->NewNode(common()->Dead());
Reduction const r = Reduce(graph()->NewNode(
common()->Phi(rep, input_count), input_count + 1, inputs));
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
}
// -----------------------------------------------------------------------------
// EffectPhi
TEST_F(DeadCodeEliminationTest, EffectPhiWithDeadControlInput) {
Node* inputs[kMaxInputs + 1];
TRACED_FORRANGE(int, input_count, 1, kMaxInputs) {
for (int i = 0; i < input_count; ++i) {
inputs[i] = graph()->start();
}
inputs[input_count] = graph()->NewNode(common()->Dead());
Reduction const r = Reduce(graph()->NewNode(
common()->EffectPhi(input_count), input_count + 1, inputs));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
}
// -----------------------------------------------------------------------------
// Terminate
TEST_F(DeadCodeEliminationTest, TerminateWithDeadControlInput) {
Reduction const r =
Reduce(graph()->NewNode(common()->Terminate(), graph()->start(),
graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
} // namespace dead_code_elimination_unittest
[turbofan] Proper dead code elimination as regular reducer. The three different concerns that the ControlReducer used to deal with are now properly separated into a.) DeadCodeElimination, which is a regular AdvancedReducer, that propagates Dead via control edges, b.) CommonOperatorReducer, which does strength reduction on common operators (i.e. Branch, Phi, and friends), and c.) GraphTrimming, which removes dead->live edges from the graph. This will make it possible to run the DeadCodeElimination together with other passes that actually introduce Dead nodes, i.e. typed lowering; and it opens the door for general inlining without two stage fix point iteration. To make the DeadCodeElimination easier and more uniform, we basically reverted the introduction of DeadValue and DeadEffect, and changed the Dead operator to produce control, value and effect. Note however that this is not a requirement, but merely a way to make dead propagation easier and more uniform. We could always go back and decide to have different Dead operators if some other change requires that. Note that there are several additional opportunities for cleanup now, i.e. OSR deconstruction could be a regular reducer now, and we don't need to use TheHole as dead value marker in the GraphReducer. And we can actually run the dead code elimination together with the other passes instead of using separate passes over the graph. We will do this in follow up CLs. R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1193833002 Cr-Commit-Position: refs/heads/master@{#29146}
2015-06-19 12:07:17 +00:00
} // namespace compiler
} // namespace internal
} // namespace v8