[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}
This commit is contained in:
parent
ba41489da5
commit
13d6de4986
@ -51,17 +51,10 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) {
|
||||
Node* vtrue = NodeProperties::GetValueInput(node, 0);
|
||||
Node* vfalse = NodeProperties::GetValueInput(node, 1);
|
||||
Node* merge = NodeProperties::GetControlInput(node);
|
||||
Node* if_true = NodeProperties::GetControlInput(merge, 0);
|
||||
Node* if_false = NodeProperties::GetControlInput(merge, 1);
|
||||
if (if_true->opcode() != IrOpcode::kIfTrue) {
|
||||
std::swap(if_true, if_false);
|
||||
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);
|
||||
DiamondMatcher matcher(merge);
|
||||
if (matcher.Matched()) {
|
||||
if (matcher.IfTrue() == merge->InputAt(1)) std::swap(vtrue, vfalse);
|
||||
Node* cond = matcher.Branch()->InputAt(0);
|
||||
if (cond->opcode() == IrOpcode::kFloat64LessThan) {
|
||||
if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
|
||||
machine()->HasFloat64Min()) {
|
||||
|
@ -123,13 +123,7 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
|
||||
return false;
|
||||
}
|
||||
// Grab the IfTrue/IfFalse projections of the Branch.
|
||||
Node* control_projections[2];
|
||||
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());
|
||||
BranchMatcher matcher(branch);
|
||||
// Check/collect other Phi/EffectPhi nodes hanging off the Merge.
|
||||
NodeVector phis(zone());
|
||||
for (Node* const use : merge->uses()) {
|
||||
@ -150,7 +144,8 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
|
||||
if (NodeProperties::IsPhi(edge.from())) {
|
||||
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);
|
||||
}
|
||||
@ -185,16 +180,16 @@ bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
|
||||
if (NodeProperties::IsPhi(edge.from())) {
|
||||
control = NodeProperties::GetControlInput(control, edge.index());
|
||||
}
|
||||
DCHECK(control == if_true || control == if_false);
|
||||
edge.UpdateTo((control == if_true) ? phi_true : phi_false);
|
||||
DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse());
|
||||
edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false);
|
||||
}
|
||||
phi->Kill();
|
||||
}
|
||||
// Fix up IfTrue and IfFalse and kill all dead nodes.
|
||||
if_false->ReplaceUses(merge_false);
|
||||
if_true->ReplaceUses(merge_true);
|
||||
if_false->Kill();
|
||||
if_true->Kill();
|
||||
matcher.IfFalse()->ReplaceUses(merge_false);
|
||||
matcher.IfTrue()->ReplaceUses(merge_true);
|
||||
matcher.IfFalse()->Kill();
|
||||
matcher.IfTrue()->Kill();
|
||||
branch->Kill();
|
||||
cond->Kill();
|
||||
merge->Kill();
|
||||
@ -219,12 +214,11 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
|
||||
Node* if_false;
|
||||
Node* if_true;
|
||||
while (true) {
|
||||
Node* control_projections[2];
|
||||
NodeProperties::CollectControlProjections(branch, control_projections, 2);
|
||||
if_true = control_projections[0];
|
||||
if_false = control_projections[1];
|
||||
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
|
||||
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
|
||||
BranchMatcher matcher(branch);
|
||||
DCHECK(matcher.Matched());
|
||||
|
||||
if_true = matcher.IfTrue();
|
||||
if_false = matcher.IfFalse();
|
||||
|
||||
auto it = if_false->uses().begin();
|
||||
if (it == if_false->uses().end()) break;
|
||||
@ -256,8 +250,6 @@ bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
|
||||
|
||||
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
||||
DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
|
||||
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
|
||||
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
|
||||
if (branch == node) {
|
||||
DCHECK_EQ(1u, values.size());
|
||||
return false;
|
||||
|
@ -566,25 +566,17 @@ class ControlReducerImpl {
|
||||
|
||||
// Check if it's an unused diamond.
|
||||
if (live == 2 && phis.empty()) {
|
||||
Node* node0 = node->InputAt(0);
|
||||
Node* node1 = node->InputAt(1);
|
||||
if (((node0->opcode() == IrOpcode::kIfTrue &&
|
||||
node1->opcode() == IrOpcode::kIfFalse) ||
|
||||
(node1->opcode() == IrOpcode::kIfTrue &&
|
||||
node0->opcode() == IrOpcode::kIfFalse)) &&
|
||||
node0->OwnedBy(node) && node1->OwnedBy(node)) {
|
||||
Node* branch0 = NodeProperties::GetControlInput(node0);
|
||||
Node* branch1 = NodeProperties::GetControlInput(node1);
|
||||
if (branch0 == branch1) {
|
||||
// It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes
|
||||
// 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);
|
||||
}
|
||||
DiamondMatcher matcher(node);
|
||||
if (matcher.Matched() && matcher.IfProjectionsAreOwned()) {
|
||||
// It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes
|
||||
// have uses 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:Branch #%d:IfTrue #%d:IfFalse\n",
|
||||
matcher.Branch()->id(), matcher.IfTrue()->id(),
|
||||
matcher.IfFalse()->id());
|
||||
// TODO(turbofan): replace single-phi diamonds with selects.
|
||||
return NodeProperties::GetControlInput(matcher.Branch());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,49 @@ bool NodeMatcher::IsComparison() const {
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
@ -542,6 +542,40 @@ typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
|
||||
typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
@ -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 internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user