Commit 13d6de49 authored by titzer's avatar titzer Committed by Commit bot

[turbofan] Introduce BranchMatcher and DiamondMatcher helpers.

R=bmeurer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1054963002

Cr-Commit-Position: refs/heads/master@{#27613}
parent ba41489d
...@@ -51,17 +51,10 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) { ...@@ -51,17 +51,10 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) {
Node* vtrue = NodeProperties::GetValueInput(node, 0); Node* vtrue = NodeProperties::GetValueInput(node, 0);
Node* vfalse = NodeProperties::GetValueInput(node, 1); Node* vfalse = NodeProperties::GetValueInput(node, 1);
Node* merge = NodeProperties::GetControlInput(node); Node* merge = NodeProperties::GetControlInput(node);
Node* if_true = NodeProperties::GetControlInput(merge, 0); DiamondMatcher matcher(merge);
Node* if_false = NodeProperties::GetControlInput(merge, 1); if (matcher.Matched()) {
if (if_true->opcode() != IrOpcode::kIfTrue) { if (matcher.IfTrue() == merge->InputAt(1)) std::swap(vtrue, vfalse);
std::swap(if_true, if_false); Node* cond = matcher.Branch()->InputAt(0);
std::swap(vtrue, vfalse);
}
if (if_true->opcode() == IrOpcode::kIfTrue &&
if_false->opcode() == IrOpcode::kIfFalse &&
if_true->InputAt(0) == if_false->InputAt(0)) {
Node* branch = if_true->InputAt(0);
Node* cond = branch->InputAt(0);
if (cond->opcode() == IrOpcode::kFloat64LessThan) { if (cond->opcode() == IrOpcode::kFloat64LessThan) {
if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse && if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
machine()->HasFloat64Min()) { machine()->HasFloat64Min()) {
......
...@@ -123,13 +123,7 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) { ...@@ -123,13 +123,7 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
return false; return false;
} }
// Grab the IfTrue/IfFalse projections of the Branch. // Grab the IfTrue/IfFalse projections of the Branch.
Node* control_projections[2]; BranchMatcher matcher(branch);
NodeProperties::CollectControlProjections(branch, control_projections,
arraysize(control_projections));
Node* if_true = control_projections[0];
Node* if_false = control_projections[1];
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
// Check/collect other Phi/EffectPhi nodes hanging off the Merge. // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
NodeVector phis(zone()); NodeVector phis(zone());
for (Node* const use : merge->uses()) { for (Node* const use : merge->uses()) {
...@@ -150,7 +144,8 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) { ...@@ -150,7 +144,8 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
if (NodeProperties::IsPhi(edge.from())) { if (NodeProperties::IsPhi(edge.from())) {
control = NodeProperties::GetControlInput(control, edge.index()); control = NodeProperties::GetControlInput(control, edge.index());
} }
if (control != if_true && control != if_false) return false; if (control != matcher.IfTrue() && control != matcher.IfFalse())
return false;
} }
phis.push_back(use); phis.push_back(use);
} }
...@@ -185,16 +180,16 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) { ...@@ -185,16 +180,16 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
if (NodeProperties::IsPhi(edge.from())) { if (NodeProperties::IsPhi(edge.from())) {
control = NodeProperties::GetControlInput(control, edge.index()); control = NodeProperties::GetControlInput(control, edge.index());
} }
DCHECK(control == if_true || control == if_false); DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse());
edge.UpdateTo((control == if_true) ? phi_true : phi_false); edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false);
} }
phi->Kill(); phi->Kill();
} }
// Fix up IfTrue and IfFalse and kill all dead nodes. // Fix up IfTrue and IfFalse and kill all dead nodes.
if_false->ReplaceUses(merge_false); matcher.IfFalse()->ReplaceUses(merge_false);
if_true->ReplaceUses(merge_true); matcher.IfTrue()->ReplaceUses(merge_true);
if_false->Kill(); matcher.IfFalse()->Kill();
if_true->Kill(); matcher.IfTrue()->Kill();
branch->Kill(); branch->Kill();
cond->Kill(); cond->Kill();
merge->Kill(); merge->Kill();
...@@ -219,12 +214,11 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { ...@@ -219,12 +214,11 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
Node* if_false; Node* if_false;
Node* if_true; Node* if_true;
while (true) { while (true) {
Node* control_projections[2]; BranchMatcher matcher(branch);
NodeProperties::CollectControlProjections(branch, control_projections, 2); DCHECK(matcher.Matched());
if_true = control_projections[0];
if_false = control_projections[1]; if_true = matcher.IfTrue();
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode()); if_false = matcher.IfFalse();
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
auto it = if_false->uses().begin(); auto it = if_false->uses().begin();
if (it == if_false->uses().end()) break; if (it == if_false->uses().end()) break;
...@@ -256,8 +250,6 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { ...@@ -256,8 +250,6 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
DCHECK_EQ(IrOpcode::kBranch, node->opcode()); DCHECK_EQ(IrOpcode::kBranch, node->opcode());
DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
if (branch == node) { if (branch == node) {
DCHECK_EQ(1u, values.size()); DCHECK_EQ(1u, values.size());
return false; return false;
......
...@@ -566,25 +566,17 @@ class ControlReducerImpl { ...@@ -566,25 +566,17 @@ class ControlReducerImpl {
// Check if it's an unused diamond. // Check if it's an unused diamond.
if (live == 2 && phis.empty()) { if (live == 2 && phis.empty()) {
Node* node0 = node->InputAt(0); DiamondMatcher matcher(node);
Node* node1 = node->InputAt(1); if (matcher.Matched() && matcher.IfProjectionsAreOwned()) {
if (((node0->opcode() == IrOpcode::kIfTrue && // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes
node1->opcode() == IrOpcode::kIfFalse) || // have uses except for the Merge and the Merge has no Phi or
(node1->opcode() == IrOpcode::kIfTrue && // EffectPhi uses, so replace the Merge with the control input of the
node0->opcode() == IrOpcode::kIfFalse)) && // diamond.
node0->OwnedBy(node) && node1->OwnedBy(node)) { TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n",
Node* branch0 = NodeProperties::GetControlInput(node0); matcher.Branch()->id(), matcher.IfTrue()->id(),
Node* branch1 = NodeProperties::GetControlInput(node1); matcher.IfFalse()->id());
if (branch0 == branch1) { // TODO(turbofan): replace single-phi diamonds with selects.
// It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes return NodeProperties::GetControlInput(matcher.Branch());
// have users except for the Merge and the Merge has no Phi or
// EffectPhi uses, so replace the Merge with the control input of the
// diamond.
TRACE(" DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(),
node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(),
branch0->id(), branch0->op()->mnemonic());
return NodeProperties::GetControlInput(branch0);
}
} }
} }
......
...@@ -12,6 +12,49 @@ bool NodeMatcher::IsComparison() const { ...@@ -12,6 +12,49 @@ bool NodeMatcher::IsComparison() const {
return IrOpcode::IsComparisonOpcode(opcode()); return IrOpcode::IsComparisonOpcode(opcode());
} }
BranchMatcher::BranchMatcher(Node* branch)
: NodeMatcher(branch), if_true_(nullptr), if_false_(nullptr) {
if (branch->opcode() != IrOpcode::kBranch) return;
for (Node* use : branch->uses()) {
if (use->opcode() == IrOpcode::kIfTrue) {
DCHECK_NULL(if_true_);
if_true_ = use;
} else if (use->opcode() == IrOpcode::kIfFalse) {
DCHECK_NULL(if_false_);
if_false_ = use;
}
}
}
DiamondMatcher::DiamondMatcher(Node* merge)
: NodeMatcher(merge),
branch_(nullptr),
if_true_(nullptr),
if_false_(nullptr) {
if (merge->InputCount() != 2) return;
if (merge->opcode() != IrOpcode::kMerge) return;
Node* input0 = merge->InputAt(0);
if (input0->InputCount() != 1) return;
Node* input1 = merge->InputAt(1);
if (input1->InputCount() != 1) return;
Node* branch = input0->InputAt(0);
if (branch != input1->InputAt(0)) return;
if (branch->opcode() != IrOpcode::kBranch) return;
if (input0->opcode() == IrOpcode::kIfTrue &&
input1->opcode() == IrOpcode::kIfFalse) {
branch_ = branch;
if_true_ = input0;
if_false_ = input1;
} else if (input0->opcode() == IrOpcode::kIfFalse &&
input1->opcode() == IrOpcode::kIfTrue) {
branch_ = branch;
if_true_ = input1;
if_false_ = input0;
}
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -542,6 +542,40 @@ typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher> ...@@ -542,6 +542,40 @@ typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher> typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
BaseWithIndexAndDisplacement64Matcher; BaseWithIndexAndDisplacement64Matcher;
struct BranchMatcher : public NodeMatcher {
explicit BranchMatcher(Node* branch);
bool Matched() const { return if_true_ && if_false_; }
Node* Branch() const { return node(); }
Node* IfTrue() const { return if_true_; }
Node* IfFalse() const { return if_false_; }
private:
Node* if_true_;
Node* if_false_;
};
struct DiamondMatcher : public NodeMatcher {
explicit DiamondMatcher(Node* merge);
bool Matched() const { return branch_; }
bool IfProjectionsAreOwned() const {
return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
}
Node* Branch() const { return branch_; }
Node* IfTrue() const { return if_true_; }
Node* IfFalse() const { return if_false_; }
Node* Merge() const { return node(); }
private:
Node* branch_;
Node* if_true_;
Node* if_false_;
};
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -728,6 +728,224 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) { ...@@ -728,6 +728,224 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
} }
TEST_F(NodeMatcherTest, BranchMatcher_match) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
BranchMatcher matcher(branch);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
BranchMatcher matcher(branch);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* other = graph()->NewNode(common()->IfValue(33), branch);
BranchMatcher matcher(branch);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
USE(other);
}
}
TEST_F(NodeMatcherTest, BranchMatcher_fail) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
BranchMatcher matcher(branch);
EXPECT_FALSE(matcher.Matched());
USE(if_true);
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
BranchMatcher matcher(branch);
EXPECT_FALSE(matcher.Matched());
USE(if_false);
}
{
BranchMatcher matcher(zero);
EXPECT_FALSE(matcher.Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
EXPECT_TRUE(BranchMatcher(branch).Matched());
EXPECT_FALSE(BranchMatcher(if_true).Matched());
EXPECT_FALSE(BranchMatcher(if_false).Matched());
}
{
Node* sw = graph()->NewNode(common()->Switch(5), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), sw);
Node* if_false = graph()->NewNode(common()->IfFalse(), sw);
EXPECT_FALSE(BranchMatcher(sw).Matched());
EXPECT_FALSE(BranchMatcher(if_true).Matched());
EXPECT_FALSE(BranchMatcher(if_false).Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_value = graph()->NewNode(common()->IfValue(2), branch);
BranchMatcher matcher(branch);
EXPECT_FALSE(matcher.Matched());
EXPECT_FALSE(BranchMatcher(if_true).Matched());
EXPECT_FALSE(BranchMatcher(if_value).Matched());
}
}
TEST_F(NodeMatcherTest, DiamondMatcher_match) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
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);
DiamondMatcher matcher(merge);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
EXPECT_EQ(merge, matcher.Merge());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
DiamondMatcher matcher(merge);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
EXPECT_EQ(merge, matcher.Merge());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_false, if_true);
DiamondMatcher matcher(merge);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
EXPECT_EQ(merge, matcher.Merge());
}
}
TEST_F(NodeMatcherTest, DiamondMatcher_fail) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_value = graph()->NewNode(common()->IfValue(1), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_value);
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* if_value = graph()->NewNode(common()->IfValue(1), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_false, if_value);
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
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);
DiamondMatcher matcher(merge);
EXPECT_TRUE(matcher.Matched());
EXPECT_EQ(branch, matcher.Branch());
EXPECT_EQ(if_true, matcher.IfTrue());
EXPECT_EQ(if_false, matcher.IfFalse());
EXPECT_EQ(merge, matcher.Merge());
EXPECT_FALSE(DiamondMatcher(branch).Matched()); // Must be the merge.
EXPECT_FALSE(DiamondMatcher(if_true).Matched());
EXPECT_FALSE(DiamondMatcher(if_false).Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* merge = graph()->NewNode(common()->Merge(3), if_true, if_false,
graph()->start());
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched()); // Too many inputs to merge.
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->start();
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched());
}
{
Node* branch = graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->start();
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched());
}
{
Node* branch1 =
graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* branch2 =
graph()->NewNode(common()->Branch(), zero, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch2);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
DiamondMatcher matcher(merge);
EXPECT_FALSE(matcher.Matched());
}
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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