OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 14 matching lines...) Expand all Loading... |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
29 #include "hydrogen-gvn.h" | 29 #include "hydrogen-gvn.h" |
30 #include "v8.h" | 30 #include "v8.h" |
31 | 31 |
32 namespace v8 { | 32 namespace v8 { |
33 namespace internal { | 33 namespace internal { |
34 | 34 |
35 class HValueMap: public ZoneObject { | 35 class HInstructionMap V8_FINAL : public ZoneObject { |
36 public: | 36 public: |
37 explicit HValueMap(Zone* zone) | 37 HInstructionMap(Zone* zone, SideEffectsScope* side_effects_scope) |
38 : array_size_(0), | 38 : array_size_(0), |
39 lists_size_(0), | 39 lists_size_(0), |
40 count_(0), | 40 count_(0), |
41 present_flags_(0), | |
42 array_(NULL), | 41 array_(NULL), |
43 lists_(NULL), | 42 lists_(NULL), |
44 free_list_head_(kNil) { | 43 free_list_head_(kNil), |
| 44 side_effects_scope_(side_effects_scope) { |
45 ResizeLists(kInitialSize, zone); | 45 ResizeLists(kInitialSize, zone); |
46 Resize(kInitialSize, zone); | 46 Resize(kInitialSize, zone); |
47 } | 47 } |
48 | 48 |
49 void Kill(GVNFlagSet flags); | 49 void Kill(SideEffects side_effects); |
50 | 50 |
51 void Add(HValue* value, Zone* zone) { | 51 void Add(HInstruction* instr, Zone* zone) { |
52 present_flags_.Add(value->gvn_flags()); | 52 present_depends_on_.Add(side_effects_scope_->ComputeDependsOn(instr)); |
53 Insert(value, zone); | 53 Insert(instr, zone); |
54 } | 54 } |
55 | 55 |
56 HValue* Lookup(HValue* value) const; | 56 HInstruction* Lookup(HInstruction* instr) const; |
57 | 57 |
58 HValueMap* Copy(Zone* zone) const { | 58 HInstructionMap* Copy(Zone* zone) const { |
59 return new(zone) HValueMap(zone, this); | 59 return new(zone) HInstructionMap(zone, this); |
60 } | 60 } |
61 | 61 |
62 bool IsEmpty() const { return count_ == 0; } | 62 bool IsEmpty() const { return count_ == 0; } |
63 | 63 |
64 private: | 64 private: |
65 // A linked list of HValue* values. Stored in arrays. | 65 // A linked list of HInstruction* values. Stored in arrays. |
66 struct HValueMapListElement { | 66 struct HInstructionMapListElement { |
67 HValue* value; | 67 HInstruction* instr; |
68 int next; // Index in the array of the next list element. | 68 int next; // Index in the array of the next list element. |
69 }; | 69 }; |
70 static const int kNil = -1; // The end of a linked list | 70 static const int kNil = -1; // The end of a linked list |
71 | 71 |
72 // Must be a power of 2. | 72 // Must be a power of 2. |
73 static const int kInitialSize = 16; | 73 static const int kInitialSize = 16; |
74 | 74 |
75 HValueMap(Zone* zone, const HValueMap* other); | 75 HInstructionMap(Zone* zone, const HInstructionMap* other); |
76 | 76 |
77 void Resize(int new_size, Zone* zone); | 77 void Resize(int new_size, Zone* zone); |
78 void ResizeLists(int new_size, Zone* zone); | 78 void ResizeLists(int new_size, Zone* zone); |
79 void Insert(HValue* value, Zone* zone); | 79 void Insert(HInstruction* instr, Zone* zone); |
80 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); } | 80 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); } |
81 | 81 |
82 int array_size_; | 82 int array_size_; |
83 int lists_size_; | 83 int lists_size_; |
84 int count_; // The number of values stored in the HValueMap. | 84 int count_; // The number of values stored in the HInstructionMap. |
85 GVNFlagSet present_flags_; // All flags that are in any value in the | 85 SideEffects present_depends_on_; |
86 // HValueMap. | 86 HInstructionMapListElement* array_; |
87 HValueMapListElement* array_; // Primary store - contains the first value | 87 // Primary store - contains the first value |
88 // with a given hash. Colliding elements are stored in linked lists. | 88 // with a given hash. Colliding elements are stored in linked lists. |
89 HValueMapListElement* lists_; // The linked lists containing hash collisions. | 89 HInstructionMapListElement* lists_; |
| 90 // The linked lists containing hash collisions. |
90 int free_list_head_; // Unused elements in lists_ are on the free list. | 91 int free_list_head_; // Unused elements in lists_ are on the free list. |
| 92 SideEffectsScope* side_effects_scope_; |
91 }; | 93 }; |
92 | 94 |
93 | 95 |
94 class HSideEffectMap BASE_EMBEDDED { | 96 class HSideEffectMap V8_FINAL BASE_EMBEDDED { |
95 public: | 97 public: |
96 HSideEffectMap(); | 98 HSideEffectMap(); |
97 explicit HSideEffectMap(HSideEffectMap* other); | 99 explicit HSideEffectMap(HSideEffectMap* other); |
98 HSideEffectMap& operator= (const HSideEffectMap& other); | 100 HSideEffectMap& operator= (const HSideEffectMap& other); |
99 | 101 |
100 void Kill(GVNFlagSet flags); | 102 void Kill(SideEffects side_effects); |
101 | 103 |
102 void Store(GVNFlagSet flags, HInstruction* instr); | 104 void Store(SideEffects side_effects, HInstruction* instr); |
103 | 105 |
104 bool IsEmpty() const { return count_ == 0; } | 106 bool IsEmpty() const { return count_ == 0; } |
105 | 107 |
106 inline HInstruction* operator[](int i) const { | 108 inline HInstruction* operator[](int i) const { |
107 ASSERT(0 <= i); | 109 ASSERT(0 <= i); |
108 ASSERT(i < kNumberOfTrackedSideEffects); | 110 ASSERT(i < kNumberOfTrackedSideEffects); |
109 return data_[i]; | 111 return data_[i]; |
110 } | 112 } |
111 inline HInstruction* at(int i) const { return operator[](i); } | 113 inline HInstruction* at(int i) const { return operator[](i); } |
112 | 114 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 if (FLAG_trace_gvn) { \ | 147 if (FLAG_trace_gvn) { \ |
146 TraceGVN(msg, a1, a2, a3, a4); \ | 148 TraceGVN(msg, a1, a2, a3, a4); \ |
147 } | 149 } |
148 | 150 |
149 #define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \ | 151 #define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \ |
150 if (FLAG_trace_gvn) { \ | 152 if (FLAG_trace_gvn) { \ |
151 TraceGVN(msg, a1, a2, a3, a4, a5); \ | 153 TraceGVN(msg, a1, a2, a3, a4, a5); \ |
152 } | 154 } |
153 | 155 |
154 | 156 |
155 HValueMap::HValueMap(Zone* zone, const HValueMap* other) | 157 HInstructionMap::HInstructionMap(Zone* zone, const HInstructionMap* other) |
156 : array_size_(other->array_size_), | 158 : array_size_(other->array_size_), |
157 lists_size_(other->lists_size_), | 159 lists_size_(other->lists_size_), |
158 count_(other->count_), | 160 count_(other->count_), |
159 present_flags_(other->present_flags_), | 161 present_depends_on_(other->present_depends_on_), |
160 array_(zone->NewArray<HValueMapListElement>(other->array_size_)), | 162 array_(zone->NewArray<HInstructionMapListElement>(other->array_size_)), |
161 lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)), | 163 lists_(zone->NewArray<HInstructionMapListElement>(other->lists_size_)), |
162 free_list_head_(other->free_list_head_) { | 164 free_list_head_(other->free_list_head_), |
| 165 side_effects_scope_(other->side_effects_scope_) { |
163 OS::MemCopy( | 166 OS::MemCopy( |
164 array_, other->array_, array_size_ * sizeof(HValueMapListElement)); | 167 array_, other->array_, array_size_ * sizeof(HInstructionMapListElement)); |
165 OS::MemCopy( | 168 OS::MemCopy( |
166 lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); | 169 lists_, other->lists_, lists_size_ * sizeof(HInstructionMapListElement)); |
167 } | 170 } |
168 | 171 |
169 | 172 |
170 void HValueMap::Kill(GVNFlagSet flags) { | 173 void HInstructionMap::Kill(SideEffects changes) { |
171 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags); | 174 if (!present_depends_on_.ContainsAnyOf(changes)) return; |
172 if (!present_flags_.ContainsAnyOf(depends_flags)) return; | 175 present_depends_on_.RemoveAll(); |
173 present_flags_.RemoveAll(); | |
174 for (int i = 0; i < array_size_; ++i) { | 176 for (int i = 0; i < array_size_; ++i) { |
175 HValue* value = array_[i].value; | 177 HInstruction* instr = array_[i].instr; |
176 if (value != NULL) { | 178 if (instr != NULL) { |
177 // Clear list of collisions first, so we know if it becomes empty. | 179 // Clear list of collisions first, so we know if it becomes empty. |
178 int kept = kNil; // List of kept elements. | 180 int kept = kNil; // List of kept elements. |
179 int next; | 181 int next; |
180 for (int current = array_[i].next; current != kNil; current = next) { | 182 for (int current = array_[i].next; current != kNil; current = next) { |
181 next = lists_[current].next; | 183 next = lists_[current].next; |
182 HValue* value = lists_[current].value; | 184 HInstruction* instr = lists_[current].instr; |
183 if (value->gvn_flags().ContainsAnyOf(depends_flags)) { | 185 SideEffects depends_on = side_effects_scope_->ComputeDependsOn(instr); |
| 186 if (depends_on.ContainsAnyOf(changes)) { |
184 // Drop it. | 187 // Drop it. |
185 count_--; | 188 count_--; |
186 lists_[current].next = free_list_head_; | 189 lists_[current].next = free_list_head_; |
187 free_list_head_ = current; | 190 free_list_head_ = current; |
188 } else { | 191 } else { |
189 // Keep it. | 192 // Keep it. |
190 lists_[current].next = kept; | 193 lists_[current].next = kept; |
191 kept = current; | 194 kept = current; |
192 present_flags_.Add(value->gvn_flags()); | 195 present_depends_on_.Add(depends_on); |
193 } | 196 } |
194 } | 197 } |
195 array_[i].next = kept; | 198 array_[i].next = kept; |
196 | 199 |
197 // Now possibly drop directly indexed element. | 200 // Now possibly drop directly indexed element. |
198 value = array_[i].value; | 201 instr = array_[i].instr; |
199 if (value->gvn_flags().ContainsAnyOf(depends_flags)) { // Drop it. | 202 SideEffects depends_on = side_effects_scope_->ComputeDependsOn(instr); |
| 203 if (depends_on.ContainsAnyOf(changes)) { // Drop it. |
200 count_--; | 204 count_--; |
201 int head = array_[i].next; | 205 int head = array_[i].next; |
202 if (head == kNil) { | 206 if (head == kNil) { |
203 array_[i].value = NULL; | 207 array_[i].instr = NULL; |
204 } else { | 208 } else { |
205 array_[i].value = lists_[head].value; | 209 array_[i].instr = lists_[head].instr; |
206 array_[i].next = lists_[head].next; | 210 array_[i].next = lists_[head].next; |
207 lists_[head].next = free_list_head_; | 211 lists_[head].next = free_list_head_; |
208 free_list_head_ = head; | 212 free_list_head_ = head; |
209 } | 213 } |
210 } else { | 214 } else { |
211 present_flags_.Add(value->gvn_flags()); // Keep it. | 215 present_depends_on_.Add(depends_on); // Keep it. |
212 } | 216 } |
213 } | 217 } |
214 } | 218 } |
215 } | 219 } |
216 | 220 |
217 | 221 |
218 HValue* HValueMap::Lookup(HValue* value) const { | 222 HInstruction* HInstructionMap::Lookup(HInstruction* instr) const { |
219 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); | 223 uint32_t hash = static_cast<uint32_t>(instr->Hashcode()); |
220 uint32_t pos = Bound(hash); | 224 uint32_t pos = Bound(hash); |
221 if (array_[pos].value != NULL) { | 225 if (array_[pos].instr != NULL) { |
222 if (array_[pos].value->Equals(value)) return array_[pos].value; | 226 if (array_[pos].instr->Equals(instr)) return array_[pos].instr; |
223 int next = array_[pos].next; | 227 int next = array_[pos].next; |
224 while (next != kNil) { | 228 while (next != kNil) { |
225 if (lists_[next].value->Equals(value)) return lists_[next].value; | 229 if (lists_[next].instr->Equals(instr)) return lists_[next].instr; |
226 next = lists_[next].next; | 230 next = lists_[next].next; |
227 } | 231 } |
228 } | 232 } |
229 return NULL; | 233 return NULL; |
230 } | 234 } |
231 | 235 |
232 | 236 |
233 void HValueMap::Resize(int new_size, Zone* zone) { | 237 void HInstructionMap::Resize(int new_size, Zone* zone) { |
234 ASSERT(new_size > count_); | 238 ASSERT(new_size > count_); |
235 // Hashing the values into the new array has no more collisions than in the | 239 // Hashing the values into the new array has no more collisions than in the |
236 // old hash map, so we can use the existing lists_ array, if we are careful. | 240 // old hash map, so we can use the existing lists_ array, if we are careful. |
237 | 241 |
238 // Make sure we have at least one free element. | 242 // Make sure we have at least one free element. |
239 if (free_list_head_ == kNil) { | 243 if (free_list_head_ == kNil) { |
240 ResizeLists(lists_size_ << 1, zone); | 244 ResizeLists(lists_size_ << 1, zone); |
241 } | 245 } |
242 | 246 |
243 HValueMapListElement* new_array = | 247 HInstructionMapListElement* new_array = |
244 zone->NewArray<HValueMapListElement>(new_size); | 248 zone->NewArray<HInstructionMapListElement>(new_size); |
245 memset(new_array, 0, sizeof(HValueMapListElement) * new_size); | 249 memset(new_array, 0, sizeof(HInstructionMapListElement) * new_size); |
246 | 250 |
247 HValueMapListElement* old_array = array_; | 251 HInstructionMapListElement* old_array = array_; |
248 int old_size = array_size_; | 252 int old_size = array_size_; |
249 | 253 |
250 int old_count = count_; | 254 int old_count = count_; |
251 count_ = 0; | 255 count_ = 0; |
252 // Do not modify present_flags_. It is currently correct. | 256 // Do not modify present_depends_on_. It is currently correct. |
253 array_size_ = new_size; | 257 array_size_ = new_size; |
254 array_ = new_array; | 258 array_ = new_array; |
255 | 259 |
256 if (old_array != NULL) { | 260 if (old_array != NULL) { |
257 // Iterate over all the elements in lists, rehashing them. | 261 // Iterate over all the elements in lists, rehashing them. |
258 for (int i = 0; i < old_size; ++i) { | 262 for (int i = 0; i < old_size; ++i) { |
259 if (old_array[i].value != NULL) { | 263 if (old_array[i].instr != NULL) { |
260 int current = old_array[i].next; | 264 int current = old_array[i].next; |
261 while (current != kNil) { | 265 while (current != kNil) { |
262 Insert(lists_[current].value, zone); | 266 Insert(lists_[current].instr, zone); |
263 int next = lists_[current].next; | 267 int next = lists_[current].next; |
264 lists_[current].next = free_list_head_; | 268 lists_[current].next = free_list_head_; |
265 free_list_head_ = current; | 269 free_list_head_ = current; |
266 current = next; | 270 current = next; |
267 } | 271 } |
268 // Rehash the directly stored value. | 272 // Rehash the directly stored instruction. |
269 Insert(old_array[i].value, zone); | 273 Insert(old_array[i].instr, zone); |
270 } | 274 } |
271 } | 275 } |
272 } | 276 } |
273 USE(old_count); | 277 USE(old_count); |
274 ASSERT(count_ == old_count); | 278 ASSERT(count_ == old_count); |
275 } | 279 } |
276 | 280 |
277 | 281 |
278 void HValueMap::ResizeLists(int new_size, Zone* zone) { | 282 void HInstructionMap::ResizeLists(int new_size, Zone* zone) { |
279 ASSERT(new_size > lists_size_); | 283 ASSERT(new_size > lists_size_); |
280 | 284 |
281 HValueMapListElement* new_lists = | 285 HInstructionMapListElement* new_lists = |
282 zone->NewArray<HValueMapListElement>(new_size); | 286 zone->NewArray<HInstructionMapListElement>(new_size); |
283 memset(new_lists, 0, sizeof(HValueMapListElement) * new_size); | 287 memset(new_lists, 0, sizeof(HInstructionMapListElement) * new_size); |
284 | 288 |
285 HValueMapListElement* old_lists = lists_; | 289 HInstructionMapListElement* old_lists = lists_; |
286 int old_size = lists_size_; | 290 int old_size = lists_size_; |
287 | 291 |
288 lists_size_ = new_size; | 292 lists_size_ = new_size; |
289 lists_ = new_lists; | 293 lists_ = new_lists; |
290 | 294 |
291 if (old_lists != NULL) { | 295 if (old_lists != NULL) { |
292 OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement)); | 296 OS::MemCopy( |
| 297 lists_, old_lists, old_size * sizeof(HInstructionMapListElement)); |
293 } | 298 } |
294 for (int i = old_size; i < lists_size_; ++i) { | 299 for (int i = old_size; i < lists_size_; ++i) { |
295 lists_[i].next = free_list_head_; | 300 lists_[i].next = free_list_head_; |
296 free_list_head_ = i; | 301 free_list_head_ = i; |
297 } | 302 } |
298 } | 303 } |
299 | 304 |
300 | 305 |
301 void HValueMap::Insert(HValue* value, Zone* zone) { | 306 void HInstructionMap::Insert(HInstruction* instr, Zone* zone) { |
302 ASSERT(value != NULL); | 307 ASSERT(instr != NULL); |
303 // Resizing when half of the hashtable is filled up. | 308 // Resizing when half of the hashtable is filled up. |
304 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone); | 309 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone); |
305 ASSERT(count_ < array_size_); | 310 ASSERT(count_ < array_size_); |
306 count_++; | 311 count_++; |
307 uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode())); | 312 uint32_t pos = Bound(static_cast<uint32_t>(instr->Hashcode())); |
308 if (array_[pos].value == NULL) { | 313 if (array_[pos].instr == NULL) { |
309 array_[pos].value = value; | 314 array_[pos].instr = instr; |
310 array_[pos].next = kNil; | 315 array_[pos].next = kNil; |
311 } else { | 316 } else { |
312 if (free_list_head_ == kNil) { | 317 if (free_list_head_ == kNil) { |
313 ResizeLists(lists_size_ << 1, zone); | 318 ResizeLists(lists_size_ << 1, zone); |
314 } | 319 } |
315 int new_element_pos = free_list_head_; | 320 int new_element_pos = free_list_head_; |
316 ASSERT(new_element_pos != kNil); | 321 ASSERT(new_element_pos != kNil); |
317 free_list_head_ = lists_[free_list_head_].next; | 322 free_list_head_ = lists_[free_list_head_].next; |
318 lists_[new_element_pos].value = value; | 323 lists_[new_element_pos].instr = instr; |
319 lists_[new_element_pos].next = array_[pos].next; | 324 lists_[new_element_pos].next = array_[pos].next; |
320 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); | 325 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].instr != NULL); |
321 array_[pos].next = new_element_pos; | 326 array_[pos].next = new_element_pos; |
322 } | 327 } |
323 } | 328 } |
324 | 329 |
325 | 330 |
326 HSideEffectMap::HSideEffectMap() : count_(0) { | 331 HSideEffectMap::HSideEffectMap() : count_(0) { |
327 memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize); | 332 memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize); |
328 } | 333 } |
329 | 334 |
330 | 335 |
331 HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) { | 336 HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) { |
332 *this = *other; // Calls operator=. | 337 *this = *other; // Calls operator=. |
333 } | 338 } |
334 | 339 |
335 | 340 |
336 HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) { | 341 HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) { |
337 if (this != &other) { | 342 if (this != &other) { |
338 OS::MemCopy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize); | 343 OS::MemCopy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize); |
339 } | 344 } |
340 return *this; | 345 return *this; |
341 } | 346 } |
342 | 347 |
343 | 348 |
344 void HSideEffectMap::Kill(GVNFlagSet flags) { | 349 void HSideEffectMap::Kill(SideEffects side_effects) { |
345 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 350 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { |
346 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 351 if (side_effects.ContainsFlag(GVNFlagFromInt(i))) { |
347 if (flags.Contains(changes_flag)) { | |
348 if (data_[i] != NULL) count_--; | 352 if (data_[i] != NULL) count_--; |
349 data_[i] = NULL; | 353 data_[i] = NULL; |
350 } | 354 } |
351 } | 355 } |
352 } | 356 } |
353 | 357 |
354 | 358 |
355 void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) { | 359 void HSideEffectMap::Store(SideEffects side_effects, HInstruction* instr) { |
356 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 360 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { |
357 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 361 if (side_effects.ContainsFlag(GVNFlagFromInt(i))) { |
358 if (flags.Contains(changes_flag)) { | |
359 if (data_[i] == NULL) count_++; | 362 if (data_[i] == NULL) count_++; |
360 data_[i] = instr; | 363 data_[i] = instr; |
361 } | 364 } |
362 } | 365 } |
363 } | 366 } |
364 | 367 |
365 | 368 |
| 369 SideEffects SideEffectsScope::ComputeChanges(HInstruction* instr) { |
| 370 SideEffects result(instr->ChangesFlags()); |
| 371 if (result.ContainsFlag(kInobjectFields)) { |
| 372 int index; |
| 373 if (instr->IsStoreNamedField() && |
| 374 ComputeInobjectField(HStoreNamedField::cast(instr)->access(), &index)) { |
| 375 result.RemoveFlag(kInobjectFields); |
| 376 result.AddSpecial(index); |
| 377 } else { |
| 378 result.AddAllSpecial(); |
| 379 } |
| 380 } |
| 381 return result; |
| 382 } |
| 383 |
| 384 |
| 385 SideEffects SideEffectsScope::ComputeDependsOn(HInstruction* instr) { |
| 386 SideEffects result(instr->DependsOnFlags()); |
| 387 if (result.ContainsFlag(kInobjectFields)) { |
| 388 int index; |
| 389 if (instr->IsLoadNamedField() && |
| 390 ComputeInobjectField(HLoadNamedField::cast(instr)->access(), &index)) { |
| 391 result.RemoveFlag(kInobjectFields); |
| 392 result.AddSpecial(index); |
| 393 } else { |
| 394 result.AddAllSpecial(); |
| 395 } |
| 396 } |
| 397 return result; |
| 398 } |
| 399 |
| 400 |
| 401 void SideEffectsScope::PrintSideEffectsTo(StringStream* stream, |
| 402 SideEffects side_effects) const { |
| 403 const char* separator = ""; |
| 404 stream->Add("["); |
| 405 for (int bit = 0; bit < kNumberOfFlags; ++bit) { |
| 406 GVNFlag flag = GVNFlagFromInt(bit); |
| 407 if (side_effects.ContainsFlag(flag)) { |
| 408 stream->Add(separator); |
| 409 separator = ", "; |
| 410 switch (flag) { |
| 411 #define DECLARE_FLAG(Type) \ |
| 412 case k##Type: \ |
| 413 stream->Add(#Type); \ |
| 414 break; |
| 415 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) |
| 416 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) |
| 417 #undef DECLARE_FLAG |
| 418 default: |
| 419 break; |
| 420 } |
| 421 } |
| 422 } |
| 423 for (int index = 0; index < num_inobject_fields_; ++index) { |
| 424 if (side_effects.ContainsSpecial(index)) { |
| 425 stream->Add(separator); |
| 426 separator = ", "; |
| 427 inobject_fields_[index].PrintTo(stream); |
| 428 } |
| 429 } |
| 430 stream->Add("]"); |
| 431 } |
| 432 |
| 433 |
| 434 bool SideEffectsScope::ComputeInobjectField(HObjectAccess access, int* index) { |
| 435 for (int i = 0; i < num_inobject_fields_; ++i) { |
| 436 if (access.Equals(inobject_fields_[i])) { |
| 437 *index = i; |
| 438 return true; |
| 439 } |
| 440 } |
| 441 if (num_inobject_fields_ < SideEffects::kNumberOfSpecials) { |
| 442 if (FLAG_trace_gvn) { |
| 443 HeapStringAllocator allocator; |
| 444 StringStream stream(&allocator); |
| 445 stream.Add("Recording inobject field access "); |
| 446 access.PrintTo(&stream); |
| 447 stream.Add(" (mapped to special index %d)\n", num_inobject_fields_); |
| 448 stream.OutputToStdOut(); |
| 449 } |
| 450 *index = num_inobject_fields_; |
| 451 inobject_fields_[num_inobject_fields_++] = access; |
| 452 return true; |
| 453 } |
| 454 return false; |
| 455 } |
| 456 |
| 457 |
366 HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) | 458 HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) |
367 : HPhase("H_Global value numbering", graph), | 459 : HPhase("H_Global value numbering", graph), |
368 removed_side_effects_(false), | 460 removed_side_effects_(false), |
369 block_side_effects_(graph->blocks()->length(), zone()), | 461 block_side_effects_(graph->blocks()->length(), zone()), |
370 loop_side_effects_(graph->blocks()->length(), zone()), | 462 loop_side_effects_(graph->blocks()->length(), zone()), |
371 visited_on_paths_(graph->blocks()->length(), zone()) { | 463 visited_on_paths_(graph->blocks()->length(), zone()) { |
372 ASSERT(!AllowHandleAllocation::IsAllowed()); | 464 ASSERT(!AllowHandleAllocation::IsAllowed()); |
373 block_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | 465 block_side_effects_.AddBlock( |
374 zone()); | 466 SideEffects(), graph->blocks()->length(), zone()); |
375 loop_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | 467 loop_side_effects_.AddBlock( |
376 zone()); | 468 SideEffects(), graph->blocks()->length(), zone()); |
377 } | 469 } |
378 | 470 |
379 | 471 |
380 void HGlobalValueNumberingPhase::Run() { | 472 void HGlobalValueNumberingPhase::Run() { |
381 ASSERT(!removed_side_effects_); | 473 ASSERT(!removed_side_effects_); |
382 for (int i = FLAG_gvn_iterations; i > 0; --i) { | 474 for (int i = FLAG_gvn_iterations; i > 0; --i) { |
383 // Compute the side effects. | 475 // Compute the side effects. |
384 ComputeBlockSideEffects(); | 476 ComputeBlockSideEffects(); |
385 | 477 |
386 // Perform loop invariant code motion if requested. | 478 // Perform loop invariant code motion if requested. |
(...skipping 15 matching lines...) Expand all Loading... |
402 } | 494 } |
403 visited_on_paths_.Clear(); | 495 visited_on_paths_.Clear(); |
404 } | 496 } |
405 } | 497 } |
406 | 498 |
407 | 499 |
408 void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { | 500 void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { |
409 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 501 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { |
410 // Compute side effects for the block. | 502 // Compute side effects for the block. |
411 HBasicBlock* block = graph()->blocks()->at(i); | 503 HBasicBlock* block = graph()->blocks()->at(i); |
412 GVNFlagSet side_effects; | 504 SideEffects side_effects; |
413 if (block->IsReachable() && !block->IsDeoptimizing()) { | 505 if (block->IsReachable() && !block->IsDeoptimizing()) { |
414 int id = block->block_id(); | 506 int id = block->block_id(); |
415 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 507 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
416 HInstruction* instr = it.Current(); | 508 HInstruction* instr = it.Current(); |
417 side_effects.Add(instr->ChangesFlags()); | 509 side_effects.Add(side_effects_scope_.ComputeChanges(instr)); |
418 } | 510 } |
419 block_side_effects_[id].Add(side_effects); | 511 block_side_effects_[id].Add(side_effects); |
420 | 512 |
421 // Loop headers are part of their loop. | 513 // Loop headers are part of their loop. |
422 if (block->IsLoopHeader()) { | 514 if (block->IsLoopHeader()) { |
423 loop_side_effects_[id].Add(side_effects); | 515 loop_side_effects_[id].Add(side_effects); |
424 } | 516 } |
425 | 517 |
426 // Propagate loop side effects upwards. | 518 // Propagate loop side effects upwards. |
427 if (block->HasParentLoopHeader()) { | 519 if (block->HasParentLoopHeader()) { |
428 HBasicBlock* with_parent = block; | 520 HBasicBlock* with_parent = block; |
429 if (block->IsLoopHeader()) side_effects = loop_side_effects_[id]; | 521 if (block->IsLoopHeader()) side_effects = loop_side_effects_[id]; |
430 do { | 522 do { |
431 HBasicBlock* parent_block = with_parent->parent_loop_header(); | 523 HBasicBlock* parent_block = with_parent->parent_loop_header(); |
432 loop_side_effects_[parent_block->block_id()].Add(side_effects); | 524 loop_side_effects_[parent_block->block_id()].Add(side_effects); |
433 with_parent = parent_block; | 525 with_parent = parent_block; |
434 } while (with_parent->HasParentLoopHeader()); | 526 } while (with_parent->HasParentLoopHeader()); |
435 } | 527 } |
436 } | 528 } |
437 } | 529 } |
438 } | 530 } |
439 | 531 |
440 | 532 |
441 SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { | |
442 char underlying_buffer[kNumberOfFlags * 128]; | |
443 Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); | |
444 #if DEBUG | |
445 int offset = 0; | |
446 const char* separator = ""; | |
447 const char* comma = ", "; | |
448 buffer[0] = 0; | |
449 uint32_t set_depends_on = 0; | |
450 uint32_t set_changes = 0; | |
451 for (int bit = 0; bit < kNumberOfFlags; ++bit) { | |
452 if (flags.Contains(static_cast<GVNFlag>(bit))) { | |
453 if (bit % 2 == 0) { | |
454 set_changes++; | |
455 } else { | |
456 set_depends_on++; | |
457 } | |
458 } | |
459 } | |
460 bool positive_changes = set_changes < (kNumberOfFlags / 2); | |
461 bool positive_depends_on = set_depends_on < (kNumberOfFlags / 2); | |
462 if (set_changes > 0) { | |
463 if (positive_changes) { | |
464 offset += OS::SNPrintF(buffer + offset, "changes ["); | |
465 } else { | |
466 offset += OS::SNPrintF(buffer + offset, "changes all except ["); | |
467 } | |
468 for (int bit = 0; bit < kNumberOfFlags; ++bit) { | |
469 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) { | |
470 switch (static_cast<GVNFlag>(bit)) { | |
471 #define DECLARE_FLAG(type) \ | |
472 case kChanges##type: \ | |
473 offset += OS::SNPrintF(buffer + offset, separator); \ | |
474 offset += OS::SNPrintF(buffer + offset, #type); \ | |
475 separator = comma; \ | |
476 break; | |
477 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | |
478 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | |
479 #undef DECLARE_FLAG | |
480 default: | |
481 break; | |
482 } | |
483 } | |
484 } | |
485 offset += OS::SNPrintF(buffer + offset, "]"); | |
486 } | |
487 if (set_depends_on > 0) { | |
488 separator = ""; | |
489 if (set_changes > 0) { | |
490 offset += OS::SNPrintF(buffer + offset, ", "); | |
491 } | |
492 if (positive_depends_on) { | |
493 offset += OS::SNPrintF(buffer + offset, "depends on ["); | |
494 } else { | |
495 offset += OS::SNPrintF(buffer + offset, "depends on all except ["); | |
496 } | |
497 for (int bit = 0; bit < kNumberOfFlags; ++bit) { | |
498 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) { | |
499 switch (static_cast<GVNFlag>(bit)) { | |
500 #define DECLARE_FLAG(type) \ | |
501 case kDependsOn##type: \ | |
502 offset += OS::SNPrintF(buffer + offset, separator); \ | |
503 offset += OS::SNPrintF(buffer + offset, #type); \ | |
504 separator = comma; \ | |
505 break; | |
506 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | |
507 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | |
508 #undef DECLARE_FLAG | |
509 default: | |
510 break; | |
511 } | |
512 } | |
513 } | |
514 offset += OS::SNPrintF(buffer + offset, "]"); | |
515 } | |
516 #else | |
517 OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral()); | |
518 #endif | |
519 size_t string_len = strlen(underlying_buffer) + 1; | |
520 ASSERT(string_len <= sizeof(underlying_buffer)); | |
521 char* result = new char[strlen(underlying_buffer) + 1]; | |
522 OS::MemCopy(result, underlying_buffer, string_len); | |
523 return SmartArrayPointer<char>(result); | |
524 } | |
525 | |
526 | |
527 void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() { | 533 void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() { |
528 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", | 534 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", |
529 graph()->use_optimistic_licm() ? "yes" : "no"); | 535 graph()->use_optimistic_licm() ? "yes" : "no"); |
530 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 536 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { |
531 HBasicBlock* block = graph()->blocks()->at(i); | 537 HBasicBlock* block = graph()->blocks()->at(i); |
532 if (block->IsLoopHeader()) { | 538 if (block->IsLoopHeader()) { |
533 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 539 SideEffects side_effects = loop_side_effects_[block->block_id()]; |
534 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", | 540 if (FLAG_trace_gvn) { |
535 block->block_id(), | 541 HeapStringAllocator allocator; |
536 GetGVNFlagsString(side_effects).get()); | 542 StringStream stream(&allocator); |
537 | 543 stream.Add("Try loop invariant motion for block B%d changes ", |
| 544 block->block_id()); |
| 545 side_effects_scope_.PrintSideEffectsTo(&stream, side_effects); |
| 546 stream.Add("\n"); |
| 547 stream.OutputToStdOut(); |
| 548 } |
538 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | 549 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); |
539 for (int j = block->block_id(); j <= last->block_id(); ++j) { | 550 for (int j = block->block_id(); j <= last->block_id(); ++j) { |
540 ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects); | 551 ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects); |
541 } | 552 } |
542 } | 553 } |
543 } | 554 } |
544 } | 555 } |
545 | 556 |
546 | 557 |
547 void HGlobalValueNumberingPhase::ProcessLoopBlock( | 558 void HGlobalValueNumberingPhase::ProcessLoopBlock( |
548 HBasicBlock* block, | 559 HBasicBlock* block, |
549 HBasicBlock* loop_header, | 560 HBasicBlock* loop_header, |
550 GVNFlagSet loop_kills) { | 561 SideEffects loop_kills) { |
551 HBasicBlock* pre_header = loop_header->predecessors()->at(0); | 562 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
552 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | 563 if (FLAG_trace_gvn) { |
553 TRACE_GVN_2("Loop invariant motion for B%d %s\n", | 564 HeapStringAllocator allocator; |
554 block->block_id(), | 565 StringStream stream(&allocator); |
555 GetGVNFlagsString(depends_flags).get()); | 566 stream.Add("Loop invariant code motion for B%d depends on ", |
| 567 block->block_id()); |
| 568 side_effects_scope_.PrintSideEffectsTo(&stream, loop_kills); |
| 569 stream.Add("\n"); |
| 570 stream.OutputToStdOut(); |
| 571 } |
556 HInstruction* instr = block->first(); | 572 HInstruction* instr = block->first(); |
557 while (instr != NULL) { | 573 while (instr != NULL) { |
558 HInstruction* next = instr->next(); | 574 HInstruction* next = instr->next(); |
559 if (instr->CheckFlag(HValue::kUseGVN)) { | 575 if (instr->CheckFlag(HValue::kUseGVN)) { |
560 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | 576 SideEffects changes = side_effects_scope_.ComputeChanges(instr); |
561 instr->id(), | 577 SideEffects depends_on = side_effects_scope_.ComputeDependsOn(instr); |
562 instr->Mnemonic(), | 578 if (FLAG_trace_gvn) { |
563 GetGVNFlagsString(instr->gvn_flags()).get(), | 579 HeapStringAllocator allocator; |
564 GetGVNFlagsString(loop_kills).get()); | 580 StringStream stream(&allocator); |
565 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 581 stream.Add("Checking instruction i%d (%s) changes ", |
| 582 instr->id(), instr->Mnemonic()); |
| 583 side_effects_scope_.PrintSideEffectsTo(&stream, changes); |
| 584 stream.Add(", depends on "); |
| 585 side_effects_scope_.PrintSideEffectsTo(&stream, depends_on); |
| 586 stream.Add(". Loop changes "); |
| 587 side_effects_scope_.PrintSideEffectsTo(&stream, loop_kills); |
| 588 stream.Add("\n"); |
| 589 stream.OutputToStdOut(); |
| 590 } |
| 591 bool can_hoist = !depends_on.ContainsAnyOf(loop_kills); |
566 if (can_hoist && !graph()->use_optimistic_licm()) { | 592 if (can_hoist && !graph()->use_optimistic_licm()) { |
567 can_hoist = block->IsLoopSuccessorDominator(); | 593 can_hoist = block->IsLoopSuccessorDominator(); |
568 } | 594 } |
569 | 595 |
570 if (can_hoist) { | 596 if (can_hoist) { |
571 bool inputs_loop_invariant = true; | 597 bool inputs_loop_invariant = true; |
572 for (int i = 0; i < instr->OperandCount(); ++i) { | 598 for (int i = 0; i < instr->OperandCount(); ++i) { |
573 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | 599 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { |
574 inputs_loop_invariant = false; | 600 inputs_loop_invariant = false; |
575 } | 601 } |
(...skipping 21 matching lines...) Expand all Loading... |
597 | 623 |
598 bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr, | 624 bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr, |
599 HBasicBlock* loop_header) { | 625 HBasicBlock* loop_header) { |
600 // If we've disabled code motion or we're in a block that unconditionally | 626 // If we've disabled code motion or we're in a block that unconditionally |
601 // deoptimizes, don't move any instructions. | 627 // deoptimizes, don't move any instructions. |
602 return AllowCodeMotion() && !instr->block()->IsDeoptimizing() && | 628 return AllowCodeMotion() && !instr->block()->IsDeoptimizing() && |
603 instr->block()->IsReachable(); | 629 instr->block()->IsReachable(); |
604 } | 630 } |
605 | 631 |
606 | 632 |
607 GVNFlagSet | 633 SideEffects |
608 HGlobalValueNumberingPhase::CollectSideEffectsOnPathsToDominatedBlock( | 634 HGlobalValueNumberingPhase::CollectSideEffectsOnPathsToDominatedBlock( |
609 HBasicBlock* dominator, HBasicBlock* dominated) { | 635 HBasicBlock* dominator, HBasicBlock* dominated) { |
610 GVNFlagSet side_effects; | 636 SideEffects side_effects; |
611 for (int i = 0; i < dominated->predecessors()->length(); ++i) { | 637 for (int i = 0; i < dominated->predecessors()->length(); ++i) { |
612 HBasicBlock* block = dominated->predecessors()->at(i); | 638 HBasicBlock* block = dominated->predecessors()->at(i); |
613 if (dominator->block_id() < block->block_id() && | 639 if (dominator->block_id() < block->block_id() && |
614 block->block_id() < dominated->block_id() && | 640 block->block_id() < dominated->block_id() && |
615 !visited_on_paths_.Contains(block->block_id())) { | 641 !visited_on_paths_.Contains(block->block_id())) { |
616 visited_on_paths_.Add(block->block_id()); | 642 visited_on_paths_.Add(block->block_id()); |
617 side_effects.Add(block_side_effects_[block->block_id()]); | 643 side_effects.Add(block_side_effects_[block->block_id()]); |
618 if (block->IsLoopHeader()) { | 644 if (block->IsLoopHeader()) { |
619 side_effects.Add(loop_side_effects_[block->block_id()]); | 645 side_effects.Add(loop_side_effects_[block->block_id()]); |
620 } | 646 } |
621 side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock( | 647 side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock( |
622 dominator, block)); | 648 dominator, block)); |
623 } | 649 } |
624 } | 650 } |
625 return side_effects; | 651 return side_effects; |
626 } | 652 } |
627 | 653 |
628 | 654 |
629 // Each instance of this class is like a "stack frame" for the recursive | 655 // Each instance of this class is like a "stack frame" for the recursive |
630 // traversal of the dominator tree done during GVN (the stack is handled | 656 // traversal of the dominator tree done during GVN (the stack is handled |
631 // as a double linked list). | 657 // as a double linked list). |
632 // We reuse frames when possible so the list length is limited by the depth | 658 // We reuse frames when possible so the list length is limited by the depth |
633 // of the dominator tree but this forces us to initialize each frame calling | 659 // of the dominator tree but this forces us to initialize each frame calling |
634 // an explicit "Initialize" method instead of a using constructor. | 660 // an explicit "Initialize" method instead of a using constructor. |
635 class GvnBasicBlockState: public ZoneObject { | 661 class GvnBasicBlockState: public ZoneObject { |
636 public: | 662 public: |
637 static GvnBasicBlockState* CreateEntry(Zone* zone, | 663 static GvnBasicBlockState* CreateEntry(Zone* zone, |
638 HBasicBlock* entry_block, | 664 HBasicBlock* entry_block, |
639 HValueMap* entry_map) { | 665 HInstructionMap* entry_map) { |
640 return new(zone) | 666 return new(zone) |
641 GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone); | 667 GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone); |
642 } | 668 } |
643 | 669 |
644 HBasicBlock* block() { return block_; } | 670 HBasicBlock* block() { return block_; } |
645 HValueMap* map() { return map_; } | 671 HInstructionMap* map() { return map_; } |
646 HSideEffectMap* dominators() { return &dominators_; } | 672 HSideEffectMap* dominators() { return &dominators_; } |
647 | 673 |
648 GvnBasicBlockState* next_in_dominator_tree_traversal( | 674 GvnBasicBlockState* next_in_dominator_tree_traversal( |
649 Zone* zone, | 675 Zone* zone, |
650 HBasicBlock** dominator) { | 676 HBasicBlock** dominator) { |
651 // This assignment needs to happen before calling next_dominated() because | 677 // This assignment needs to happen before calling next_dominated() because |
652 // that call can reuse "this" if we are at the last dominated block. | 678 // that call can reuse "this" if we are at the last dominated block. |
653 *dominator = block(); | 679 *dominator = block(); |
654 GvnBasicBlockState* result = next_dominated(zone); | 680 GvnBasicBlockState* result = next_dominated(zone); |
655 if (result == NULL) { | 681 if (result == NULL) { |
656 GvnBasicBlockState* dominator_state = pop(); | 682 GvnBasicBlockState* dominator_state = pop(); |
657 if (dominator_state != NULL) { | 683 if (dominator_state != NULL) { |
658 // This branch is guaranteed not to return NULL because pop() never | 684 // This branch is guaranteed not to return NULL because pop() never |
659 // returns a state where "is_done() == true". | 685 // returns a state where "is_done() == true". |
660 *dominator = dominator_state->block(); | 686 *dominator = dominator_state->block(); |
661 result = dominator_state->next_dominated(zone); | 687 result = dominator_state->next_dominated(zone); |
662 } else { | 688 } else { |
663 // Unnecessary (we are returning NULL) but done for cleanness. | 689 // Unnecessary (we are returning NULL) but done for cleanness. |
664 *dominator = NULL; | 690 *dominator = NULL; |
665 } | 691 } |
666 } | 692 } |
667 return result; | 693 return result; |
668 } | 694 } |
669 | 695 |
670 private: | 696 private: |
671 void Initialize(HBasicBlock* block, | 697 void Initialize(HBasicBlock* block, |
672 HValueMap* map, | 698 HInstructionMap* map, |
673 HSideEffectMap* dominators, | 699 HSideEffectMap* dominators, |
674 bool copy_map, | 700 bool copy_map, |
675 Zone* zone) { | 701 Zone* zone) { |
676 block_ = block; | 702 block_ = block; |
677 map_ = copy_map ? map->Copy(zone) : map; | 703 map_ = copy_map ? map->Copy(zone) : map; |
678 dominated_index_ = -1; | 704 dominated_index_ = -1; |
679 length_ = block->dominated_blocks()->length(); | 705 length_ = block->dominated_blocks()->length(); |
680 if (dominators != NULL) { | 706 if (dominators != NULL) { |
681 dominators_ = *dominators; | 707 dominators_ = *dominators; |
682 } | 708 } |
683 } | 709 } |
684 bool is_done() { return dominated_index_ >= length_; } | 710 bool is_done() { return dominated_index_ >= length_; } |
685 | 711 |
686 GvnBasicBlockState(GvnBasicBlockState* previous, | 712 GvnBasicBlockState(GvnBasicBlockState* previous, |
687 HBasicBlock* block, | 713 HBasicBlock* block, |
688 HValueMap* map, | 714 HInstructionMap* map, |
689 HSideEffectMap* dominators, | 715 HSideEffectMap* dominators, |
690 Zone* zone) | 716 Zone* zone) |
691 : previous_(previous), next_(NULL) { | 717 : previous_(previous), next_(NULL) { |
692 Initialize(block, map, dominators, true, zone); | 718 Initialize(block, map, dominators, true, zone); |
693 } | 719 } |
694 | 720 |
695 GvnBasicBlockState* next_dominated(Zone* zone) { | 721 GvnBasicBlockState* next_dominated(Zone* zone) { |
696 dominated_index_++; | 722 dominated_index_++; |
697 if (dominated_index_ == length_ - 1) { | 723 if (dominated_index_ == length_ - 1) { |
698 // No need to copy the map for the last child in the dominator tree. | 724 // No need to copy the map for the last child in the dominator tree. |
(...skipping 26 matching lines...) Expand all Loading... |
725 block()->block_id(), | 751 block()->block_id(), |
726 previous_->block()->block_id()) | 752 previous_->block()->block_id()) |
727 result = result->previous_; | 753 result = result->previous_; |
728 } | 754 } |
729 return result; | 755 return result; |
730 } | 756 } |
731 | 757 |
732 GvnBasicBlockState* previous_; | 758 GvnBasicBlockState* previous_; |
733 GvnBasicBlockState* next_; | 759 GvnBasicBlockState* next_; |
734 HBasicBlock* block_; | 760 HBasicBlock* block_; |
735 HValueMap* map_; | 761 HInstructionMap* map_; |
736 HSideEffectMap dominators_; | 762 HSideEffectMap dominators_; |
737 int dominated_index_; | 763 int dominated_index_; |
738 int length_; | 764 int length_; |
739 }; | 765 }; |
740 | 766 |
741 | 767 |
742 // This is a recursive traversal of the dominator tree but it has been turned | 768 // This is a recursive traversal of the dominator tree but it has been turned |
743 // into a loop to avoid stack overflows. | 769 // into a loop to avoid stack overflows. |
744 // The logical "stack frames" of the recursion are kept in a list of | 770 // The logical "stack frames" of the recursion are kept in a list of |
745 // GvnBasicBlockState instances. | 771 // GvnBasicBlockState instances. |
746 void HGlobalValueNumberingPhase::AnalyzeGraph() { | 772 void HGlobalValueNumberingPhase::AnalyzeGraph() { |
747 HBasicBlock* entry_block = graph()->entry_block(); | 773 HBasicBlock* entry_block = graph()->entry_block(); |
748 HValueMap* entry_map = new(zone()) HValueMap(zone()); | 774 HInstructionMap* entry_map = |
| 775 new(zone()) HInstructionMap(zone(), &side_effects_scope_); |
749 GvnBasicBlockState* current = | 776 GvnBasicBlockState* current = |
750 GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map); | 777 GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map); |
751 | 778 |
752 while (current != NULL) { | 779 while (current != NULL) { |
753 HBasicBlock* block = current->block(); | 780 HBasicBlock* block = current->block(); |
754 HValueMap* map = current->map(); | 781 HInstructionMap* map = current->map(); |
755 HSideEffectMap* dominators = current->dominators(); | 782 HSideEffectMap* dominators = current->dominators(); |
756 | 783 |
757 TRACE_GVN_2("Analyzing block B%d%s\n", | 784 TRACE_GVN_2("Analyzing block B%d%s\n", |
758 block->block_id(), | 785 block->block_id(), |
759 block->IsLoopHeader() ? " (loop header)" : ""); | 786 block->IsLoopHeader() ? " (loop header)" : ""); |
760 | 787 |
761 // If this is a loop header kill everything killed by the loop. | 788 // If this is a loop header kill everything killed by the loop. |
762 if (block->IsLoopHeader()) { | 789 if (block->IsLoopHeader()) { |
763 map->Kill(loop_side_effects_[block->block_id()]); | 790 map->Kill(loop_side_effects_[block->block_id()]); |
764 dominators->Kill(loop_side_effects_[block->block_id()]); | 791 dominators->Kill(loop_side_effects_[block->block_id()]); |
765 } | 792 } |
766 | 793 |
767 // Go through all instructions of the current block. | 794 // Go through all instructions of the current block. |
768 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 795 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
769 HInstruction* instr = it.Current(); | 796 HInstruction* instr = it.Current(); |
770 if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) { | 797 if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) { |
771 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 798 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { |
772 HValue* other = dominators->at(i); | 799 HValue* other = dominators->at(i); |
773 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 800 GVNFlag flag = GVNFlagFromInt(i); |
774 GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); | 801 if (instr->DependsOnFlags().Contains(flag) && other != NULL) { |
775 if (instr->DependsOnFlags().Contains(depends_on_flag) && | |
776 (other != NULL)) { | |
777 TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", | 802 TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", |
778 i, | 803 i, |
779 instr->id(), | 804 instr->id(), |
780 instr->Mnemonic(), | 805 instr->Mnemonic(), |
781 other->id(), | 806 other->id(), |
782 other->Mnemonic()); | 807 other->Mnemonic()); |
783 if (instr->HandleSideEffectDominator(changes_flag, other)) { | 808 if (instr->HandleSideEffectDominator(flag, other)) { |
784 removed_side_effects_ = true; | 809 removed_side_effects_ = true; |
785 } | 810 } |
786 } | 811 } |
787 } | 812 } |
788 } | 813 } |
789 // Instruction was unlinked during graph traversal. | 814 // Instruction was unlinked during graph traversal. |
790 if (!instr->IsLinked()) continue; | 815 if (!instr->IsLinked()) continue; |
791 | 816 |
792 GVNFlagSet flags = instr->ChangesFlags(); | 817 SideEffects changes = side_effects_scope_.ComputeChanges(instr); |
793 if (!flags.IsEmpty()) { | 818 if (!changes.IsEmpty()) { |
794 // Clear all instructions in the map that are affected by side effects. | 819 // Clear all instructions in the map that are affected by side effects. |
795 // Store instruction as the dominating one for tracked side effects. | 820 // Store instruction as the dominating one for tracked side effects. |
796 map->Kill(flags); | 821 map->Kill(changes); |
797 dominators->Store(flags, instr); | 822 dominators->Store(changes, instr); |
798 TRACE_GVN_2("Instruction %d %s\n", instr->id(), | 823 if (FLAG_trace_gvn) { |
799 GetGVNFlagsString(flags).get()); | 824 HeapStringAllocator allocator; |
| 825 StringStream stream(&allocator); |
| 826 stream.Add("Instruction i%d changes ", instr->id()); |
| 827 side_effects_scope_.PrintSideEffectsTo(&stream, changes); |
| 828 stream.Add("\n"); |
| 829 stream.OutputToStdOut(); |
| 830 } |
800 } | 831 } |
801 if (instr->CheckFlag(HValue::kUseGVN)) { | 832 if (instr->CheckFlag(HValue::kUseGVN)) { |
802 ASSERT(!instr->HasObservableSideEffects()); | 833 ASSERT(!instr->HasObservableSideEffects()); |
803 HValue* other = map->Lookup(instr); | 834 HInstruction* other = map->Lookup(instr); |
804 if (other != NULL) { | 835 if (other != NULL) { |
805 ASSERT(instr->Equals(other) && other->Equals(instr)); | 836 ASSERT(instr->Equals(other) && other->Equals(instr)); |
806 TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n", | 837 TRACE_GVN_4("Replacing instruction i%d (%s) with i%d (%s)\n", |
807 instr->id(), | 838 instr->id(), |
808 instr->Mnemonic(), | 839 instr->Mnemonic(), |
809 other->id(), | 840 other->id(), |
810 other->Mnemonic()); | 841 other->Mnemonic()); |
811 if (instr->HasSideEffects()) removed_side_effects_ = true; | 842 if (instr->HasSideEffects()) removed_side_effects_ = true; |
812 instr->DeleteAndReplaceWith(other); | 843 instr->DeleteAndReplaceWith(other); |
813 } else { | 844 } else { |
814 map->Add(instr, zone()); | 845 map->Add(instr, zone()); |
815 } | 846 } |
816 } | 847 } |
817 } | 848 } |
818 | 849 |
819 HBasicBlock* dominator_block; | 850 HBasicBlock* dominator_block; |
820 GvnBasicBlockState* next = | 851 GvnBasicBlockState* next = |
821 current->next_in_dominator_tree_traversal(zone(), | 852 current->next_in_dominator_tree_traversal(zone(), |
822 &dominator_block); | 853 &dominator_block); |
823 | 854 |
824 if (next != NULL) { | 855 if (next != NULL) { |
825 HBasicBlock* dominated = next->block(); | 856 HBasicBlock* dominated = next->block(); |
826 HValueMap* successor_map = next->map(); | 857 HInstructionMap* successor_map = next->map(); |
827 HSideEffectMap* successor_dominators = next->dominators(); | 858 HSideEffectMap* successor_dominators = next->dominators(); |
828 | 859 |
829 // Kill everything killed on any path between this block and the | 860 // Kill everything killed on any path between this block and the |
830 // dominated block. We don't have to traverse these paths if the | 861 // dominated block. We don't have to traverse these paths if the |
831 // value map and the dominators list is already empty. If the range | 862 // value map and the dominators list is already empty. If the range |
832 // of block ids (block_id, dominated_id) is empty there are no such | 863 // of block ids (block_id, dominated_id) is empty there are no such |
833 // paths. | 864 // paths. |
834 if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) && | 865 if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) && |
835 dominator_block->block_id() + 1 < dominated->block_id()) { | 866 dominator_block->block_id() + 1 < dominated->block_id()) { |
836 visited_on_paths_.Clear(); | 867 visited_on_paths_.Clear(); |
837 GVNFlagSet side_effects_on_all_paths = | 868 SideEffects side_effects_on_all_paths = |
838 CollectSideEffectsOnPathsToDominatedBlock(dominator_block, | 869 CollectSideEffectsOnPathsToDominatedBlock(dominator_block, |
839 dominated); | 870 dominated); |
840 successor_map->Kill(side_effects_on_all_paths); | 871 successor_map->Kill(side_effects_on_all_paths); |
841 successor_dominators->Kill(side_effects_on_all_paths); | 872 successor_dominators->Kill(side_effects_on_all_paths); |
842 } | 873 } |
843 } | 874 } |
844 current = next; | 875 current = next; |
845 } | 876 } |
846 } | 877 } |
847 | 878 |
848 } } // namespace v8::internal | 879 } } // namespace v8::internal |
OLD | NEW |