Introduce and test NodeProperties::CollectControlProjections.

R=bmeurer@chromium.org
TEST=unittests/NodePropertiesTest.CollectControlProjections

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

Cr-Commit-Position: refs/heads/master@{#26720}
This commit is contained in:
mstarzinger 2015-02-18 05:55:24 -08:00 committed by Commit bot
parent 161161900b
commit 7e7e85f32e
5 changed files with 89 additions and 61 deletions

View File

@ -68,19 +68,14 @@ void ControlFlowOptimizer::VisitBranch(Node* node) {
Node* if_false; Node* if_false;
Node* if_true; Node* if_true;
while (true) { while (true) {
// TODO(turbofan): use NodeProperties::CollectSuccessorProjections() here Node* control_projections[2];
// once available. NodeProperties::CollectControlProjections(branch, control_projections, 2);
auto it = branch->uses().begin(); if_true = control_projections[0];
DCHECK(it != branch->uses().end()); if_false = control_projections[1];
if_true = *it++;
DCHECK(it != branch->uses().end());
if_false = *it++;
DCHECK(it == branch->uses().end());
if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode()); DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode()); DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
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;
Node* branch1 = *it++; Node* branch1 = *it++;
if (branch1->opcode() != IrOpcode::kBranch) break; if (branch1->opcode() != IrOpcode::kBranch) break;

View File

@ -181,6 +181,50 @@ Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
} }
// static
void NodeProperties::CollectControlProjections(Node* node, Node** projections,
size_t projection_count) {
#ifdef DEBUG
DCHECK_EQ(static_cast<int>(projection_count), node->UseCount());
std::memset(projections, 0, sizeof(*projections) * projection_count);
#endif
size_t if_value_index = 0;
for (Node* const use : node->uses()) {
size_t index;
switch (use->opcode()) {
default:
UNREACHABLE();
// Fall through.
case IrOpcode::kIfTrue:
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
index = 0;
break;
case IrOpcode::kIfFalse:
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
index = 1;
break;
case IrOpcode::kIfValue:
DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
index = if_value_index++;
break;
case IrOpcode::kIfDefault:
DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
index = projection_count - 1;
break;
}
DCHECK_LT(if_value_index, projection_count);
DCHECK_LT(index, projection_count);
DCHECK_NULL(projections[index]);
projections[index] = use;
}
#ifdef DEBUG
for (size_t index = 0; index < projection_count; ++index) {
DCHECK_NOT_NULL(projections[index]);
}
#endif
}
// static // static
bool NodeProperties::AllValueInputsAreTyped(Node* node) { bool NodeProperties::AllValueInputsAreTyped(Node* node) {
int input_count = node->op()->ValueInputCount(); int input_count = node->op()->ValueInputCount();

View File

@ -90,6 +90,12 @@ class NodeProperties FINAL {
static Node* FindProjection(Node* node, size_t projection_index); static Node* FindProjection(Node* node, size_t projection_index);
// Collect the branch-related projections from a node, such as IfTrue,
// IfFalse, IfValue and IfDefault.
// - Branch: [ IfTrue, IfFalse ]
// - Switch: [ IfValue, ..., IfDefault ]
static void CollectControlProjections(Node* node, Node** proj, size_t count);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Type Bounds. // Type Bounds.

View File

@ -364,63 +364,19 @@ class CFGBuilder : public ZoneObject {
} }
void BuildBlocksForSuccessors(Node* node) { void BuildBlocksForSuccessors(Node* node) {
size_t const successor_count = node->op()->ControlOutputCount(); size_t const successor_cnt = node->op()->ControlOutputCount();
Node** successors = zone_->NewArray<Node*>(successor_count); Node** successors = zone_->NewArray<Node*>(successor_cnt);
CollectSuccessorProjections(node, successors, successor_count); NodeProperties::CollectControlProjections(node, successors, successor_cnt);
for (size_t index = 0; index < successor_count; ++index) { for (size_t index = 0; index < successor_cnt; ++index) {
BuildBlockForNode(successors[index]); BuildBlockForNode(successors[index]);
} }
} }
// Collect the branch-related projections from a node, such as IfTrue,
// IfFalse, Case and Default.
void CollectSuccessorProjections(Node* node, Node** successors,
size_t successor_count) {
#ifdef DEBUG
DCHECK_EQ(static_cast<int>(successor_count), node->UseCount());
std::memset(successors, 0, sizeof(*successors) * successor_count);
#endif
size_t if_value_index = 0;
for (Node* const use : node->uses()) {
size_t index;
switch (use->opcode()) {
default:
UNREACHABLE();
// Fall through.
case IrOpcode::kIfTrue:
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
index = 0;
break;
case IrOpcode::kIfFalse:
DCHECK_EQ(IrOpcode::kBranch, node->opcode());
index = 1;
break;
case IrOpcode::kIfValue:
DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
index = if_value_index++;
break;
case IrOpcode::kIfDefault:
DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
index = successor_count - 1;
break;
}
DCHECK_LT(if_value_index, successor_count);
DCHECK_LT(index, successor_count);
DCHECK_NULL(successors[index]);
successors[index] = use;
}
#ifdef DEBUG
for (size_t index = 0; index < successor_count; ++index) {
DCHECK_NOT_NULL(successors[index]);
}
#endif
}
void CollectSuccessorBlocks(Node* node, BasicBlock** successor_blocks, void CollectSuccessorBlocks(Node* node, BasicBlock** successor_blocks,
size_t successor_count) { size_t successor_cnt) {
Node** successors = reinterpret_cast<Node**>(successor_blocks); Node** successors = reinterpret_cast<Node**>(successor_blocks);
CollectSuccessorProjections(node, successors, successor_count); NodeProperties::CollectControlProjections(node, successors, successor_cnt);
for (size_t index = 0; index < successor_count; ++index) { for (size_t index = 0; index < successor_cnt; ++index) {
successor_blocks[index] = schedule_->block(successors[index]); successor_blocks[index] = schedule_->block(successors[index]);
} }
} }

View File

@ -7,6 +7,7 @@
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
using testing::AnyOf;
using testing::IsNull; using testing::IsNull;
namespace v8 { namespace v8 {
@ -27,6 +28,32 @@ TEST_F(NodePropertiesTest, FindProjection) {
EXPECT_THAT(NodeProperties::FindProjection(start, 1234567890), IsNull()); EXPECT_THAT(NodeProperties::FindProjection(start, 1234567890), IsNull());
} }
TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
Node* result[2];
CommonOperatorBuilder common(zone());
Node* branch = Node::New(zone(), 1, common.Branch(), 0, nullptr, false);
Node* if_false = Node::New(zone(), 2, common.IfFalse(), 1, &branch, false);
Node* if_true = Node::New(zone(), 3, common.IfTrue(), 1, &branch, false);
NodeProperties::CollectControlProjections(branch, result, arraysize(result));
EXPECT_EQ(if_true, result[0]);
EXPECT_EQ(if_false, result[1]);
}
TEST_F(NodePropertiesTest, CollectControlProjections_Switch) {
Node* result[3];
CommonOperatorBuilder common(zone());
Node* sw = Node::New(zone(), 1, common.Switch(3), 0, nullptr, false);
Node* if_default = Node::New(zone(), 2, common.IfDefault(), 1, &sw, false);
Node* if_value1 = Node::New(zone(), 3, common.IfValue(1), 1, &sw, false);
Node* if_value2 = Node::New(zone(), 4, common.IfValue(2), 1, &sw, false);
NodeProperties::CollectControlProjections(sw, result, arraysize(result));
EXPECT_THAT(result[0], AnyOf(if_value1, if_value2));
EXPECT_THAT(result[1], AnyOf(if_value1, if_value2));
EXPECT_EQ(if_default, result[2]);
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8