"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",
#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 {
// 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.
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:
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);
}
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);
}
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
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:
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);
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);
}
+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) \
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 {
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()));
}
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.
// 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();
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);
}
-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;
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.
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:
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);
}
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);
}
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.
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;
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);
}
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:
#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 {
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--;
}
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:
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);
}
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);
}
#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 {
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--;
}
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:
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);
}
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);
}
--- /dev/null
+// 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
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);
#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);
}
-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);
}
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;
}
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
#ifndef V8_COMPILER_NODE_H_
#define V8_COMPILER_NODE_H_
-#include <deque>
-#include <vector>
-
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
#include "src/types-inl.h"
-#include "src/zone.h"
-#include "src/zone-allocator.h"
#include "src/zone-containers.h"
namespace v8 {
// by the Node's id.
class Node FINAL {
public:
- bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; }
- void Kill();
+ static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
+ Node** inputs, bool has_extensible_inputs);
- void CollectProjections(ZoneVector<Node*>* projections);
- Node* FindProjection(size_t projection_index);
+ bool IsDead() const { return InputCount() > 0 && !InputAt(0); }
+ void Kill();
const Operator* op() const { return op_; }
void set_op(const Operator* op) { op_ = op; }
int InputCount() const { return input_count(); }
Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; }
- inline void ReplaceInput(int index, Node* new_input);
- inline void AppendInput(Zone* zone, Node* new_input);
- inline void InsertInput(Zone* zone, int index, Node* new_input);
- inline void RemoveInput(int index);
+ inline void ReplaceInput(int index, Node* new_to);
+ void AppendInput(Zone* zone, Node* new_to);
+ void InsertInput(Zone* zone, int index, Node* new_to);
+ void RemoveInput(int index);
+ void RemoveAllInputs();
+ void TrimInputCount(int new_input_count);
int UseCount() const;
Node* UseAt(int index) const;
- inline void ReplaceUses(Node* replace_to);
- template <class UnaryPredicate>
- inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to);
- inline void RemoveAllInputs();
-
- inline void TrimInputCount(int input_count);
+ void ReplaceUses(Node* replace_to);
- class InputEdges {
+ class InputEdges FINAL {
public:
+ typedef Edge value_type;
+
class iterator;
- iterator begin() const;
- iterator end() const;
+ inline iterator begin() const;
+ inline iterator end() const;
+
bool empty() const;
explicit InputEdges(Node* node) : node_(node) {}
Node* node_;
};
- class Inputs {
+ InputEdges input_edges() { return InputEdges(this); }
+
+ class Inputs FINAL {
public:
- class iterator;
- iterator begin() const;
- iterator end() const;
+ typedef Node* value_type;
+
+ class const_iterator;
+ inline const_iterator begin() const;
+ inline const_iterator end() const;
+
bool empty() const;
explicit Inputs(Node* node) : node_(node) {}
};
Inputs inputs() { return Inputs(this); }
- InputEdges input_edges() { return InputEdges(this); }
- class UseEdges {
+ class UseEdges FINAL {
public:
+ typedef Edge value_type;
+
class iterator;
- iterator begin() const;
- iterator end() const;
+ inline iterator begin() const;
+ inline iterator end() const;
+
bool empty() const;
explicit UseEdges(Node* node) : node_(node) {}
Node* node_;
};
- class Uses {
+ UseEdges use_edges() { return UseEdges(this); }
+
+ class Uses FINAL {
public:
- class iterator;
- iterator begin() const;
- iterator end() const;
+ typedef Node* value_type;
+
+ class const_iterator;
+ inline const_iterator begin() const;
+ inline const_iterator end() const;
+
bool empty() const;
explicit Uses(Node* node) : node_(node) {}
};
Uses uses() { return Uses(this); }
- UseEdges use_edges() { return UseEdges(this); }
-
- bool OwnedBy(Node* owner) const;
- static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
- Node** inputs, bool has_extensible_inputs);
-
- protected:
- friend class Graph;
- friend class Edge;
+ // Returns true if {owner} is the user of {this} node.
+ bool OwnedBy(Node* owner) const {
+ return first_use_ && first_use_->from == owner && !first_use_->next;
+ }
- class Use : public ZoneObject {
- public:
+ private:
+ struct Use FINAL : public ZoneObject {
Node* from;
Use* next;
Use* prev;
int input_index;
};
- class Input {
+ class Input FINAL {
public:
Node* to;
Use* use;
void Update(Node* new_to);
};
- void EnsureAppendableInputs(Zone* zone);
+ inline Node(NodeId id, const Operator* op, int input_count,
+ int reserve_input_count);
+
+ inline void EnsureAppendableInputs(Zone* zone);
Input* GetInputRecordPtr(int index) const {
if (has_appendable_inputs()) {
}
}
- inline void AppendUse(Use* use);
- inline void RemoveUse(Use* use);
+ inline void AppendUse(Use* const use);
+ inline void RemoveUse(Use* const use);
void* operator new(size_t, void* location) { return location; }
- private:
- inline Node(NodeId id, const Operator* op, int input_count,
- int reserve_input_count);
-
typedef ZoneDeque<Input> InputDeque;
- friend class NodeMarkerBase;
- friend class NodeProperties;
-
// Only NodeProperties should manipulate the bounds.
Bounds bounds() { return bounds_; }
void set_bounds(Bounds b) { bounds_ = b; }
const Operator* op_;
Bounds bounds_;
Mark mark_;
- NodeId id_;
+ NodeId const id_;
unsigned bit_field_;
union {
// When a node is initially allocated, it uses a static buffer to hold its
Use* first_use_;
Use* last_use_;
+ friend class Edge;
+ friend class NodeMarkerBase;
+ friend class NodeProperties;
+
DISALLOW_COPY_AND_ASSIGN(Node);
};
+std::ostream& operator<<(std::ostream& os, const Node& n);
+
+
+// Typedefs to shorten commonly used Node containers.
+typedef ZoneDeque<Node*> NodeDeque;
+typedef ZoneVector<Node*> NodeVector;
+typedef ZoneVector<NodeVector> NodeVectorVector;
+
+
+// Helper to extract parameters from Operator1<*> nodes.
+template <typename T>
+static inline const T& OpParameter(const Node* node) {
+ return OpParameter<T>(node->op());
+}
+
+
// An encapsulation for information associated with a single use of node as a
// input from another node, allowing access to both the defining node and
// the node having the input.
-class Edge {
+class Edge FINAL {
public:
Node* from() const { return input_->use->from; }
Node* to() const { return input_->to; }
int index() const {
- int index = input_->use->input_index;
- DCHECK(index < input_->use->from->input_count());
+ int const index = input_->use->input_index;
+ DCHECK_LT(index, input_->use->from->input_count());
return index;
}
void UpdateTo(Node* new_to) { input_->Update(new_to); }
private:
- friend class Node::Uses::iterator;
- friend class Node::Inputs::iterator;
friend class Node::UseEdges::iterator;
friend class Node::InputEdges::iterator;
- explicit Edge(Node::Input* input) : input_(input) {}
+ explicit Edge(Node::Input* input) : input_(input) { DCHECK_NOT_NULL(input); }
- Node::Input* input_;
+ Node::Input* const input_;
};
-// A forward iterator to visit the edges for the input dependencies of a node..
-class Node::InputEdges::iterator {
+// A forward iterator to visit the edges for the input dependencies of a node.
+class Node::InputEdges::iterator FINAL {
public:
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
typedef Edge value_type;
typedef Edge* pointer;
typedef Edge& reference;
- iterator(const Node::InputEdges::iterator& other) // NOLINT
- : input_(other.input_) {}
- iterator() : input_(NULL) {}
+
+ iterator() : input_(nullptr) {}
+ iterator(const iterator& other) : input_(other.input_) {}
Edge operator*() const { return Edge(input_); }
- bool operator==(const iterator& other) const { return Equals(other); }
- bool operator!=(const iterator& other) const { return !Equals(other); }
+ bool operator==(const iterator& other) const {
+ return input_ == other.input_;
+ }
+ bool operator!=(const iterator& other) const { return !(*this == other); }
iterator& operator++() {
- DCHECK(input_ != NULL);
- Edge edge(input_);
- Node* from = edge.from();
- SetInput(from, input_->use->input_index + 1);
+ SetInput(Edge(input_).from(), input_->use->input_index + 1);
return *this;
}
- iterator operator++(int) {
- iterator result(*this);
- ++(*this);
- return result;
- }
+ iterator operator++(int);
private:
friend class Node;
- explicit iterator(Node* from, int index = 0) : input_(NULL) {
+ explicit iterator(Node* from, int index = 0) : input_(nullptr) {
SetInput(from, index);
}
- bool Equals(const iterator& other) const { return other.input_ == input_; }
void SetInput(Node* from, int index) {
DCHECK(index >= 0 && index <= from->InputCount());
if (index < from->InputCount()) {
input_ = from->GetInputRecordPtr(index);
} else {
- input_ = NULL;
+ input_ = nullptr;
}
}
};
+Node::InputEdges::iterator Node::InputEdges::begin() const {
+ return Node::InputEdges::iterator(this->node_, 0);
+}
+
+
+Node::InputEdges::iterator Node::InputEdges::end() const {
+ return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
+}
+
+
// A forward iterator to visit the inputs of a node.
-class Node::Inputs::iterator {
+class Node::Inputs::const_iterator FINAL {
public:
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
typedef Node** pointer;
typedef Node*& reference;
- iterator(const Node::Inputs::iterator& other) // NOLINT
- : iter_(other.iter_) {}
+ const_iterator(const const_iterator& other) : iter_(other.iter_) {}
Node* operator*() const { return (*iter_).to(); }
- bool operator==(const iterator& other) const { return Equals(other); }
- bool operator!=(const iterator& other) const { return !Equals(other); }
- iterator& operator++() {
+ bool operator==(const const_iterator& other) const {
+ return iter_ == other.iter_;
+ }
+ bool operator!=(const const_iterator& other) const {
+ return !(*this == other);
+ }
+ const_iterator& operator++() {
++iter_;
return *this;
}
- iterator operator++(int) {
- iterator result(*this);
- ++(*this);
- return result;
- }
-
+ const_iterator operator++(int);
private:
friend class Node::Inputs;
- explicit iterator(Node* node, int index) : iter_(node, index) {}
-
- bool Equals(const iterator& other) const { return other.iter_ == iter_; }
+ const_iterator(Node* node, int index) : iter_(node, index) {}
Node::InputEdges::iterator iter_;
};
+
+Node::Inputs::const_iterator Node::Inputs::begin() const {
+ return const_iterator(this->node_, 0);
+}
+
+
+Node::Inputs::const_iterator Node::Inputs::end() const {
+ return const_iterator(this->node_, this->node_->InputCount());
+}
+
+
// A forward iterator to visit the uses edges of a node. The edges are returned
// in
// the order in which they were added as inputs.
-class Node::UseEdges::iterator {
+class Node::UseEdges::iterator FINAL {
public:
- iterator(const Node::UseEdges::iterator& other) // NOLINT
- : current_(other.current_),
- next_(other.next_) {}
+ iterator(const iterator& other)
+ : current_(other.current_), next_(other.next_) {}
- Edge operator*() const { return Edge(CurrentInput()); }
+ Edge operator*() const {
+ return Edge(current_->from->GetInputRecordPtr(current_->input_index));
+ }
- bool operator==(const iterator& other) { return Equals(other); }
- bool operator!=(const iterator& other) { return !Equals(other); }
+ bool operator==(const iterator& other) const {
+ return current_ == other.current_;
+ }
+ bool operator!=(const iterator& other) const { return !(*this == other); }
iterator& operator++() {
- DCHECK(current_ != NULL);
+ DCHECK_NOT_NULL(current_);
current_ = next_;
- next_ = (current_ == NULL) ? NULL : current_->next;
+ next_ = current_ ? current_->next : nullptr;
return *this;
}
- iterator operator++(int) {
- iterator result(*this);
- ++(*this);
- return result;
- }
+ iterator operator++(int);
private:
friend class Node::UseEdges;
- iterator() : current_(NULL), next_(NULL) {}
+ iterator() : current_(nullptr), next_(nullptr) {}
explicit iterator(Node* node)
: current_(node->first_use_),
- next_(current_ == NULL ? NULL : current_->next) {}
-
- bool Equals(const iterator& other) const {
- return other.current_ == current_;
- }
-
- Input* CurrentInput() const {
- return current_->from->GetInputRecordPtr(current_->input_index);
- }
+ next_(current_ ? current_->next : nullptr) {}
Node::Use* current_;
Node::Use* next_;
};
-// A forward iterator to visit the uses of a node. The uses are returned in
-// the order in which they were added as inputs.
-class Node::Uses::iterator {
- public:
- iterator(const Node::Uses::iterator& other) // NOLINT
- : current_(other.current_) {}
-
- Node* operator*() { return current_->from; }
-
- bool operator==(const iterator& other) { return other.current_ == current_; }
- bool operator!=(const iterator& other) { return other.current_ != current_; }
- iterator& operator++() {
- DCHECK(current_ != NULL);
- current_ = current_->next;
- return *this;
- }
-
- private:
- friend class Node::Uses;
-
- iterator() : current_(NULL) {}
- explicit iterator(Node* node) : current_(node->first_use_) {}
-
- Input* CurrentInput() const {
- return current_->from->GetInputRecordPtr(current_->input_index);
- }
-
- Node::Use* current_;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const Node& n);
-
-typedef ZoneDeque<Node*> NodeDeque;
-
-typedef ZoneVector<Node*> NodeVector;
-typedef NodeVector::iterator NodeVectorIter;
-typedef NodeVector::const_iterator NodeVectorConstIter;
-typedef NodeVector::reverse_iterator NodeVectorRIter;
-
-typedef ZoneVector<NodeVector> NodeVectorVector;
-typedef NodeVectorVector::iterator NodeVectorVectorIter;
-typedef NodeVectorVector::reverse_iterator NodeVectorVectorRIter;
-
-typedef Node::Uses::iterator UseIter;
-typedef Node::Inputs::iterator InputIter;
-
-// Helper to extract parameters from Operator1<*> nodes.
-template <typename T>
-static inline const T& OpParameter(const Node* node) {
- return OpParameter<T>(node->op());
-}
-
-inline Node::InputEdges::iterator Node::InputEdges::begin() const {
- return Node::InputEdges::iterator(this->node_, 0);
-}
-
-inline Node::InputEdges::iterator Node::InputEdges::end() const {
- return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
-}
-
-inline Node::Inputs::iterator Node::Inputs::begin() const {
- return Node::Inputs::iterator(this->node_, 0);
-}
-
-inline Node::Inputs::iterator Node::Inputs::end() const {
- return Node::Inputs::iterator(this->node_, this->node_->InputCount());
-}
-
-inline Node::UseEdges::iterator Node::UseEdges::begin() const {
+Node::UseEdges::iterator Node::UseEdges::begin() const {
return Node::UseEdges::iterator(this->node_);
}
-inline Node::UseEdges::iterator Node::UseEdges::end() const {
- return Node::UseEdges::iterator();
-}
-inline Node::Uses::iterator Node::Uses::begin() const {
- return Node::Uses::iterator(this->node_);
+Node::UseEdges::iterator Node::UseEdges::end() const {
+ return Node::UseEdges::iterator();
}
-inline Node::Uses::iterator Node::Uses::end() const {
- return Node::Uses::iterator();
-}
-inline bool Node::InputEdges::empty() const { return begin() == end(); }
-inline bool Node::Uses::empty() const { return begin() == end(); }
-inline bool Node::UseEdges::empty() const { return begin() == end(); }
-inline bool Node::Inputs::empty() const { return begin() == end(); }
+// A forward iterator to visit the uses of a node. The uses are returned in
+// the order in which they were added as inputs.
+class Node::Uses::const_iterator FINAL {
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef int difference_type;
+ typedef Node* value_type;
+ typedef Node** pointer;
+ typedef Node*& reference;
-inline void Node::ReplaceUses(Node* replace_to) {
- for (Use* use = first_use_; use != NULL; use = use->next) {
- use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
- }
- if (replace_to->last_use_ == NULL) {
- DCHECK_EQ(NULL, replace_to->first_use_);
- replace_to->first_use_ = first_use_;
- replace_to->last_use_ = last_use_;
- } else if (first_use_ != NULL) {
- DCHECK_NE(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_ = NULL;
- last_use_ = NULL;
-}
+ const_iterator(const const_iterator& other) : current_(other.current_) {}
-template <class UnaryPredicate>
-inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) {
- for (Use* use = first_use_; use != NULL;) {
- Use* next = use->next;
- if (pred(use->from)) {
- RemoveUse(use);
- replace_to->AppendUse(use);
- use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
- }
- use = next;
+ Node* operator*() const { return current_->from; }
+ bool operator==(const const_iterator& other) const {
+ return other.current_ == current_;
}
-}
-
-inline void Node::RemoveAllInputs() {
- for (Edge edge : input_edges()) {
- edge.UpdateTo(NULL);
+ bool operator!=(const const_iterator& other) const {
+ return other.current_ != current_;
}
-}
-
-inline void Node::TrimInputCount(int new_input_count) {
- if (new_input_count == input_count()) return; // Nothing to do.
-
- DCHECK(new_input_count < input_count());
-
- // Update inline inputs.
- for (int i = new_input_count; i < input_count(); i++) {
- Node::Input* input = GetInputRecordPtr(i);
- input->Update(NULL);
+ const_iterator& operator++() {
+ DCHECK_NOT_NULL(current_);
+ current_ = current_->next;
+ return *this;
}
- set_input_count(new_input_count);
-}
+ const_iterator operator++(int);
-inline void Node::ReplaceInput(int index, Node* new_to) {
- Input* input = GetInputRecordPtr(index);
- input->Update(new_to);
-}
+ private:
+ friend class Node::Uses;
-inline 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 != NULL) {
- old_to->RemoveUse(use);
- }
- to = new_to;
- // And put it into the new node's use list.
- if (new_to != NULL) {
- new_to->AppendUse(use);
- } else {
- use->next = NULL;
- use->prev = NULL;
- }
-}
+ const_iterator() : current_(nullptr) {}
+ explicit const_iterator(Node* node) : current_(node->first_use_) {}
-inline 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);
- }
-}
+ Node::Use* current_;
+};
-inline void Node::AppendInput(Zone* zone, Node* to_append) {
- Use* new_use = new (zone) Use;
- Input new_input;
- new_input.to = to_append;
- 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);
- }
- new_use->input_index = input_count();
- new_use->from = this;
- to_append->AppendUse(new_use);
- set_input_count(input_count() + 1);
-}
-inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) {
- DCHECK(index >= 0 && index < InputCount());
- // TODO(turbofan): Optimize this implementation!
- AppendInput(zone, InputAt(InputCount() - 1));
- for (int i = InputCount() - 1; i > index; --i) {
- ReplaceInput(i, InputAt(i - 1));
- }
- ReplaceInput(index, to_insert);
+Node::Uses::const_iterator Node::Uses::begin() const {
+ return const_iterator(this->node_);
}
-inline void Node::RemoveInput(int index) {
- DCHECK(index >= 0 && index < InputCount());
- // TODO(turbofan): Optimize this implementation!
- for (; index < InputCount() - 1; ++index) {
- ReplaceInput(index, InputAt(index + 1));
- }
- TrimInputCount(InputCount() - 1);
-}
-inline void Node::AppendUse(Use* use) {
- use->next = NULL;
- use->prev = last_use_;
- if (last_use_ == NULL) {
- first_use_ = use;
- } else {
- last_use_->next = use;
- }
- last_use_ = use;
-}
+Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
-inline void Node::RemoveUse(Use* use) {
- if (last_use_ == use) {
- last_use_ = use->prev;
- }
- if (use->prev != NULL) {
- use->prev->next = use->next;
- } else {
- first_use_ = use->next;
- }
- if (use->next != NULL) {
- use->next->prev = use->prev;
- }
-}
-inline bool Node::OwnedBy(Node* owner) const {
- return first_use_ != NULL && first_use_->from == owner &&
- first_use_->next == NULL;
+void Node::ReplaceInput(int index, Node* new_to) {
+ GetInputRecordPtr(index)->Update(new_to);
}
} // namespace compiler
#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;
// 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();
// 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);
}
}
// 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);
}
}
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);
}
}
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();
}
#include "src/compiler/verifier.h"
+#include <algorithm>
#include <deque>
#include <queue>
#include <sstream>
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();
}
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.
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.
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
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.
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:
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);
}
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);
}
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();
}
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);
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);
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;
++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;
// 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;
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;
}
-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;
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
--- /dev/null
+// 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
--- /dev/null
+// 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
'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',
'../../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',