a56a581b45
We would be allowing or disallowing using the local heap rather than that scope. There's one case that remains in common-operator-reducer.cc. Bug: v8:7790 Change-Id: Ice0b407aa37b3aa349fc68f4a7c2644156097e3e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2983206 Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org> Cr-Commit-Position: refs/heads/master@{#75379}
376 lines
13 KiB
C++
376 lines
13 KiB
C++
// 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 {
|
|
|
|
class DeadCodeEliminationTest : public GraphTest {
|
|
public:
|
|
explicit DeadCodeEliminationTest(int num_parameters = 4)
|
|
: GraphTest(num_parameters) {}
|
|
~DeadCodeEliminationTest() override = default;
|
|
|
|
protected:
|
|
Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) {
|
|
DeadCodeElimination reducer(editor, graph(), common(), zone());
|
|
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};
|
|
|
|
|
|
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());
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 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);
|
|
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);
|
|
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()));
|
|
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);
|
|
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);
|
|
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()));
|
|
EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement()));
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Phi
|
|
|
|
|
|
TEST_F(DeadCodeEliminationTest, PhiWithDeadControlInput) {
|
|
Node* inputs[kMaxInputs + 1];
|
|
TRACED_FOREACH(MachineRepresentation, rep, kMachineRepresentations) {
|
|
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));
|
|
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
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|