4940c0bd42
Now all nodes that care about deoptimization always take frame state inputs no matter whether deoptimization is enabled for a particular function. In case that deoptimization is off, the AstGraphBuilder just inserts the empty frame state. This greatly simplifies the logic in various places and makes testing easier as well, and is probably the first step towards enabling --turbo-deoptimization by default. There seems to be no noticable performance impact on asm.js programs. Also fix the graph replay in order to regenerate the scheduler unittests. Review URL: https://codereview.chromium.org/1106613003 Cr-Commit-Position: refs/heads/master@{#28026}
138 lines
5.3 KiB
C++
138 lines
5.3 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/control-flow-optimizer.h"
|
|
#include "src/compiler/js-graph.h"
|
|
#include "src/compiler/js-operator.h"
|
|
#include "src/compiler/machine-operator.h"
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
|
#include "testing/gmock-support.h"
|
|
|
|
using testing::AllOf;
|
|
using testing::Capture;
|
|
using testing::CaptureEq;
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class ControlFlowOptimizerTest : public GraphTest {
|
|
public:
|
|
explicit ControlFlowOptimizerTest(int num_parameters = 3)
|
|
: GraphTest(num_parameters),
|
|
machine_(zone()),
|
|
javascript_(zone()),
|
|
jsgraph_(isolate(), graph(), common(), javascript(), machine()) {}
|
|
~ControlFlowOptimizerTest() override {}
|
|
|
|
protected:
|
|
void Optimize() {
|
|
ControlFlowOptimizer optimizer(jsgraph(), zone());
|
|
optimizer.Optimize();
|
|
}
|
|
|
|
Node* EmptyFrameState() { return jsgraph()->EmptyFrameState(); }
|
|
|
|
JSGraph* jsgraph() { return &jsgraph_; }
|
|
JSOperatorBuilder* javascript() { return &javascript_; }
|
|
MachineOperatorBuilder* machine() { return &machine_; }
|
|
|
|
private:
|
|
MachineOperatorBuilder machine_;
|
|
JSOperatorBuilder javascript_;
|
|
JSGraph jsgraph_;
|
|
};
|
|
|
|
|
|
TEST_F(ControlFlowOptimizerTest, BuildSwitch1) {
|
|
Node* index = Parameter(0);
|
|
Node* branch0 = graph()->NewNode(
|
|
common()->Branch(),
|
|
graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(0)),
|
|
start());
|
|
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
|
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
|
Node* branch1 = graph()->NewNode(
|
|
common()->Branch(),
|
|
graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(1)),
|
|
if_false0);
|
|
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
|
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
|
Node* merge =
|
|
graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1);
|
|
graph()->SetEnd(graph()->NewNode(common()->End(), merge));
|
|
Optimize();
|
|
Capture<Node*> switch_capture;
|
|
EXPECT_THAT(end(),
|
|
IsEnd(IsMerge(IsIfValue(0, CaptureEq(&switch_capture)),
|
|
IsIfValue(1, CaptureEq(&switch_capture)),
|
|
IsIfDefault(AllOf(CaptureEq(&switch_capture),
|
|
IsSwitch(index, start()))))));
|
|
}
|
|
|
|
|
|
TEST_F(ControlFlowOptimizerTest, BuildSwitch2) {
|
|
Node* input = Parameter(0);
|
|
Node* context = Parameter(1);
|
|
Node* index = graph()->NewNode(javascript()->ToNumber(), input, context,
|
|
EmptyFrameState(), start(), start());
|
|
Node* if_success = graph()->NewNode(common()->IfSuccess(), index);
|
|
Node* branch0 = graph()->NewNode(
|
|
common()->Branch(),
|
|
graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(0)),
|
|
if_success);
|
|
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
|
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
|
Node* branch1 = graph()->NewNode(
|
|
common()->Branch(),
|
|
graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(1)),
|
|
if_false0);
|
|
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
|
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
|
Node* merge =
|
|
graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1);
|
|
graph()->SetEnd(graph()->NewNode(common()->End(), merge));
|
|
Optimize();
|
|
Capture<Node*> switch_capture;
|
|
EXPECT_THAT(
|
|
end(),
|
|
IsEnd(IsMerge(IsIfValue(0, CaptureEq(&switch_capture)),
|
|
IsIfValue(1, CaptureEq(&switch_capture)),
|
|
IsIfDefault(AllOf(CaptureEq(&switch_capture),
|
|
IsSwitch(index, IsIfSuccess(index)))))));
|
|
}
|
|
|
|
|
|
TEST_F(ControlFlowOptimizerTest, CloneBranch) {
|
|
Node* cond0 = Parameter(0);
|
|
Node* cond1 = Parameter(1);
|
|
Node* cond2 = Parameter(2);
|
|
Node* branch0 = graph()->NewNode(common()->Branch(), cond0, start());
|
|
Node* control1 = graph()->NewNode(common()->IfTrue(), branch0);
|
|
Node* control2 = graph()->NewNode(common()->IfFalse(), branch0);
|
|
Node* merge0 = graph()->NewNode(common()->Merge(2), control1, control2);
|
|
Node* phi0 =
|
|
graph()->NewNode(common()->Phi(kRepBit, 2), cond1, cond2, merge0);
|
|
Node* branch = graph()->NewNode(common()->Branch(), phi0, merge0);
|
|
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
|
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
|
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
|
graph()->SetEnd(graph()->NewNode(common()->End(), merge));
|
|
Optimize();
|
|
Capture<Node*> branch1_capture, branch2_capture;
|
|
EXPECT_THAT(
|
|
end(),
|
|
IsEnd(IsMerge(IsMerge(IsIfTrue(CaptureEq(&branch1_capture)),
|
|
IsIfTrue(CaptureEq(&branch2_capture))),
|
|
IsMerge(IsIfFalse(AllOf(CaptureEq(&branch1_capture),
|
|
IsBranch(cond1, control1))),
|
|
IsIfFalse(AllOf(CaptureEq(&branch2_capture),
|
|
IsBranch(cond2, control2)))))));
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|