node.cc 14.6 KB
Newer Older
1 2 3 4
// Copyright 2013 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.

5
#include "src/compiler/node.h"
6

7 8 9 10
namespace v8 {
namespace internal {
namespace compiler {

11 12 13
Node::OutOfLineInputs* Node::OutOfLineInputs::New(Zone* zone, int capacity) {
  size_t size =
      sizeof(OutOfLineInputs) + capacity * (sizeof(Node*) + sizeof(Use));
14 15
  intptr_t raw_buffer =
      reinterpret_cast<intptr_t>(zone->Allocate<Node::OutOfLineInputs>(size));
16 17 18 19 20 21 22
  Node::OutOfLineInputs* outline =
      reinterpret_cast<OutOfLineInputs*>(raw_buffer + capacity * sizeof(Use));
  outline->capacity_ = capacity;
  outline->count_ = 0;
  return outline;
}

23 24
void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr,
                                        ZoneNodePtr* old_input_ptr, int count) {
25
  DCHECK_GE(count, 0);
26 27 28
  // Extract the inputs from the old use and input pointers and copy them
  // to this out-of-line-storage.
  Use* new_use_ptr = reinterpret_cast<Use*>(this) - 1;
29
  ZoneNodePtr* new_input_ptr = inputs();
30
  CHECK_IMPLIES(count > 0, Use::InputIndexField::is_valid(count - 1));
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
  for (int current = 0; current < count; current++) {
    new_use_ptr->bit_field_ =
        Use::InputIndexField::encode(current) | Use::InlineField::encode(false);
    DCHECK_EQ(old_input_ptr, old_use_ptr->input_ptr());
    DCHECK_EQ(new_input_ptr, new_use_ptr->input_ptr());
    Node* old_to = *old_input_ptr;
    if (old_to) {
      *old_input_ptr = nullptr;
      old_to->RemoveUse(old_use_ptr);
      *new_input_ptr = old_to;
      old_to->AppendUse(new_use_ptr);
    } else {
      *new_input_ptr = nullptr;
    }
    old_input_ptr++;
    new_input_ptr++;
    old_use_ptr--;
    new_use_ptr--;
  }
  this->count_ = count;
}

53 54 55
// These structs are just type tags for Zone::Allocate<T>(size_t) calls.
struct NodeWithOutOfLineInputs {};
struct NodeWithInLineInputs {};
56

57 58 59 60 61
template <typename NodePtrT>
Node* Node::NewImpl(Zone* zone, NodeId id, const Operator* op, int input_count,
                    NodePtrT const* inputs, bool has_extensible_inputs) {
  // Node uses compressed pointers, so zone must support pointer compression.
  DCHECK_IMPLIES(kCompressGraphZone, zone->supports_compression());
62 63
  DCHECK_GE(input_count, 0);

64
  ZoneNodePtr* input_ptr;
65 66 67 68
  Use* use_ptr;
  Node* node;
  bool is_inline;

69 70 71
  // Verify that none of the inputs are {nullptr}.
  for (int i = 0; i < input_count; i++) {
    if (inputs[i] == nullptr) {
72 73
      FATAL("Node::New() Error: #%d:%s[%d] is nullptr", static_cast<int>(id),
            op->mnemonic(), i);
74 75 76
    }
  }

77 78 79 80 81 82
  if (input_count > kMaxInlineCapacity) {
    // Allocate out-of-line inputs.
    int capacity =
        has_extensible_inputs ? input_count + kMaxInlineCapacity : input_count;
    OutOfLineInputs* outline = OutOfLineInputs::New(zone, capacity);

83
    // Allocate node, with space for OutOfLineInputs pointer.
84
    void* node_buffer = zone->Allocate<NodeWithOutOfLineInputs>(
85
        sizeof(Node) + sizeof(ZoneOutOfLineInputsPtr));
86
    node = new (node_buffer) Node(id, op, kOutlineMarker, 0);
87
    node->set_outline_inputs(outline);
88 89 90 91

    outline->node_ = node;
    outline->count_ = input_count;

92
    input_ptr = outline->inputs();
93 94 95
    use_ptr = reinterpret_cast<Use*>(outline);
    is_inline = false;
  } else {
96 97 98
    // Allocate node with inline inputs. Capacity must be at least 1 so that
    // an OutOfLineInputs pointer can be stored when inputs are added later.
    int capacity = std::max(1, input_count);
99 100 101 102 103
    if (has_extensible_inputs) {
      const int max = kMaxInlineCapacity;
      capacity = std::min(input_count + 3, max);
    }

104
    size_t size = sizeof(Node) + capacity * (sizeof(ZoneNodePtr) + sizeof(Use));
105 106
    intptr_t raw_buffer =
        reinterpret_cast<intptr_t>(zone->Allocate<NodeWithInLineInputs>(size));
107 108
    void* node_buffer =
        reinterpret_cast<void*>(raw_buffer + capacity * sizeof(Use));
109

110
    node = new (node_buffer) Node(id, op, input_count, capacity);
111
    input_ptr = node->inline_inputs();
112 113 114 115 116
    use_ptr = reinterpret_cast<Use*>(node);
    is_inline = true;
  }

  // Initialize the input pointers and the uses.
117 118
  CHECK_IMPLIES(input_count > 0,
                Use::InputIndexField::is_valid(input_count - 1));
119 120
  for (int current = 0; current < input_count; ++current) {
    Node* to = *inputs++;
121 122 123 124
    input_ptr[current] = to;
    Use* use = use_ptr - 1 - current;
    use->bit_field_ = Use::InputIndexField::encode(current) |
                      Use::InlineField::encode(is_inline);
125 126
    to->AppendUse(use);
  }
127 128
  node->Verify();
  return node;
129 130
}

131 132 133 134
Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
                Node* const* inputs, bool has_extensible_inputs) {
  return NewImpl(zone, id, op, input_count, inputs, has_extensible_inputs);
}
135

136 137
Node* Node::Clone(Zone* zone, NodeId id, const Node* node) {
  int const input_count = node->InputCount();
138 139 140 141
  ZoneNodePtr const* const inputs = node->has_inline_inputs()
                                        ? node->inline_inputs()
                                        : node->outline_inputs()->inputs();
  Node* const clone = NewImpl(zone, id, node->op(), input_count, inputs, false);
142
  clone->set_type(node->type());
143 144 145 146
  return clone;
}


147 148
void Node::Kill() {
  DCHECK_NOT_NULL(op());
149
  NullAllInputs();
150 151 152 153
  DCHECK(uses().empty());
}


154 155 156
void Node::AppendInput(Zone* zone, Node* new_to) {
  DCHECK_NOT_NULL(zone);
  DCHECK_NOT_NULL(new_to);
157

158 159
  int const inline_count = InlineCountField::decode(bit_field_);
  int const inline_capacity = InlineCapacityField::decode(bit_field_);
160 161 162 163 164
  if (inline_count < inline_capacity) {
    // Append inline input.
    bit_field_ = InlineCountField::update(bit_field_, inline_count + 1);
    *GetInputPtr(inline_count) = new_to;
    Use* use = GetUsePtr(inline_count);
165
    STATIC_ASSERT(InlineCapacityField::kMax <= Use::InputIndexField::kMax);
166 167 168
    use->bit_field_ = Use::InputIndexField::encode(inline_count) |
                      Use::InlineField::encode(true);
    new_to->AppendUse(use);
169
  } else {
170
    // Append out-of-line input.
171
    int const input_count = InputCount();
172 173 174 175 176 177 178
    OutOfLineInputs* outline = nullptr;
    if (inline_count != kOutlineMarker) {
      // switch to out of line inputs.
      outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
      outline->node_ = this;
      outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
      bit_field_ = InlineCountField::update(bit_field_, kOutlineMarker);
179
      set_outline_inputs(outline);
180 181
    } else {
      // use current out of line inputs.
182
      outline = outline_inputs();
183 184 185 186 187
      if (input_count >= outline->capacity_) {
        // out of space in out-of-line inputs.
        outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
        outline->node_ = this;
        outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
188
        set_outline_inputs(outline);
189 190 191 192 193
      }
    }
    outline->count_++;
    *GetInputPtr(input_count) = new_to;
    Use* use = GetUsePtr(input_count);
194
    CHECK(Use::InputIndexField::is_valid(input_count));
195 196 197
    use->bit_field_ = Use::InputIndexField::encode(input_count) |
                      Use::InlineField::encode(false);
    new_to->AppendUse(use);
198
  }
199
  Verify();
200 201 202 203 204 205 206 207 208 209
}


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));
210
  }
211
  ReplaceInput(index, new_to);
212
  Verify();
213 214
}

215 216 217 218 219 220
void Node::InsertInputs(Zone* zone, int index, int count) {
  DCHECK_NOT_NULL(zone);
  DCHECK_LE(0, index);
  DCHECK_LT(0, count);
  DCHECK_LT(index, InputCount());
  for (int i = 0; i < count; i++) {
221
    AppendInput(zone, InputAt(std::max(InputCount() - count, 0)));
222
  }
223
  for (int i = InputCount() - count - 1; i >= std::max(index, count); --i) {
224 225 226 227 228 229 230
    ReplaceInput(i, InputAt(i - count));
  }
  for (int i = 0; i < count; i++) {
    ReplaceInput(index + i, nullptr);
  }
  Verify();
}
231

232
Node* Node::RemoveInput(int index) {
233 234
  DCHECK_LE(0, index);
  DCHECK_LT(index, InputCount());
235
  Node* result = InputAt(index);
236 237 238 239
  for (; index < InputCount() - 1; ++index) {
    ReplaceInput(index, InputAt(index + 1));
  }
  TrimInputCount(InputCount() - 1);
240
  Verify();
241
  return result;
242 243
}

244
void Node::ClearInputs(int start, int count) {
245
  ZoneNodePtr* input_ptr = GetInputPtr(start);
246 247 248 249 250 251 252 253 254 255
  Use* use_ptr = GetUsePtr(start);
  while (count-- > 0) {
    DCHECK_EQ(input_ptr, use_ptr->input_ptr());
    Node* input = *input_ptr;
    *input_ptr = nullptr;
    if (input) input->RemoveUse(use_ptr);
    input_ptr++;
    use_ptr--;
  }
  Verify();
256 257 258
}


259 260 261
void Node::NullAllInputs() { ClearInputs(0, InputCount()); }


262
void Node::TrimInputCount(int new_input_count) {
263 264 265 266 267 268
  int current_count = InputCount();
  DCHECK_LE(new_input_count, current_count);
  if (new_input_count == current_count) return;  // Nothing to do.
  ClearInputs(new_input_count, current_count - new_input_count);
  if (has_inline_inputs()) {
    bit_field_ = InlineCountField::update(bit_field_, new_input_count);
269
  } else {
270
    outline_inputs()->count_ = new_input_count;
271 272 273
  }
}

274 275 276 277 278 279 280 281 282 283 284 285 286
void Node::EnsureInputCount(Zone* zone, int new_input_count) {
  int current_count = InputCount();
  DCHECK_NE(current_count, 0);
  if (current_count > new_input_count) {
    TrimInputCount(new_input_count);
  } else if (current_count < new_input_count) {
    Node* dummy = InputAt(current_count - 1);
    do {
      AppendInput(zone, dummy);
      current_count++;
    } while (current_count < new_input_count);
  }
}
287

288 289 290 291 292 293 294 295 296
int Node::UseCount() const {
  int use_count = 0;
  for (const Use* use = first_use_; use; use = use->next) {
    ++use_count;
  }
  return use_count;
}


297 298 299 300 301 302 303
void Node::ReplaceUses(Node* that) {
  DCHECK(this->first_use_ == nullptr || this->first_use_->prev == nullptr);
  DCHECK(that->first_use_ == nullptr || that->first_use_->prev == nullptr);

  // Update the pointers to {this} to point to {that}.
  Use* last_use = nullptr;
  for (Use* use = this->first_use_; use; use = use->next) {
304
    *use->input_ptr() = that;
305 306 307 308 309 310 311
    last_use = use;
  }
  if (last_use) {
    // Concat the use list of {this} and {that}.
    last_use->next = that->first_use_;
    if (that->first_use_) that->first_use_->prev = last_use;
    that->first_use_ = this->first_use_;
312 313 314 315
  }
  first_use_ = nullptr;
}

316 317 318 319 320 321 322 323 324 325 326
bool Node::OwnedBy(Node const* owner) const {
  unsigned mask = 0;
  for (Use* use = first_use_; use; use = use->next) {
    if (use->from() == owner) {
      mask |= 1;
    } else {
      return false;
    }
  }
  return mask == 1;
}
327

328 329 330
bool Node::OwnedBy(Node const* owner1, Node const* owner2) const {
  unsigned mask = 0;
  for (Use* use = first_use_; use; use = use->next) {
331 332
    Node* from = use->from();
    if (from == owner1) {
333
      mask |= 1;
334
    } else if (from == owner2) {
335 336 337 338 339 340 341 342
      mask |= 2;
    } else {
      return false;
    }
  }
  return mask == 3;
}

343
void Node::Print(int depth) const {
344
  StdoutStream os;
345
  Print(os, depth);
346 347
}

348 349 350 351
namespace {
void PrintNode(const Node* node, std::ostream& os, int depth,
               int indentation = 0) {
  for (int i = 0; i < indentation; ++i) {
352
    os << "  ";
353
  }
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
  if (node) {
    os << *node;
  } else {
    os << "(NULL)";
  }
  os << std::endl;
  if (depth <= 0) return;
  for (Node* input : node->inputs()) {
    PrintNode(input, os, depth - 1, indentation + 1);
  }
}
}  // namespace

void Node::Print(std::ostream& os, int depth) const {
  PrintNode(this, os, depth);
369 370
}

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
std::ostream& operator<<(std::ostream& os, const Node& n) {
  os << n.id() << ": " << *n.op();
  if (n.InputCount() > 0) {
    os << "(";
    for (int i = 0; i < n.InputCount(); ++i) {
      if (i != 0) os << ", ";
      if (n.InputAt(i)) {
        os << n.InputAt(i)->id();
      } else {
        os << "null";
      }
    }
    os << ")";
  }
  return os;
}
387

388
Node::Node(NodeId id, const Operator* op, int inline_count, int inline_capacity)
389 390
    : op_(op),
      mark_(0),
391 392 393
      bit_field_(IdField::encode(id) | InlineCountField::encode(inline_count) |
                 InlineCapacityField::encode(inline_capacity)),
      first_use_(nullptr) {
394 395 396 397
  // Check that the id didn't overflow.
  STATIC_ASSERT(IdField::kMax < std::numeric_limits<NodeId>::max());
  CHECK(IdField::is_valid(id));

398 399
  // Inputs must either be out of line or within the inline capacity.
  DCHECK(inline_count == kOutlineMarker || inline_count <= inline_capacity);
400
  DCHECK_LE(inline_capacity, kMaxInlineCapacity);
401 402 403
}


404
void Node::AppendUse(Use* use) {
405
  DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
406
  DCHECK_EQ(this, *use->input_ptr());
407 408 409 410
  use->next = first_use_;
  use->prev = nullptr;
  if (first_use_) first_use_->prev = use;
  first_use_ = use;
411 412 413
}


414
void Node::RemoveUse(Use* use) {
415
  DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
416
  if (use->prev) {
417
    DCHECK_NE(first_use_, use);
418 419
    use->prev->next = use->next;
  } else {
420
    DCHECK_EQ(first_use_, use);
421 422 423 424
    first_use_ = use->next;
  }
  if (use->next) {
    use->next->prev = use->prev;
425 426 427 428
  }
}


429 430
#if DEBUG
void Node::Verify() {
431
  // Check basic validity of input data structures.
432 433 434 435 436 437 438
  fflush(stdout);
  int count = this->InputCount();
  // Avoid quadratic explosion for mega nodes; only verify if the input
  // count is less than 200 or is a round number of 100s.
  if (count > 200 && count % 100) return;

  for (int i = 0; i < count; i++) {
439 440 441
    DCHECK_EQ(i, this->GetUsePtr(i)->input_index());
    DCHECK_EQ(this->GetInputPtr(i), this->GetUsePtr(i)->input_ptr());
    DCHECK_EQ(count, this->InputCount());
442 443 444 445
  }
  {  // Direct input iteration.
    int index = 0;
    for (Node* input : this->inputs()) {
446
      DCHECK_EQ(this->InputAt(index), input);
447 448
      index++;
    }
449 450
    DCHECK_EQ(count, index);
    DCHECK_EQ(this->InputCount(), index);
451 452 453 454
  }
  {  // Input edge iteration.
    int index = 0;
    for (Edge edge : this->input_edges()) {
455 456 457
      DCHECK_EQ(edge.from(), this);
      DCHECK_EQ(index, edge.index());
      DCHECK_EQ(this->InputAt(index), edge.to());
458 459
      index++;
    }
460 461
    DCHECK_EQ(count, index);
    DCHECK_EQ(this->InputCount(), index);
462 463 464 465
  }
}
#endif

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
  iterator result(*this);
  ++(*this);
  return result;
}


Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
  const_iterator result(*this);
  ++(*this);
  return result;
}


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(); }

499 500 501
}  // namespace compiler
}  // namespace internal
}  // namespace v8