1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/compiler/value-numbering-reducer.h"
9 #include "src/base/functional.h"
10 #include "src/compiler/node.h"
18 size_t HashCode(Node* node) {
19 size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount());
20 for (int j = 0; j < node->InputCount(); ++j) {
21 h = base::hash_combine(h, node->InputAt(j)->id());
27 bool Equals(Node* a, Node* b) {
30 DCHECK_NOT_NULL(a->op());
31 DCHECK_NOT_NULL(b->op());
32 if (!a->op()->Equals(b->op())) return false;
33 if (a->InputCount() != b->InputCount()) return false;
34 for (int j = 0; j < a->InputCount(); ++j) {
35 DCHECK_NOT_NULL(a->InputAt(j));
36 DCHECK_NOT_NULL(b->InputAt(j));
37 if (a->InputAt(j)->id() != b->InputAt(j)->id()) return false;
45 ValueNumberingReducer::ValueNumberingReducer(Zone* zone)
46 : entries_(nullptr), capacity_(0), size_(0), zone_(zone) {}
49 ValueNumberingReducer::~ValueNumberingReducer() {}
52 Reduction ValueNumberingReducer::Reduce(Node* node) {
53 if (!node->op()->HasProperty(Operator::kEliminatable)) return NoChange();
55 const size_t hash = HashCode(node);
58 DCHECK(capacity_ == 0);
59 // Allocate the initial entries and insert the first entry.
60 capacity_ = kInitialCapacity;
61 entries_ = zone()->NewArray<Node*>(kInitialCapacity);
62 memset(entries_, 0, sizeof(*entries_) * kInitialCapacity);
63 entries_[hash & (kInitialCapacity - 1)] = node;
68 DCHECK(size_ < capacity_);
69 DCHECK(size_ * kCapacityToSizeRatio < capacity_);
71 const size_t mask = capacity_ - 1;
72 size_t dead = capacity_;
74 for (size_t i = hash & mask;; i = (i + 1) & mask) {
75 Node* entry = entries_[i];
77 if (dead != capacity_) {
78 // Reuse dead entry that we discovered on the way.
79 entries_[dead] = node;
81 // Have to insert a new entry.
85 // Resize to keep load factor below 1/kCapacityToSizeRatio.
86 if (size_ * kCapacityToSizeRatio >= capacity_) Grow();
88 DCHECK(size_ * kCapacityToSizeRatio < capacity_);
95 // Skip dead entries, but remember their indices so we can reuse them.
96 if (entry->IsDead()) {
100 if (Equals(entry, node)) {
101 return Replace(entry);
107 void ValueNumberingReducer::Grow() {
108 // Allocate a new block of entries kCapacityToSizeRatio times the previous
110 Node** const old_entries = entries_;
111 size_t const old_capacity = capacity_;
112 capacity_ *= kCapacityToSizeRatio;
113 entries_ = zone()->NewArray<Node*>(static_cast<int>(capacity_));
114 memset(entries_, 0, sizeof(*entries_) * capacity_);
116 size_t const mask = capacity_ - 1;
118 // Insert the old entries into the new block (skipping dead nodes).
119 for (size_t i = 0; i < old_capacity; ++i) {
120 Node* const old_entry = old_entries[i];
121 if (!old_entry || old_entry->IsDead()) continue;
122 for (size_t j = HashCode(old_entry) & mask;; j = (j + 1) & mask) {
123 Node* const entry = entries_[j];
124 if (entry == old_entry) {
125 // Skip duplicate of the old entry.
129 entries_[j] = old_entry;
137 } // namespace compiler
138 } // namespace internal