OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/value-numbering-reducer.h" | 5 #include "src/compiler/value-numbering-reducer.h" |
6 | 6 |
| 7 #include <cstring> |
| 8 |
| 9 #include "src/base/functional.h" |
7 #include "src/compiler/node.h" | 10 #include "src/compiler/node.h" |
8 | 11 |
9 namespace v8 { | 12 namespace v8 { |
10 namespace internal { | 13 namespace internal { |
11 namespace compiler { | 14 namespace compiler { |
12 | 15 |
13 namespace { | 16 namespace { |
14 | 17 |
15 size_t HashCode(Node* node) { return node->op()->HashCode(); } | 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()); |
| 22 } |
| 23 return h; |
| 24 } |
16 | 25 |
17 | 26 |
18 bool Equals(Node* a, Node* b) { | 27 bool Equals(Node* a, Node* b) { |
19 DCHECK_NOT_NULL(a); | 28 DCHECK_NOT_NULL(a); |
20 DCHECK_NOT_NULL(b); | 29 DCHECK_NOT_NULL(b); |
21 DCHECK_NOT_NULL(a->op()); | 30 DCHECK_NOT_NULL(a->op()); |
22 DCHECK_NOT_NULL(b->op()); | 31 DCHECK_NOT_NULL(b->op()); |
23 if (!a->op()->Equals(b->op())) return false; | 32 if (!a->op()->Equals(b->op())) return false; |
24 if (a->InputCount() != b->InputCount()) return false; | 33 if (a->InputCount() != b->InputCount()) return false; |
25 for (int j = 0; j < a->InputCount(); ++j) { | 34 for (int j = 0; j < a->InputCount(); ++j) { |
26 DCHECK_NOT_NULL(a->InputAt(j)); | 35 DCHECK_NOT_NULL(a->InputAt(j)); |
27 DCHECK_NOT_NULL(b->InputAt(j)); | 36 DCHECK_NOT_NULL(b->InputAt(j)); |
28 if (a->InputAt(j)->id() != b->InputAt(j)->id()) return false; | 37 if (a->InputAt(j)->id() != b->InputAt(j)->id()) return false; |
29 } | 38 } |
30 return true; | 39 return true; |
31 } | 40 } |
32 | 41 |
33 } // namespace | 42 } // namespace |
34 | 43 |
35 | 44 |
36 class ValueNumberingReducer::Entry FINAL : public ZoneObject { | 45 ValueNumberingReducer::ValueNumberingReducer(Zone* zone) |
37 public: | 46 : entries_(nullptr), capacity_(0), size_(0), zone_(zone) {} |
38 Entry(Node* node, Entry* next) : node_(node), next_(next) {} | |
39 | |
40 Node* node() const { return node_; } | |
41 Entry* next() const { return next_; } | |
42 | |
43 private: | |
44 Node* node_; | |
45 Entry* next_; | |
46 }; | |
47 | |
48 | |
49 ValueNumberingReducer::ValueNumberingReducer(Zone* zone) : zone_(zone) { | |
50 for (size_t i = 0; i < arraysize(buckets_); ++i) { | |
51 buckets_[i] = NULL; | |
52 } | |
53 } | |
54 | 47 |
55 | 48 |
56 ValueNumberingReducer::~ValueNumberingReducer() {} | 49 ValueNumberingReducer::~ValueNumberingReducer() {} |
57 | 50 |
58 | 51 |
59 Reduction ValueNumberingReducer::Reduce(Node* node) { | 52 Reduction ValueNumberingReducer::Reduce(Node* node) { |
60 Entry** head = &buckets_[HashCode(node) % arraysize(buckets_)]; | 53 if (!node->op()->HasProperty(Operator::kEliminatable)) return NoChange(); |
61 for (Entry* entry = *head; entry; entry = entry->next()) { | 54 |
62 if (entry->node()->IsDead()) continue; | 55 const size_t hash = HashCode(node); |
63 if (entry->node() == node) return NoChange(); | 56 if (!entries_) { |
64 if (Equals(node, entry->node())) { | 57 DCHECK(size_ == 0); |
65 return Replace(entry->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; |
| 64 size_ = 1; |
| 65 return NoChange(); |
| 66 } |
| 67 |
| 68 DCHECK(size_ < capacity_); |
| 69 DCHECK(size_ * kCapacityToSizeRatio < capacity_); |
| 70 |
| 71 const size_t mask = capacity_ - 1; |
| 72 size_t dead = capacity_; |
| 73 |
| 74 for (size_t i = hash & mask;; i = (i + 1) & mask) { |
| 75 Node* entry = entries_[i]; |
| 76 if (!entry) { |
| 77 if (dead != capacity_) { |
| 78 // Reuse dead entry that we discovered on the way. |
| 79 entries_[dead] = node; |
| 80 } else { |
| 81 // Have to insert a new entry. |
| 82 entries_[i] = node; |
| 83 size_++; |
| 84 |
| 85 // Resize to keep load factor below 1/kCapacityToSizeRatio. |
| 86 if (size_ * kCapacityToSizeRatio >= capacity_) Grow(); |
| 87 } |
| 88 DCHECK(size_ * kCapacityToSizeRatio < capacity_); |
| 89 return NoChange(); |
| 90 } |
| 91 if (entry == node) { |
| 92 return NoChange(); |
| 93 } |
| 94 |
| 95 // Skip dead entries, but remember their indices so we can reuse them. |
| 96 if (entry->IsDead()) { |
| 97 dead = i; |
| 98 continue; |
| 99 } |
| 100 if (Equals(entry, node)) { |
| 101 return Replace(entry); |
66 } | 102 } |
67 } | 103 } |
68 *head = new (zone()) Entry(node, *head); | 104 } |
69 return NoChange(); | 105 |
| 106 |
| 107 void ValueNumberingReducer::Grow() { |
| 108 // Allocate a new block of entries kCapacityToSizeRatio times the previous |
| 109 // capacity. |
| 110 Node** const old_entries = entries_; |
| 111 size_t const old_capacity = capacity_; |
| 112 capacity_ *= kCapacityToSizeRatio; |
| 113 entries_ = zone()->NewArray<Node*>(capacity_); |
| 114 memset(entries_, 0, sizeof(*entries_) * capacity_); |
| 115 size_ = 0; |
| 116 size_t const mask = capacity_ - 1; |
| 117 |
| 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 entry = old_entries[i]; |
| 121 if (!entry || entry->IsDead()) continue; |
| 122 for (size_t j = HashCode(entry) & mask;; j = (j + 1) & mask) { |
| 123 if (!entries_[j]) { |
| 124 entries_[j] = entry; |
| 125 size_++; |
| 126 break; |
| 127 } |
| 128 } |
| 129 } |
70 } | 130 } |
71 | 131 |
72 } // namespace compiler | 132 } // namespace compiler |
73 } // namespace internal | 133 } // namespace internal |
74 } // namespace v8 | 134 } // namespace v8 |
OLD | NEW |