OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #ifndef RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ | 5 #ifndef RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ |
6 #define RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ | 6 #define RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ |
7 | 7 |
8 #include "vm/flow_graph.h" | 8 #include "vm/flow_graph.h" |
9 #include "vm/growable_array.h" | 9 #include "vm/growable_array.h" |
10 #include "vm/intermediate_language.h" | 10 #include "vm/intermediate_language.h" |
11 | 11 |
12 namespace dart { | 12 namespace dart { |
13 | 13 |
14 class AllocationFinger; | 14 class AllocationFinger; |
15 class BlockInfo; | 15 class BlockInfo; |
16 class FlowGraph; | 16 class FlowGraph; |
17 class LiveRange; | 17 class LiveRange; |
18 class UseInterval; | 18 class UseInterval; |
19 class UsePosition; | 19 class UsePosition; |
20 | 20 |
21 | |
22 class ReachingDefs : public ValueObject { | 21 class ReachingDefs : public ValueObject { |
23 public: | 22 public: |
24 explicit ReachingDefs(const FlowGraph& flow_graph) | 23 explicit ReachingDefs(const FlowGraph& flow_graph) |
25 : flow_graph_(flow_graph), phis_(10) {} | 24 : flow_graph_(flow_graph), phis_(10) {} |
26 | 25 |
27 BitVector* Get(PhiInstr* phi); | 26 BitVector* Get(PhiInstr* phi); |
28 | 27 |
29 private: | 28 private: |
30 void AddPhi(PhiInstr* phi); | 29 void AddPhi(PhiInstr* phi); |
31 void Compute(); | 30 void Compute(); |
32 | 31 |
33 const FlowGraph& flow_graph_; | 32 const FlowGraph& flow_graph_; |
34 GrowableArray<PhiInstr*> phis_; | 33 GrowableArray<PhiInstr*> phis_; |
35 }; | 34 }; |
36 | 35 |
37 | |
38 class SSALivenessAnalysis : public LivenessAnalysis { | 36 class SSALivenessAnalysis : public LivenessAnalysis { |
39 public: | 37 public: |
40 explicit SSALivenessAnalysis(const FlowGraph& flow_graph) | 38 explicit SSALivenessAnalysis(const FlowGraph& flow_graph) |
41 : LivenessAnalysis(flow_graph.max_virtual_register_number(), | 39 : LivenessAnalysis(flow_graph.max_virtual_register_number(), |
42 flow_graph.postorder()), | 40 flow_graph.postorder()), |
43 graph_entry_(flow_graph.graph_entry()) {} | 41 graph_entry_(flow_graph.graph_entry()) {} |
44 | 42 |
45 private: | 43 private: |
46 // Compute initial values for live-out, kill and live-in sets. | 44 // Compute initial values for live-out, kill and live-in sets. |
47 virtual void ComputeInitialSets(); | 45 virtual void ComputeInitialSets(); |
48 | 46 |
49 GraphEntryInstr* graph_entry_; | 47 GraphEntryInstr* graph_entry_; |
50 }; | 48 }; |
51 | 49 |
52 | |
53 class FlowGraphAllocator : public ValueObject { | 50 class FlowGraphAllocator : public ValueObject { |
54 public: | 51 public: |
55 // Number of stack slots needed for a fpu register spill slot. | 52 // Number of stack slots needed for a fpu register spill slot. |
56 static const intptr_t kDoubleSpillFactor = kDoubleSize / kWordSize; | 53 static const intptr_t kDoubleSpillFactor = kDoubleSize / kWordSize; |
57 | 54 |
58 explicit FlowGraphAllocator(const FlowGraph& flow_graph, | 55 explicit FlowGraphAllocator(const FlowGraph& flow_graph, |
59 bool intrinsic_mode = false); | 56 bool intrinsic_mode = false); |
60 | 57 |
61 void AllocateRegisters(); | 58 void AllocateRegisters(); |
62 | 59 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 | 143 |
147 // Find all safepoints that are covered by this live range. | 144 // Find all safepoints that are covered by this live range. |
148 void AssignSafepoints(Definition* defn, LiveRange* range); | 145 void AssignSafepoints(Definition* defn, LiveRange* range); |
149 | 146 |
150 void PrepareForAllocation(Location::Kind register_kind, | 147 void PrepareForAllocation(Location::Kind register_kind, |
151 intptr_t number_of_registers, | 148 intptr_t number_of_registers, |
152 const GrowableArray<LiveRange*>& unallocated, | 149 const GrowableArray<LiveRange*>& unallocated, |
153 LiveRange** blocking_ranges, | 150 LiveRange** blocking_ranges, |
154 bool* blocked_registers); | 151 bool* blocked_registers); |
155 | 152 |
156 | |
157 // Process live ranges sorted by their start and assign registers | 153 // Process live ranges sorted by their start and assign registers |
158 // to them | 154 // to them |
159 void AllocateUnallocatedRanges(); | 155 void AllocateUnallocatedRanges(); |
160 void AdvanceActiveIntervals(const intptr_t start); | 156 void AdvanceActiveIntervals(const intptr_t start); |
161 | 157 |
162 // Connect split siblings over non-linear control flow edges. | 158 // Connect split siblings over non-linear control flow edges. |
163 void ResolveControlFlow(); | 159 void ResolveControlFlow(); |
164 void ConnectSplitSiblings(LiveRange* range, | 160 void ConnectSplitSiblings(LiveRange* range, |
165 BlockEntryInstr* source_block, | 161 BlockEntryInstr* source_block, |
166 BlockEntryInstr* target_block); | 162 BlockEntryInstr* target_block); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 | 300 |
305 // Per register lists of allocated live ranges. Contain only those | 301 // Per register lists of allocated live ranges. Contain only those |
306 // ranges that can be affected by future allocation decisions. | 302 // ranges that can be affected by future allocation decisions. |
307 // Those live ranges that end before the start of the current live range are | 303 // Those live ranges that end before the start of the current live range are |
308 // removed from the list and will not be affected. | 304 // removed from the list and will not be affected. |
309 // The length of both arrays is 'number_of_registers_' | 305 // The length of both arrays is 'number_of_registers_' |
310 GrowableArray<ZoneGrowableArray<LiveRange*>*> registers_; | 306 GrowableArray<ZoneGrowableArray<LiveRange*>*> registers_; |
311 | 307 |
312 GrowableArray<bool> blocked_registers_; | 308 GrowableArray<bool> blocked_registers_; |
313 | 309 |
314 | |
315 // Worklist for register allocator. Always maintained sorted according | 310 // Worklist for register allocator. Always maintained sorted according |
316 // to ShouldBeAllocatedBefore predicate. | 311 // to ShouldBeAllocatedBefore predicate. |
317 GrowableArray<LiveRange*> unallocated_; | 312 GrowableArray<LiveRange*> unallocated_; |
318 | 313 |
319 // List of used spill slots. Contains positions after which spill slots | 314 // List of used spill slots. Contains positions after which spill slots |
320 // become free and can be reused for allocation. | 315 // become free and can be reused for allocation. |
321 GrowableArray<intptr_t> spill_slots_; | 316 GrowableArray<intptr_t> spill_slots_; |
322 | 317 |
323 // For every used spill slot contains a flag determines whether it is | 318 // For every used spill slot contains a flag determines whether it is |
324 // QuadSpillSlot to ensure that indexes of quad and double spill slots | 319 // QuadSpillSlot to ensure that indexes of quad and double spill slots |
325 // are disjoint. | 320 // are disjoint. |
326 GrowableArray<bool> quad_spill_slots_; | 321 GrowableArray<bool> quad_spill_slots_; |
327 | 322 |
328 // Track whether a spill slot is expected to hold a tagged or untagged value. | 323 // Track whether a spill slot is expected to hold a tagged or untagged value. |
329 // This is used to keep tagged and untagged spill slots disjoint. See bug | 324 // This is used to keep tagged and untagged spill slots disjoint. See bug |
330 // #18955 for details. | 325 // #18955 for details. |
331 GrowableArray<bool> untagged_spill_slots_; | 326 GrowableArray<bool> untagged_spill_slots_; |
332 | 327 |
333 intptr_t cpu_spill_slot_count_; | 328 intptr_t cpu_spill_slot_count_; |
334 | 329 |
335 const bool intrinsic_mode_; | 330 const bool intrinsic_mode_; |
336 | 331 |
337 DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator); | 332 DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator); |
338 }; | 333 }; |
339 | 334 |
340 | |
341 // Additional information about a block that is not contained in a | 335 // Additional information about a block that is not contained in a |
342 // block entry. | 336 // block entry. |
343 class BlockInfo : public ZoneAllocated { | 337 class BlockInfo : public ZoneAllocated { |
344 public: | 338 public: |
345 explicit BlockInfo(BlockEntryInstr* entry) | 339 explicit BlockInfo(BlockEntryInstr* entry) |
346 : entry_(entry), | 340 : entry_(entry), |
347 loop_(NULL), | 341 loop_(NULL), |
348 is_loop_header_(false), | 342 is_loop_header_(false), |
349 backedge_interference_(NULL) {} | 343 backedge_interference_(NULL) {} |
350 | 344 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 bool is_loop_header_; | 387 bool is_loop_header_; |
394 | 388 |
395 BlockEntryInstr* last_block_; | 389 BlockEntryInstr* last_block_; |
396 intptr_t loop_id_; | 390 intptr_t loop_id_; |
397 | 391 |
398 BitVector* backedge_interference_; | 392 BitVector* backedge_interference_; |
399 | 393 |
400 DISALLOW_COPY_AND_ASSIGN(BlockInfo); | 394 DISALLOW_COPY_AND_ASSIGN(BlockInfo); |
401 }; | 395 }; |
402 | 396 |
403 | |
404 // UsePosition represents a single use of an SSA value by some instruction. | 397 // UsePosition represents a single use of an SSA value by some instruction. |
405 // It points to a location slot which either tells register allocator | 398 // It points to a location slot which either tells register allocator |
406 // where instruction expects the value (if slot contains a fixed location) or | 399 // where instruction expects the value (if slot contains a fixed location) or |
407 // asks register allocator to allocate storage (register or spill slot) for | 400 // asks register allocator to allocate storage (register or spill slot) for |
408 // this use with certain properties (if slot contains an unallocated location). | 401 // this use with certain properties (if slot contains an unallocated location). |
409 class UsePosition : public ZoneAllocated { | 402 class UsePosition : public ZoneAllocated { |
410 public: | 403 public: |
411 UsePosition(intptr_t pos, UsePosition* next, Location* location_slot) | 404 UsePosition(intptr_t pos, UsePosition* next, Location* location_slot) |
412 : pos_(pos), location_slot_(location_slot), hint_(NULL), next_(next) { | 405 : pos_(pos), location_slot_(location_slot), hint_(NULL), next_(next) { |
413 ASSERT(location_slot != NULL); | 406 ASSERT(location_slot != NULL); |
414 } | 407 } |
415 | 408 |
416 Location* location_slot() const { return location_slot_; } | 409 Location* location_slot() const { return location_slot_; } |
417 void set_location_slot(Location* location_slot) { | 410 void set_location_slot(Location* location_slot) { |
418 location_slot_ = location_slot; | 411 location_slot_ = location_slot; |
419 } | 412 } |
420 | 413 |
421 Location hint() const { | 414 Location hint() const { |
422 ASSERT(HasHint()); | 415 ASSERT(HasHint()); |
423 return *hint_; | 416 return *hint_; |
424 } | 417 } |
425 | 418 |
426 void set_hint(Location* hint) { hint_ = hint; } | 419 void set_hint(Location* hint) { hint_ = hint; } |
427 | 420 |
428 bool HasHint() const { return (hint_ != NULL) && !hint_->IsUnallocated(); } | 421 bool HasHint() const { return (hint_ != NULL) && !hint_->IsUnallocated(); } |
429 | 422 |
430 | |
431 void set_next(UsePosition* next) { next_ = next; } | 423 void set_next(UsePosition* next) { next_ = next; } |
432 UsePosition* next() const { return next_; } | 424 UsePosition* next() const { return next_; } |
433 | 425 |
434 intptr_t pos() const { return pos_; } | 426 intptr_t pos() const { return pos_; } |
435 | 427 |
436 private: | 428 private: |
437 const intptr_t pos_; | 429 const intptr_t pos_; |
438 Location* location_slot_; | 430 Location* location_slot_; |
439 Location* hint_; | 431 Location* hint_; |
440 UsePosition* next_; | 432 UsePosition* next_; |
441 | 433 |
442 DISALLOW_COPY_AND_ASSIGN(UsePosition); | 434 DISALLOW_COPY_AND_ASSIGN(UsePosition); |
443 }; | 435 }; |
444 | 436 |
445 | |
446 // UseInterval represents a holeless half open interval of liveness for a given | 437 // UseInterval represents a holeless half open interval of liveness for a given |
447 // SSA value: [start, end) in terms of lifetime positions that | 438 // SSA value: [start, end) in terms of lifetime positions that |
448 // NumberInstructions assigns to instructions. Register allocator has to keep | 439 // NumberInstructions assigns to instructions. Register allocator has to keep |
449 // a value live in the register or in a spill slot from start position and until | 440 // a value live in the register or in a spill slot from start position and until |
450 // the end position. The interval can cover zero or more uses. | 441 // the end position. The interval can cover zero or more uses. |
451 // Note: currently all uses of the same SSA value are linked together into a | 442 // Note: currently all uses of the same SSA value are linked together into a |
452 // single list (and not split between UseIntervals). | 443 // single list (and not split between UseIntervals). |
453 class UseInterval : public ZoneAllocated { | 444 class UseInterval : public ZoneAllocated { |
454 public: | 445 public: |
455 UseInterval(intptr_t start, intptr_t end, UseInterval* next) | 446 UseInterval(intptr_t start, intptr_t end, UseInterval* next) |
(...skipping 16 matching lines...) Expand all Loading... |
472 private: | 463 private: |
473 friend class LiveRange; | 464 friend class LiveRange; |
474 | 465 |
475 intptr_t start_; | 466 intptr_t start_; |
476 intptr_t end_; | 467 intptr_t end_; |
477 UseInterval* next_; | 468 UseInterval* next_; |
478 | 469 |
479 DISALLOW_COPY_AND_ASSIGN(UseInterval); | 470 DISALLOW_COPY_AND_ASSIGN(UseInterval); |
480 }; | 471 }; |
481 | 472 |
482 | |
483 // AllocationFinger is used to keep track of currently active position | 473 // AllocationFinger is used to keep track of currently active position |
484 // for the register allocator and cache lookup results. | 474 // for the register allocator and cache lookup results. |
485 class AllocationFinger : public ValueObject { | 475 class AllocationFinger : public ValueObject { |
486 public: | 476 public: |
487 AllocationFinger() | 477 AllocationFinger() |
488 : first_pending_use_interval_(NULL), | 478 : first_pending_use_interval_(NULL), |
489 first_register_use_(NULL), | 479 first_register_use_(NULL), |
490 first_register_beneficial_use_(NULL), | 480 first_register_beneficial_use_(NULL), |
491 first_hinted_use_(NULL) {} | 481 first_hinted_use_(NULL) {} |
492 | 482 |
(...skipping 12 matching lines...) Expand all Loading... |
505 | 495 |
506 private: | 496 private: |
507 UseInterval* first_pending_use_interval_; | 497 UseInterval* first_pending_use_interval_; |
508 UsePosition* first_register_use_; | 498 UsePosition* first_register_use_; |
509 UsePosition* first_register_beneficial_use_; | 499 UsePosition* first_register_beneficial_use_; |
510 UsePosition* first_hinted_use_; | 500 UsePosition* first_hinted_use_; |
511 | 501 |
512 DISALLOW_COPY_AND_ASSIGN(AllocationFinger); | 502 DISALLOW_COPY_AND_ASSIGN(AllocationFinger); |
513 }; | 503 }; |
514 | 504 |
515 | |
516 class SafepointPosition : public ZoneAllocated { | 505 class SafepointPosition : public ZoneAllocated { |
517 public: | 506 public: |
518 SafepointPosition(intptr_t pos, LocationSummary* locs) | 507 SafepointPosition(intptr_t pos, LocationSummary* locs) |
519 : pos_(pos), locs_(locs), next_(NULL) {} | 508 : pos_(pos), locs_(locs), next_(NULL) {} |
520 | 509 |
521 void set_next(SafepointPosition* next) { next_ = next; } | 510 void set_next(SafepointPosition* next) { next_ = next; } |
522 SafepointPosition* next() const { return next_; } | 511 SafepointPosition* next() const { return next_; } |
523 | 512 |
524 intptr_t pos() const { return pos_; } | 513 intptr_t pos() const { return pos_; } |
525 | 514 |
526 LocationSummary* locs() const { return locs_; } | 515 LocationSummary* locs() const { return locs_; } |
527 | 516 |
528 private: | 517 private: |
529 const intptr_t pos_; | 518 const intptr_t pos_; |
530 LocationSummary* const locs_; | 519 LocationSummary* const locs_; |
531 | 520 |
532 SafepointPosition* next_; | 521 SafepointPosition* next_; |
533 }; | 522 }; |
534 | 523 |
535 | |
536 // LiveRange represents a sequence of UseIntervals for a given SSA value. | 524 // LiveRange represents a sequence of UseIntervals for a given SSA value. |
537 class LiveRange : public ZoneAllocated { | 525 class LiveRange : public ZoneAllocated { |
538 public: | 526 public: |
539 explicit LiveRange(intptr_t vreg, Representation rep) | 527 explicit LiveRange(intptr_t vreg, Representation rep) |
540 : vreg_(vreg), | 528 : vreg_(vreg), |
541 representation_(rep), | 529 representation_(rep), |
542 assigned_location_(), | 530 assigned_location_(), |
543 spill_slot_(), | 531 spill_slot_(), |
544 uses_(NULL), | 532 uses_(NULL), |
545 first_use_interval_(NULL), | 533 first_use_interval_(NULL), |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 LiveRange* next_sibling_; | 639 LiveRange* next_sibling_; |
652 | 640 |
653 intptr_t has_only_any_uses_in_loops_; | 641 intptr_t has_only_any_uses_in_loops_; |
654 bool is_loop_phi_; | 642 bool is_loop_phi_; |
655 | 643 |
656 AllocationFinger finger_; | 644 AllocationFinger finger_; |
657 | 645 |
658 DISALLOW_COPY_AND_ASSIGN(LiveRange); | 646 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
659 }; | 647 }; |
660 | 648 |
661 | |
662 } // namespace dart | 649 } // namespace dart |
663 | 650 |
664 #endif // RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ | 651 #endif // RUNTIME_VM_FLOW_GRAPH_ALLOCATOR_H_ |
OLD | NEW |