Commit 835cc463 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Initial attempt to cleanup Node and related classes.

- Make Node::Inputs and Node::Uses mostly STL compliant.
- Get rid of some pre-C++11 crappiness.
- Start moving unit tests from cctest to unittests.
- TrimInputCount() now tries to reserve inputs slots for
  later appending.
- Fix numerous style guide violations.

TEST=cctest,unittests
R=dcarney@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#26098}
parent 6950ead0
......@@ -546,6 +546,7 @@ source_set("v8_base") {
"src/compiler/node-marker.cc",
"src/compiler/node-marker.h",
"src/compiler/node-matchers.h",
"src/compiler/node-properties.cc",
"src/compiler/node-properties-inl.h",
"src/compiler/node-properties.h",
"src/compiler/node.cc",
......
......@@ -5,6 +5,7 @@
#include "src/base/bits.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
......@@ -1035,9 +1036,9 @@ void InstructionSelector::VisitCall(Node* node) {
// TODO(dcarney): might be possible to use claim/poke instead
// Push any stack arguments.
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
Emit(kArmPush, NULL, g.UseRegister(*input));
for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
++i) {
Emit(kArmPush, nullptr, g.UseRegister(*i));
}
// Select the appropriate opcode based on the call type.
......@@ -1180,14 +1181,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* const node = value->InputAt(0);
Node* const result = node->FindProjection(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (!result || selector->IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -1286,7 +1287,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
}
......@@ -1296,7 +1297,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
}
......
......@@ -4,6 +4,7 @@
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
......@@ -1310,14 +1311,14 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* node = value->InputAt(0);
Node* result = node->FindProjection(0);
Node* const node = value->InputAt(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (result == NULL || IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -1461,7 +1462,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
kArithmeticImm, &cont);
......@@ -1472,7 +1473,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
kArithmeticImm, &cont);
......
......@@ -103,6 +103,12 @@ std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
}
size_t ProjectionIndexOf(const Operator* const op) {
DCHECK_EQ(IrOpcode::kProjection, op->opcode());
return OpParameter<size_t>(op);
}
#define CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 0, 0, 1) \
V(End, Operator::kFoldable, 0, 0, 1, 0, 0, 0) \
......
......@@ -153,6 +153,9 @@ size_t hash_value(FrameStateCallInfo const&);
std::ostream& operator<<(std::ostream&, FrameStateCallInfo const&);
size_t ProjectionIndexOf(const Operator* const);
// Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level.
class CommonOperatorBuilder FINAL : public ZoneObject {
......
......@@ -106,8 +106,9 @@ class ControlReducerImpl {
marked.Push(start);
marked.SetReachableFromStart(start);
// We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal.
typedef std::pair<Node*, UseIter> FwIter;
// We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid
// O(n^2) traversal.
typedef std::pair<Node*, Node::Uses::const_iterator> FwIter;
ZoneVector<FwIter> fw_stack(zone_);
fw_stack.push_back(FwIter(start, start->uses().begin()));
......@@ -420,8 +421,8 @@ class ControlReducerImpl {
}
Node* replacement = NULL;
Node::Inputs inputs = node->inputs();
for (InputIter it = inputs.begin(); n > 1; --n, ++it) {
auto const inputs = node->inputs();
for (auto it = inputs.begin(); n > 1; --n, ++it) {
Node* input = *it;
if (input->opcode() == IrOpcode::kDead) continue; // ignore dead inputs.
if (input != node && input != replacement) { // non-redundant input.
......
......@@ -154,9 +154,11 @@ void GraphReducer::ReduceTop() {
// Otherwise {node} was replaced by a new node. Replace all old uses of
// {node} with {replacement}. New nodes created by this reduction can
// use {node}.
node->ReplaceUsesIf(
[node_count](Node* const node) { return node->id() < node_count; },
replacement);
for (Edge edge : node->use_edges()) {
if (edge.from()->id() < node_count) {
edge.UpdateTo(replacement);
}
}
// Unlink {node} if it's no longer used.
if (node->uses().empty()) {
node->Kill();
......
......@@ -417,7 +417,8 @@ class GraphC1Visualizer {
void PrintNodeId(Node* n);
void PrintNode(Node* n);
void PrintInputs(Node* n);
void PrintInputs(InputIter* i, int count, const char* prefix);
template <typename InputIterator>
void PrintInputs(InputIterator* i, int count, const char* prefix);
void PrintType(Node* node);
void PrintLiveRange(LiveRange* range, const char* type);
......@@ -516,7 +517,8 @@ void GraphC1Visualizer::PrintNode(Node* n) {
}
void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
template <typename InputIterator>
void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
const char* prefix) {
if (count > 0) {
os_ << prefix;
......
......@@ -734,11 +734,11 @@ void InstructionSelector::VisitCall(Node* node) {
InitializeCallBuffer(node, &buffer, true, true);
// Push any stack arguments.
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
++i) {
// TODO(titzer): handle pushing double parameters.
Emit(kIA32Push, NULL,
g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
Emit(kIA32Push, nullptr,
g.CanBeImmediate(*i) ? g.UseImmediate(*i) : g.Use(*i));
}
// Select the appropriate opcode based on the call type.
......@@ -877,14 +877,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* node = value->InputAt(0);
Node* result = node->FindProjection(0);
Node* const node = value->InputAt(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (result == NULL || selector->IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -959,7 +959,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kIA32Add, &cont);
}
......@@ -969,7 +969,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kIA32Sub, &cont);
}
......
......@@ -337,8 +337,14 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
if (buffer->descriptor->ReturnCount() == 1) {
buffer->output_nodes.push_back(call);
} else {
buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), NULL);
call->CollectProjections(&buffer->output_nodes);
buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), nullptr);
for (auto use : call->uses()) {
if (use->opcode() != IrOpcode::kProjection) continue;
size_t const index = ProjectionIndexOf(use->op());
DCHECK_LT(index, buffer->output_nodes.size());
DCHECK_EQ(nullptr, buffer->output_nodes[index]);
buffer->output_nodes[index] = use;
}
}
// Filter out the outputs that aren't live because no projection uses them.
......@@ -1000,10 +1006,10 @@ void InstructionSelector::VisitProjection(Node* node) {
switch (value->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32SubWithOverflow:
if (OpParameter<size_t>(node) == 0) {
if (ProjectionIndexOf(node->op()) == 0u) {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
} else {
DCHECK(OpParameter<size_t>(node) == 1u);
DCHECK(ProjectionIndexOf(node->op()) == 1u);
MarkAsUsed(value);
}
break;
......
......@@ -407,10 +407,8 @@ void JSInliner::TryInlineJSCall(Node* call_node) {
CreateArgumentsAdaptorFrameState(&call, function, info.zone());
}
for (NodeVectorConstIter it = visitor.copies().begin();
it != visitor.copies().end(); ++it) {
Node* node = *it;
if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
for (Node* node : visitor.copies()) {
if (node && node->opcode() == IrOpcode::kFrameState) {
AddClosureToFrameState(node, function);
NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
}
......
......@@ -130,7 +130,7 @@ Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
Reduction MachineOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kProjection:
return ReduceProjection(OpParameter<size_t>(node), node->InputAt(0));
return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
case IrOpcode::kWord32And:
return ReduceWord32And(node);
case IrOpcode::kWord32Or:
......
......@@ -5,6 +5,7 @@
#include "src/base/bits.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
......@@ -468,10 +469,10 @@ void InstructionSelector::VisitCall(Node* node) {
Emit(kMipsStackClaim | MiscField::encode(push_count), NULL);
}
int slot = buffer.pushed_nodes.size() - 1;
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
Emit(kMipsStoreToStackSlot | MiscField::encode(slot), NULL,
g.UseRegister(*input));
for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
++i) {
Emit(kMipsStoreToStackSlot | MiscField::encode(slot), nullptr,
g.UseRegister(*i));
slot--;
}
......@@ -691,14 +692,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* const node = value->InputAt(0);
Node* const result = node->FindProjection(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (!result || selector->IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -778,7 +779,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMipsAddOvf, &cont);
}
......@@ -788,7 +789,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMipsSubOvf, &cont);
}
......
......@@ -5,6 +5,7 @@
#include "src/base/bits.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
......@@ -648,10 +649,10 @@ void InstructionSelector::VisitCall(Node* node) {
Emit(kMips64StackClaim | MiscField::encode(push_count), NULL);
}
int slot = buffer.pushed_nodes.size() - 1;
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
Emit(kMips64StoreToStackSlot | MiscField::encode(slot), NULL,
g.UseRegister(*input));
for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
++i) {
Emit(kMips64StoreToStackSlot | MiscField::encode(slot), nullptr,
g.UseRegister(*i));
slot--;
}
......@@ -920,14 +921,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* node = value->InputAt(0);
Node* result = node->FindProjection(0);
Node* const node = value->InputAt(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (result == NULL || selector->IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -1000,7 +1001,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dadd, &cont);
}
......@@ -1010,7 +1011,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dsub, &cont);
}
......
// 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/node-properties.h"
namespace v8 {
namespace internal {
namespace compiler {
Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
for (auto use : node->uses()) {
if (use->opcode() == IrOpcode::kProjection &&
ProjectionIndexOf(use->op()) == projection_index) {
return use;
}
}
return nullptr;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -39,7 +39,9 @@ class NodeProperties {
static inline void ReplaceFrameStateInput(Node* node, Node* frame_state);
static inline void RemoveNonValueInputs(Node* node);
static inline void ReplaceWithValue(Node* node, Node* value,
Node* effect = NULL);
Node* effect = nullptr);
static Node* FindProjection(Node* node, size_t projection_index);
static inline bool IsTyped(Node* node);
static inline Bounds GetBounds(Node* node);
......
......@@ -4,24 +4,12 @@
#include "src/compiler/node.h"
#include <algorithm>
namespace v8 {
namespace internal {
namespace compiler {
Node::Node(NodeId id, const Operator* op, int input_count,
int reserved_input_count)
: op_(op),
mark_(0),
id_(id),
bit_field_(InputCountField::encode(input_count) |
ReservedInputCountField::encode(reserved_input_count) |
HasAppendableInputsField::encode(false)),
first_use_(nullptr),
last_use_(nullptr) {
inputs_.static_ = reinterpret_cast<Input*>(this + 1);
}
Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
Node** inputs, bool has_extensible_inputs) {
size_t node_size = sizeof(Node);
......@@ -57,28 +45,67 @@ void Node::Kill() {
}
void Node::CollectProjections(NodeVector* projections) {
for (size_t i = 0; i < projections->size(); i++) {
(*projections)[i] = NULL;
void Node::AppendInput(Zone* zone, Node* new_to) {
DCHECK_NOT_NULL(zone);
DCHECK_NOT_NULL(new_to);
Use* new_use = new (zone) Use;
Input new_input;
new_input.to = new_to;
new_input.use = new_use;
if (reserved_input_count() > 0) {
DCHECK(!has_appendable_inputs());
set_reserved_input_count(reserved_input_count() - 1);
inputs_.static_[input_count()] = new_input;
} else {
EnsureAppendableInputs(zone);
inputs_.appendable_->push_back(new_input);
}
for (UseIter i = uses().begin(); i != uses().end(); ++i) {
if ((*i)->opcode() != IrOpcode::kProjection) continue;
size_t index = OpParameter<size_t>(*i);
DCHECK_LT(index, projections->size());
DCHECK_EQ(NULL, (*projections)[index]);
(*projections)[index] = *i;
new_use->input_index = input_count();
new_use->from = this;
new_to->AppendUse(new_use);
set_input_count(input_count() + 1);
}
void Node::InsertInput(Zone* zone, int index, Node* new_to) {
DCHECK_NOT_NULL(zone);
DCHECK_LE(0, index);
DCHECK_LT(index, InputCount());
AppendInput(zone, InputAt(InputCount() - 1));
for (int i = InputCount() - 1; i > index; --i) {
ReplaceInput(i, InputAt(i - 1));
}
ReplaceInput(index, new_to);
}
Node* Node::FindProjection(size_t projection_index) {
for (UseIter i = uses().begin(); i != uses().end(); ++i) {
if ((*i)->opcode() == IrOpcode::kProjection &&
OpParameter<size_t>(*i) == projection_index) {
return *i;
}
void Node::RemoveInput(int index) {
DCHECK_LE(0, index);
DCHECK_LT(index, InputCount());
for (; index < InputCount() - 1; ++index) {
ReplaceInput(index, InputAt(index + 1));
}
TrimInputCount(InputCount() - 1);
}
void Node::RemoveAllInputs() {
for (Edge edge : input_edges()) edge.UpdateTo(nullptr);
}
void Node::TrimInputCount(int new_input_count) {
DCHECK_LE(new_input_count, input_count());
if (new_input_count == input_count()) return; // Nothing to do.
for (int index = new_input_count; index < input_count(); ++index) {
ReplaceInput(index, nullptr);
}
if (!has_appendable_inputs()) {
set_reserved_input_count(std::min<int>(
ReservedInputCountField::kMax,
reserved_input_count() + (input_count() - new_input_count)));
}
return NULL;
set_input_count(new_input_count);
}
......@@ -94,11 +121,102 @@ int Node::UseCount() const {
Node* Node::UseAt(int index) const {
DCHECK_LE(0, index);
DCHECK_LT(index, UseCount());
Use* current = first_use_;
const Use* use = first_use_;
while (index-- != 0) {
current = current->next;
use = use->next;
}
return use->from;
}
void Node::ReplaceUses(Node* replace_to) {
for (Use* use = first_use_; use; use = use->next) {
use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
}
if (!replace_to->last_use_) {
DCHECK_EQ(nullptr, replace_to->first_use_);
replace_to->first_use_ = first_use_;
replace_to->last_use_ = last_use_;
} else if (first_use_) {
DCHECK_NOT_NULL(replace_to->first_use_);
replace_to->last_use_->next = first_use_;
first_use_->prev = replace_to->last_use_;
replace_to->last_use_ = last_use_;
}
first_use_ = nullptr;
last_use_ = nullptr;
}
void Node::Input::Update(Node* new_to) {
Node* old_to = this->to;
if (new_to == old_to) return; // Nothing to do.
// Snip out the use from where it used to be
if (old_to) {
old_to->RemoveUse(use);
}
to = new_to;
// And put it into the new node's use list.
if (new_to) {
new_to->AppendUse(use);
} else {
use->next = nullptr;
use->prev = nullptr;
}
}
Node::Node(NodeId id, const Operator* op, int input_count,
int reserved_input_count)
: op_(op),
mark_(0),
id_(id),
bit_field_(InputCountField::encode(input_count) |
ReservedInputCountField::encode(reserved_input_count) |
HasAppendableInputsField::encode(false)),
first_use_(nullptr),
last_use_(nullptr) {
inputs_.static_ = reinterpret_cast<Input*>(this + 1);
}
void Node::EnsureAppendableInputs(Zone* zone) {
if (!has_appendable_inputs()) {
void* deque_buffer = zone->New(sizeof(InputDeque));
InputDeque* deque = new (deque_buffer) InputDeque(zone);
for (int i = 0; i < input_count(); ++i) {
deque->push_back(inputs_.static_[i]);
}
inputs_.appendable_ = deque;
set_has_appendable_inputs(true);
}
}
void Node::AppendUse(Use* const use) {
use->next = nullptr;
use->prev = last_use_;
if (last_use_) {
last_use_->next = use;
} else {
first_use_ = use;
}
last_use_ = use;
}
void Node::RemoveUse(Use* const use) {
if (use == last_use_) {
last_use_ = use->prev;
}
if (use->prev) {
use->prev->next = use->next;
} else {
first_use_ = use->next;
}
if (use->next) {
use->next->prev = use->prev;
}
return current->from;
}
......@@ -115,6 +233,46 @@ std::ostream& operator<<(std::ostream& os, const Node& n) {
return os;
}
Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
iterator result(*this);
++(*this);
return result;
}
bool Node::InputEdges::empty() const { return begin() == end(); }
Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
const_iterator result(*this);
++(*this);
return result;
}
bool Node::Inputs::empty() const { return begin() == end(); }
Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) {
iterator result(*this);
++(*this);
return result;
}
bool Node::UseEdges::empty() const { return begin() == end(); }
Node::Uses::const_iterator Node::Uses::const_iterator::operator++(int n) {
const_iterator result(*this);
++(*this);
return result;
}
bool Node::Uses::empty() const { return begin() == end(); }
} // namespace compiler
} // namespace internal
} // namespace v8
This diff is collapsed.
......@@ -127,11 +127,10 @@ void Scheduler::UpdatePlacement(Node* node, Placement placement) {
#undef DEFINE_CONTROL_CASE
{
// Control nodes force coupled uses to be placed.
Node::Uses uses = node->uses();
for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
if (GetPlacement(*i) == Scheduler::kCoupled) {
DCHECK_EQ(node, NodeProperties::GetControlInput(*i));
UpdatePlacement(*i, placement);
for (auto use : node->uses()) {
if (GetPlacement(use) == Scheduler::kCoupled) {
DCHECK_EQ(node, NodeProperties::GetControlInput(use));
UpdatePlacement(use, placement);
}
}
break;
......@@ -1131,8 +1130,8 @@ class ScheduleEarlyNodeVisitor {
// Run the schedule early algorithm on a set of fixed root nodes.
void Run(NodeVector* roots) {
for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
queue_.push(*i);
for (Node* const root : *roots) {
queue_.push(root);
while (!queue_.empty()) {
VisitNode(queue_.front());
queue_.pop();
......@@ -1160,9 +1159,8 @@ class ScheduleEarlyNodeVisitor {
// Propagate schedule early position.
DCHECK(data->minimum_block_ != NULL);
Node::Uses uses = node->uses();
for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
PropagateMinimumPositionToNode(data->minimum_block_, *i);
for (auto use : node->uses()) {
PropagateMinimumPositionToNode(data->minimum_block_, use);
}
}
......@@ -1236,8 +1234,8 @@ class ScheduleLateNodeVisitor {
// Run the schedule late algorithm on a set of fixed root nodes.
void Run(NodeVector* roots) {
for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
ProcessQueue(*i);
for (Node* const root : *roots) {
ProcessQueue(root);
}
}
......@@ -1404,7 +1402,7 @@ void Scheduler::SealFinalSchedule() {
for (NodeVector& nodes : scheduled_nodes_) {
BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++);
BasicBlock* block = schedule_->GetBlockById(id);
for (NodeVectorRIter i = nodes.rbegin(); i != nodes.rend(); ++i) {
for (auto i = nodes.rbegin(); i != nodes.rend(); ++i) {
schedule_->AddNode(block, *i);
}
}
......@@ -1472,9 +1470,9 @@ void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(),
to->id().ToInt());
NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]);
for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) {
schedule_->SetBlockForNode(to, *i);
scheduled_nodes_[to->id().ToSize()].push_back(*i);
for (Node* const node : *nodes) {
schedule_->SetBlockForNode(to, node);
scheduled_nodes_[to->id().ToSize()].push_back(node);
}
nodes->clear();
}
......
......@@ -4,6 +4,7 @@
#include "src/compiler/verifier.h"
#include <algorithm>
#include <deque>
#include <queue>
#include <sstream>
......@@ -28,20 +29,14 @@ namespace compiler {
static bool IsDefUseChainLinkPresent(Node* def, Node* use) {
Node::Uses uses = def->uses();
for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
if (*it == use) return true;
}
return false;
auto const uses = def->uses();
return std::find(uses.begin(), uses.end(), use) != uses.end();
}
static bool IsUseDefChainLinkPresent(Node* def, Node* use) {
Node::Inputs inputs = use->inputs();
for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) {
if (*it == def) return true;
}
return false;
auto const inputs = use->inputs();
return std::find(inputs.begin(), inputs.end(), def) != inputs.end();
}
......@@ -205,13 +200,12 @@ void Verifier::Visitor::Pre(Node* node) {
UNREACHABLE();
case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse.
Node::Uses uses = node->uses();
int count_true = 0, count_false = 0;
for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
(*it)->opcode() == IrOpcode::kIfFalse);
if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
for (auto use : node->uses()) {
CHECK(use->opcode() == IrOpcode::kIfTrue ||
use->opcode() == IrOpcode::kIfFalse);
if (use->opcode() == IrOpcode::kIfTrue) ++count_true;
if (use->opcode() == IrOpcode::kIfFalse) ++count_false;
}
CHECK(count_true == 1 && count_false == 1);
// Type is empty.
......@@ -314,7 +308,7 @@ void Verifier::Visitor::Pre(Node* node) {
break;
case IrOpcode::kProjection: {
// Projection has an input that produces enough values.
int index = static_cast<int>(OpParameter<size_t>(node->op()));
int index = static_cast<int>(ProjectionIndexOf(node->op()));
Node* input = NodeProperties::GetValueInput(node, 0);
CHECK_GT(input->op()->ValueOutputCount(), index);
// Type can be anything.
......
......@@ -4,6 +4,7 @@
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
......@@ -938,11 +939,11 @@ void InstructionSelector::VisitCall(Node* node) {
InitializeCallBuffer(node, &buffer, true, true);
// Push any stack arguments.
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
++i) {
// TODO(titzer): handle pushing double parameters.
Emit(kX64Push, NULL,
g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
Emit(kX64Push, nullptr,
g.CanBeImmediate(*i) ? g.UseImmediate(*i) : g.Use(*i));
}
// Select the appropriate opcode based on the call type.
......@@ -1111,14 +1112,14 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* node = value->InputAt(0);
Node* result = node->FindProjection(0);
Node* const node = value->InputAt(0);
Node* const result = NodeProperties::FindProjection(node, 0);
if (result == NULL || IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
......@@ -1248,7 +1249,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
VisitBinop(this, node, kX64Add32, &cont);
}
......@@ -1258,7 +1259,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kX64Sub32, &cont);
}
......
......@@ -52,10 +52,8 @@ static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
bool IsUsedBy(Node* a, Node* b) {
for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
if (b == *i) return true;
}
return false;
auto const uses = a->uses();
return std::find(uses.begin(), uses.end(), b) != uses.end();
}
......
......@@ -16,136 +16,26 @@ using namespace v8::internal::compiler;
static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
"dummy", 0, 0, 0, 1, 0, 0);
TEST(NodeAllocation) {
GraphTester graph;
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator);
CHECK(n2->id() != n1->id());
}
TEST(NodeWithOpcode) {
GraphTester graph;
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator);
CHECK(n1->op() == &dummy_operator);
CHECK(n2->op() == &dummy_operator);
}
TEST(NodeInputs1) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator, n0);
CHECK_EQ(1, n2->InputCount());
CHECK(n0 == n2->InputAt(0));
}
TEST(NodeInputs2) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
CHECK_EQ(2, n2->InputCount());
CHECK(n0 == n2->InputAt(0));
CHECK(n1 == n2->InputAt(1));
}
TEST(NodeInputs3) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator, n0, n1, n1);
CHECK_EQ(3, n2->InputCount());
CHECK(n0 == n2->InputAt(0));
CHECK(n1 == n2->InputAt(1));
CHECK(n1 == n2->InputAt(2));
}
TEST(NodeInputIteratorEmpty) {
GraphTester graph;
Node* n1 = graph.NewNode(&dummy_operator);
Node::Inputs::iterator i(n1->inputs().begin());
int input_count = 0;
for (; i != n1->inputs().end(); ++i) {
input_count++;
}
CHECK_EQ(0, input_count);
}
TEST(NodeInputIteratorOne) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node::Inputs::iterator i(n1->inputs().begin());
CHECK_EQ(1, n1->InputCount());
CHECK_EQ(n0, *i);
++i;
CHECK(n1->inputs().end() == i);
}
TEST(NodeUseIteratorEmpty) {
GraphTester graph;
Node* n1 = graph.NewNode(&dummy_operator);
int use_count = 0;
for (Edge const edge : n1->use_edges()) {
USE(edge);
use_count++;
}
CHECK_EQ(0, use_count);
}
TEST(NodeUseIteratorOne) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node::Uses::iterator i(n0->uses().begin());
CHECK_EQ(n1, *i);
++i;
CHECK(n0->uses().end() == i);
}
TEST(NodeUseIteratorReplaceNoUses) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator);
Node* n3 = graph.NewNode(&dummy_operator, n2);
n0->ReplaceUses(n1);
CHECK(n0->uses().begin() == n0->uses().end());
n0->ReplaceUses(n2);
CHECK(n0->uses().begin() == n0->uses().end());
USE(n3);
}
TEST(NodeUseIteratorReplaceUses) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node* n2 = graph.NewNode(&dummy_operator, n0);
Node* n3 = graph.NewNode(&dummy_operator);
Node::Uses::iterator i1(n0->uses().begin());
auto i1(n0->uses().begin());
CHECK_EQ(n1, *i1);
++i1;
CHECK_EQ(n2, *i1);
n0->ReplaceUses(n3);
Node::Uses::iterator i2(n3->uses().begin());
auto i2(n3->uses().begin());
CHECK_EQ(n1, *i2);
++i2;
CHECK_EQ(n2, *i2);
Node::Inputs::iterator i3(n1->inputs().begin());
auto i3(n1->inputs().begin());
CHECK_EQ(n3, *i3);
++i3;
CHECK(n1->inputs().end() == i3);
Node::Inputs::iterator i4(n2->inputs().begin());
auto i4(n2->inputs().begin());
CHECK_EQ(n3, *i4);
++i4;
CHECK(n2->inputs().end() == i4);
......@@ -160,14 +50,14 @@ TEST(NodeUseIteratorReplaceUsesSelf) {
n1->ReplaceInput(0, n1); // Create self-reference.
Node::Uses::iterator i1(n1->uses().begin());
auto i1(n1->uses().begin());
CHECK_EQ(n1, *i1);
n1->ReplaceUses(n3);
CHECK(n1->uses().begin() == n1->uses().end());
Node::Uses::iterator i2(n3->uses().begin());
auto i2(n3->uses().begin());
CHECK_EQ(n1, *i2);
++i2;
CHECK(n1->uses().end() == i2);
......@@ -180,7 +70,7 @@ TEST(ReplaceInput) {
Node* n1 = graph.NewNode(&dummy_operator);
Node* n2 = graph.NewNode(&dummy_operator);
Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
Node::Inputs::iterator i1(n3->inputs().begin());
auto i1(n3->inputs().begin());
CHECK(n0 == *i1);
CHECK_EQ(n0, n3->InputAt(0));
++i1;
......@@ -192,26 +82,26 @@ TEST(ReplaceInput) {
++i1;
CHECK(i1 == n3->inputs().end());
Node::Uses::iterator i2(n1->uses().begin());
auto i2(n1->uses().begin());
CHECK_EQ(n3, *i2);
++i2;
CHECK(i2 == n1->uses().end());
Node* n4 = graph.NewNode(&dummy_operator);
Node::Uses::iterator i3(n4->uses().begin());
auto i3(n4->uses().begin());
CHECK(i3 == n4->uses().end());
n3->ReplaceInput(1, n4);
Node::Uses::iterator i4(n1->uses().begin());
auto i4(n1->uses().begin());
CHECK(i4 == n1->uses().end());
Node::Uses::iterator i5(n4->uses().begin());
auto i5(n4->uses().begin());
CHECK_EQ(n3, *i5);
++i5;
CHECK(i5 == n4->uses().end());
Node::Inputs::iterator i6(n3->inputs().begin());
auto i6(n3->inputs().begin());
CHECK(n0 == *i6);
CHECK_EQ(n0, n3->InputAt(0));
++i6;
......@@ -321,7 +211,7 @@ TEST(Inputs) {
// Make sure uses have been hooked op correctly.
Node::Uses uses(n4->uses());
Node::Uses::iterator current = uses.begin();
auto current = uses.begin();
CHECK(current != uses.end());
CHECK(*current == n3);
++current;
......@@ -450,7 +340,7 @@ TEST(ReplaceUsesFromAppendedInputs) {
CHECK_EQ(3, n3->UseCount());
Node::Uses uses(n3->uses());
Node::Uses::iterator current = uses.begin();
auto current = uses.begin();
CHECK(current != uses.end());
CHECK(*current == n1);
++current;
......@@ -464,76 +354,6 @@ TEST(ReplaceUsesFromAppendedInputs) {
}
template <bool result>
struct FixedPredicate {
bool operator()(const Node* node) const { return result; }
};
TEST(ReplaceUsesIfWithFixedPredicate) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node* n2 = graph.NewNode(&dummy_operator, n0);
Node* n3 = graph.NewNode(&dummy_operator);
CHECK_EQ(0, n2->UseCount());
n2->ReplaceUsesIf(FixedPredicate<true>(), n1);
CHECK_EQ(0, n2->UseCount());
n2->ReplaceUsesIf(FixedPredicate<false>(), n1);
CHECK_EQ(0, n2->UseCount());
CHECK_EQ(0, n3->UseCount());
n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
CHECK_EQ(0, n3->UseCount());
n3->ReplaceUsesIf(FixedPredicate<false>(), n1);
CHECK_EQ(0, n3->UseCount());
CHECK_EQ(2, n0->UseCount());
CHECK_EQ(0, n1->UseCount());
n0->ReplaceUsesIf(FixedPredicate<false>(), n1);
CHECK_EQ(2, n0->UseCount());
CHECK_EQ(0, n1->UseCount());
n0->ReplaceUsesIf(FixedPredicate<true>(), n1);
CHECK_EQ(0, n0->UseCount());
CHECK_EQ(2, n1->UseCount());
n1->AppendInput(graph.zone(), n1);
CHECK_EQ(3, n1->UseCount());
n1->AppendInput(graph.zone(), n3);
CHECK_EQ(1, n3->UseCount());
n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
CHECK_EQ(4, n1->UseCount());
CHECK_EQ(0, n3->UseCount());
n1->ReplaceUsesIf(FixedPredicate<false>(), n3);
CHECK_EQ(4, n1->UseCount());
CHECK_EQ(0, n3->UseCount());
}
TEST(ReplaceUsesIfWithEqualTo) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
CHECK_EQ(0, n2->UseCount());
n2->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n1), n0);
CHECK_EQ(0, n2->UseCount());
CHECK_EQ(2, n0->UseCount());
CHECK_EQ(1, n1->UseCount());
n1->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n0), n0);
CHECK_EQ(2, n0->UseCount());
CHECK_EQ(1, n1->UseCount());
n0->ReplaceUsesIf(std::bind2nd(std::equal_to<Node*>(), n2), n1);
CHECK_EQ(1, n0->UseCount());
CHECK_EQ(2, n1->UseCount());
}
TEST(ReplaceInputMultipleUses) {
GraphTester graph;
......
......@@ -105,6 +105,26 @@ Node* TypedGraphTest::Parameter(Type* type, int32_t index) {
return node;
}
namespace {
const Operator kDummyOperator(0, Operator::kNoProperties, "Dummy", 0, 0, 0, 1,
0, 0);
} // namespace
TEST_F(GraphTest, NewNode) {
Node* n0 = graph()->NewNode(&kDummyOperator);
Node* n1 = graph()->NewNode(&kDummyOperator);
EXPECT_NE(n0, n1);
EXPECT_LT(0, n0->id());
EXPECT_LT(0, n1->id());
EXPECT_NE(n0->id(), n1->id());
EXPECT_EQ(&kDummyOperator, n0->op());
EXPECT_EQ(&kDummyOperator, n1->op());
}
} // namespace compiler
} // namespace internal
} // namespace v8
// 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/node-properties-inl.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::IsNull;
namespace v8 {
namespace internal {
namespace compiler {
typedef TestWithZone NodePropertiesTest;
TEST_F(NodePropertiesTest, FindProjection) {
CommonOperatorBuilder common(zone());
Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
Node* proj0 = Node::New(zone(), 1, common.Projection(0), 1, &start, false);
Node* proj1 = Node::New(zone(), 2, common.Projection(1), 1, &start, false);
EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0));
EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1));
EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull());
EXPECT_THAT(NodeProperties::FindProjection(start, 1234567890), IsNull());
}
} // namespace compiler
} // namespace internal
} // namespace v8
// 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/node.h"
#include "src/compiler/operator.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock-support.h"
using testing::ElementsAre;
using testing::UnorderedElementsAre;
namespace v8 {
namespace internal {
namespace compiler {
typedef TestWithZone NodeTest;
namespace {
const IrOpcode::Value kOpcode0 = static_cast<IrOpcode::Value>(0);
const IrOpcode::Value kOpcode1 = static_cast<IrOpcode::Value>(1);
const IrOpcode::Value kOpcode2 = static_cast<IrOpcode::Value>(2);
const Operator kOp0(kOpcode0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 0, 0);
const Operator kOp1(kOpcode1, Operator::kNoProperties, "Op1", 1, 0, 0, 1, 0, 0);
const Operator kOp2(kOpcode2, Operator::kNoProperties, "Op2", 2, 0, 0, 1, 0, 0);
} // namespace
TEST_F(NodeTest, New) {
Node* const node = Node::New(zone(), 1, &kOp0, 0, nullptr, false);
EXPECT_EQ(1, node->id());
EXPECT_EQ(0, node->UseCount());
EXPECT_TRUE(node->uses().empty());
EXPECT_EQ(0, node->InputCount());
EXPECT_TRUE(node->inputs().empty());
EXPECT_EQ(&kOp0, node->op());
EXPECT_EQ(kOpcode0, node->opcode());
}
TEST_F(NodeTest, NewWithInputs) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(0, n0->UseCount());
EXPECT_EQ(0, n0->InputCount());
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_EQ(1, n0->UseCount());
EXPECT_EQ(n1, n0->UseAt(0));
EXPECT_EQ(0, n1->UseCount());
EXPECT_EQ(1, n1->InputCount());
EXPECT_EQ(n0, n1->InputAt(0));
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_EQ(2, n0->UseCount());
EXPECT_EQ(n1, n0->UseAt(0));
EXPECT_EQ(n2, n0->UseAt(1));
EXPECT_EQ(2, n2->InputCount());
EXPECT_EQ(n0, n2->InputAt(0));
EXPECT_EQ(n1, n2->InputAt(1));
}
TEST_F(NodeTest, InputIteratorEmpty) {
Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(node->inputs().begin(), node->inputs().end());
}
TEST_F(NodeTest, InputIteratorOne) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_THAT(n1->inputs(), ElementsAre(n0));
}
TEST_F(NodeTest, InputIteratorTwo) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_THAT(n2->inputs(), ElementsAre(n0, n1));
}
TEST_F(NodeTest, UseIteratorEmpty) {
Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(node->uses().begin(), node->uses().end());
}
TEST_F(NodeTest, UseIteratorOne) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_THAT(n0->uses(), ElementsAre(n1));
}
TEST_F(NodeTest, UseIteratorTwo) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2));
}
TEST_F(NodeTest, OwnedBy) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_FALSE(n0->OwnedBy(n0));
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_FALSE(n0->OwnedBy(n0));
EXPECT_FALSE(n1->OwnedBy(n1));
EXPECT_TRUE(n0->OwnedBy(n1));
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_FALSE(n0->OwnedBy(n0));
EXPECT_FALSE(n1->OwnedBy(n1));
EXPECT_FALSE(n2->OwnedBy(n2));
EXPECT_FALSE(n0->OwnedBy(n1));
EXPECT_FALSE(n0->OwnedBy(n2));
EXPECT_TRUE(n1->OwnedBy(n2));
n2->ReplaceInput(0, n2);
EXPECT_TRUE(n0->OwnedBy(n1));
EXPECT_TRUE(n1->OwnedBy(n2));
n2->ReplaceInput(1, n0);
EXPECT_FALSE(n0->OwnedBy(n1));
EXPECT_FALSE(n1->OwnedBy(n2));
}
TEST_F(NodeTest, ReplaceUsesNone) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
Node* node = Node::New(zone(), 42, &kOp0, 0, nullptr, false);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n0);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n1);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n2);
EXPECT_TRUE(node->uses().empty());
}
TEST_F(NodeTest, AppendInput) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* node = Node::New(zone(), 12345, &kOp0, 0, nullptr, true);
EXPECT_TRUE(node->inputs().empty());
node->AppendInput(zone(), n0);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n0));
node->AppendInput(zone(), n1);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1));
node->AppendInput(zone(), n0);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0));
node->AppendInput(zone(), n0);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0));
node->AppendInput(zone(), n1);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0, n1));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -58,8 +58,10 @@
'compiler/machine-operator-unittest.cc',
'compiler/move-optimizer-unittest.cc',
'compiler/node-matchers-unittest.cc',
'compiler/node-properties-unittest.cc',
'compiler/node-test-utils.cc',
'compiler/node-test-utils.h',
'compiler/node-unittest.cc',
'compiler/opcodes-unittest.cc',
'compiler/register-allocator-unittest.cc',
'compiler/select-lowering-unittest.cc',
......
......@@ -497,6 +497,7 @@
'../../src/compiler/node-marker.h',
'../../src/compiler/node-matchers.h',
'../../src/compiler/node-properties-inl.h',
'../../src/compiler/node-properties.cc',
'../../src/compiler/node-properties.h',
'../../src/compiler/node.cc',
'../../src/compiler/node.h',
......
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