OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 VM_FLOW_GRAPH_ALLOCATOR_H_ | 5 #ifndef VM_FLOW_GRAPH_ALLOCATOR_H_ |
6 #define VM_FLOW_GRAPH_ALLOCATOR_H_ | 6 #define VM_FLOW_GRAPH_ALLOCATOR_H_ |
7 | 7 |
8 #include "vm/growable_array.h" | 8 #include "vm/growable_array.h" |
9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
10 | 10 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 // required to resolve data flow between split siblings when allocation | 69 // required to resolve data flow between split siblings when allocation |
70 // is finished. | 70 // is finished. |
71 // For specific examples see comments inside ProcessOneInstruction. | 71 // For specific examples see comments inside ProcessOneInstruction. |
72 // Additionally creates parallel moves at the joins' predecessors | 72 // Additionally creates parallel moves at the joins' predecessors |
73 // that will be used for phi resolution. | 73 // that will be used for phi resolution. |
74 void NumberInstructions(); | 74 void NumberInstructions(); |
75 Instruction* InstructionAt(intptr_t pos) const; | 75 Instruction* InstructionAt(intptr_t pos) const; |
76 bool IsBlockEntry(intptr_t pos) const; | 76 bool IsBlockEntry(intptr_t pos) const; |
77 | 77 |
78 LiveRange* GetLiveRange(intptr_t vreg); | 78 LiveRange* GetLiveRange(intptr_t vreg); |
| 79 LiveRange* MakeLiveRangeForTemporary(); |
79 | 80 |
80 // Visit instructions in the postorder and build live ranges for | 81 // Visit instructions in the postorder and build live ranges for |
81 // all SSA values. | 82 // all SSA values. |
82 void BuildLiveRanges(); | 83 void BuildLiveRanges(); |
83 Instruction* ConnectOutgoingPhiMoves(BlockEntryInstr* block); | 84 Instruction* ConnectOutgoingPhiMoves(BlockEntryInstr* block); |
84 void ProcessOneInstruction(BlockEntryInstr* block, Instruction* instr); | 85 void ProcessOneInstruction(BlockEntryInstr* block, Instruction* instr); |
85 void ConnectIncomingPhiMoves(BlockEntryInstr* block); | 86 void ConnectIncomingPhiMoves(BlockEntryInstr* block); |
86 void BlockLocation(Location loc, intptr_t pos); | 87 void BlockLocation(Location loc, intptr_t pos); |
87 | 88 |
88 // Process live ranges sorted by their start and assign registers | 89 // Process live ranges sorted by their start and assign registers |
89 // to them | 90 // to them |
90 void AllocateCPURegisters(); | 91 void AllocateCPURegisters(); |
91 void AdvanceActiveIntervals(const intptr_t start); | 92 void AdvanceActiveIntervals(const intptr_t start); |
92 | 93 |
93 // Connect split siblings over non-linear control flow edges. | 94 // Connect split siblings over non-linear control flow edges. |
94 void ResolveControlFlow(); | 95 void ResolveControlFlow(); |
95 void ConnectSplitSiblings(LiveRange* range, | 96 void ConnectSplitSiblings(LiveRange* range, |
96 BlockEntryInstr* source_block, | 97 BlockEntryInstr* source_block, |
97 BlockEntryInstr* target_block); | 98 BlockEntryInstr* target_block); |
98 | 99 |
99 | 100 |
100 // Update location slot corresponding to the use with location allocated for | 101 // Update location slot corresponding to the use with location allocated for |
101 // the use's live range. | 102 // the use's live range. |
102 void ConvertUseTo(UsePosition* use, Location loc); | 103 void ConvertUseTo(UsePosition* use, Location loc); |
103 void ConvertAllUses(LiveRange* range); | 104 void ConvertAllUses(LiveRange* range); |
104 | 105 |
105 // Add live range to the list of unallocated live ranges to be processed | 106 // Add live range to the list of unallocated live ranges to be processed |
106 // by the allocator. | 107 // by the allocator. |
107 void AddToUnallocated(LiveRange* range); | 108 void AddToUnallocated(LiveRange* range); |
108 #ifdef DEBUG | 109 #if defined(DEBUG) |
109 bool UnallocatedIsSorted(); | 110 bool UnallocatedIsSorted(); |
110 #endif | 111 #endif |
111 | 112 |
112 // Try to find a free register for an unallocated live range. | 113 // Try to find a free register for an unallocated live range. |
113 bool AllocateFreeRegister(LiveRange* unallocated); | 114 bool AllocateFreeRegister(LiveRange* unallocated); |
114 | 115 |
115 // Try to find a register that can be used by a given live range. | 116 // Try to find a register that can be used by a given live range. |
116 // If all registers are occupied consider evicting interference for | 117 // If all registers are occupied consider evicting interference for |
117 // a register that is going to be used as far from the start of | 118 // a register that is going to be used as far from the start of |
118 // the unallocated live range as possible. | 119 // the unallocated live range as possible. |
(...skipping 14 matching lines...) Expand all Loading... |
133 | 134 |
134 bool UpdateFreeUntil(Register reg, | 135 bool UpdateFreeUntil(Register reg, |
135 LiveRange* unallocated, | 136 LiveRange* unallocated, |
136 intptr_t* cur_free_until, | 137 intptr_t* cur_free_until, |
137 intptr_t* cur_blocked_at); | 138 intptr_t* cur_blocked_at); |
138 | 139 |
139 // Split given live range in an optimal position between given positions. | 140 // Split given live range in an optimal position between given positions. |
140 LiveRange* SplitBetween(LiveRange* range, intptr_t from, intptr_t to); | 141 LiveRange* SplitBetween(LiveRange* range, intptr_t from, intptr_t to); |
141 | 142 |
142 // Find a spill slot that can be used by the given live range. | 143 // Find a spill slot that can be used by the given live range. |
143 intptr_t AllocateSpillSlotFor(LiveRange* range); | 144 void AllocateSpillSlotFor(LiveRange* range); |
144 | 145 |
145 // Allocate the given live range to a spill slot. | 146 // Allocate the given live range to a spill slot. |
146 void Spill(LiveRange* range); | 147 void Spill(LiveRange* range); |
147 | 148 |
148 // Spill the given live range from the given position onwards. | 149 // Spill the given live range from the given position onwards. |
149 void SpillAfter(LiveRange* range, intptr_t from); | 150 void SpillAfter(LiveRange* range, intptr_t from); |
150 | 151 |
151 // Spill the given live range from the given position until some | 152 // Spill the given live range from the given position until some |
152 // position preceeding the to position. | 153 // position preceeding the to position. |
153 void SpillBetween(LiveRange* range, intptr_t from, intptr_t to); | 154 void SpillBetween(LiveRange* range, intptr_t from, intptr_t to); |
(...skipping 29 matching lines...) Expand all Loading... |
183 // SSA values. | 184 // SSA values. |
184 const intptr_t vreg_count_; | 185 const intptr_t vreg_count_; |
185 | 186 |
186 // LiveRanges corresponding to SSA values. | 187 // LiveRanges corresponding to SSA values. |
187 GrowableArray<LiveRange*> live_ranges_; | 188 GrowableArray<LiveRange*> live_ranges_; |
188 | 189 |
189 // Worklist for register allocator. Always maintained sorted according | 190 // Worklist for register allocator. Always maintained sorted according |
190 // to ShouldBeAllocatedBefore predicate. | 191 // to ShouldBeAllocatedBefore predicate. |
191 GrowableArray<LiveRange*> unallocated_; | 192 GrowableArray<LiveRange*> unallocated_; |
192 | 193 |
| 194 #if defined(DEBUG) |
| 195 GrowableArray<LiveRange*> temporaries_; |
| 196 #endif |
| 197 |
| 198 GrowableArray<LiveRange*> spilled_; |
| 199 |
193 // Per register lists of allocated live ranges. Contain only those | 200 // Per register lists of allocated live ranges. Contain only those |
194 // ranges that can be affected by future allocation decisions. | 201 // ranges that can be affected by future allocation decisions. |
195 // Those live ranges that end before the start of the current live range are | 202 // Those live ranges that end before the start of the current live range are |
196 // removed from the list and will not be affected. | 203 // removed from the list and will not be affected. |
197 GrowableArray<LiveRange*> cpu_regs_[kNumberOfCpuRegisters]; | 204 GrowableArray<LiveRange*> cpu_regs_[kNumberOfCpuRegisters]; |
198 | 205 |
199 // List of used spill slots. Contain positions after which spill slots | 206 // List of used spill slots. Contain positions after which spill slots |
200 // become free and can be reused for allocation. | 207 // become free and can be reused for allocation. |
201 GrowableArray<intptr_t> spill_slots_; | 208 GrowableArray<intptr_t> spill_slots_; |
202 | 209 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 DISALLOW_COPY_AND_ASSIGN(AllocationFinger); | 321 DISALLOW_COPY_AND_ASSIGN(AllocationFinger); |
315 }; | 322 }; |
316 | 323 |
317 | 324 |
318 // LiveRange represents a sequence of UseIntervals for a given SSA value. | 325 // LiveRange represents a sequence of UseIntervals for a given SSA value. |
319 class LiveRange : public ZoneAllocated { | 326 class LiveRange : public ZoneAllocated { |
320 public: | 327 public: |
321 explicit LiveRange(intptr_t vreg) | 328 explicit LiveRange(intptr_t vreg) |
322 : vreg_(vreg), | 329 : vreg_(vreg), |
323 assigned_location_(), | 330 assigned_location_(), |
| 331 spill_slot_(), |
324 uses_(NULL), | 332 uses_(NULL), |
325 first_use_interval_(NULL), | 333 first_use_interval_(NULL), |
326 last_use_interval_(NULL), | 334 last_use_interval_(NULL), |
327 next_sibling_(NULL), | 335 next_sibling_(NULL), |
328 finger_() { | 336 finger_() { |
329 } | 337 } |
330 | 338 |
331 static LiveRange* MakeTemp(intptr_t pos, Location* location_slot); | 339 static LiveRange* MakeTemp(intptr_t pos, Location* location_slot); |
332 | 340 |
333 intptr_t vreg() const { return vreg_; } | 341 intptr_t vreg() const { return vreg_; } |
334 LiveRange* next_sibling() const { return next_sibling_; } | 342 LiveRange* next_sibling() const { return next_sibling_; } |
335 UsePosition* first_use() const { return uses_; } | 343 UsePosition* first_use() const { return uses_; } |
336 void set_first_use(UsePosition* use) { uses_ = use; } | 344 void set_first_use(UsePosition* use) { uses_ = use; } |
337 UseInterval* first_use_interval() const { return first_use_interval_; } | 345 UseInterval* first_use_interval() const { return first_use_interval_; } |
338 UseInterval* last_use_interval() const { return last_use_interval_; } | 346 UseInterval* last_use_interval() const { return last_use_interval_; } |
339 Location assigned_location() const { return assigned_location_; } | 347 Location assigned_location() const { return assigned_location_; } |
340 intptr_t Start() const { return first_use_interval()->start(); } | 348 intptr_t Start() const { return first_use_interval()->start(); } |
341 intptr_t End() const { return last_use_interval()->end(); } | 349 intptr_t End() const { return last_use_interval()->end(); } |
342 | 350 |
343 AllocationFinger* finger() { return &finger_; } | 351 AllocationFinger* finger() { return &finger_; } |
344 | 352 |
345 void set_assigned_location(Location location) { | 353 void set_assigned_location(Location location) { |
346 assigned_location_ = location; | 354 assigned_location_ = location; |
347 } | 355 } |
348 | 356 |
| 357 void set_spill_slot(Location spill_slot) { |
| 358 spill_slot_ = spill_slot; |
| 359 } |
| 360 |
349 void DefineAt(intptr_t pos); | 361 void DefineAt(intptr_t pos); |
350 | 362 |
351 void AddUse(intptr_t pos, Location* location_slot); | 363 void AddUse(intptr_t pos, Location* location_slot); |
352 void AddUseInterval(intptr_t start, intptr_t end); | 364 void AddUseInterval(intptr_t start, intptr_t end); |
353 | 365 |
354 void Print(); | 366 void Print(); |
355 | 367 |
356 void AssignLocation(UseInterval* use, Location loc); | 368 void AssignLocation(UseInterval* use, Location loc); |
357 | 369 |
358 LiveRange* SplitAt(intptr_t pos); | 370 LiveRange* SplitAt(intptr_t pos); |
359 | 371 |
360 bool CanCover(intptr_t pos) const { | 372 bool CanCover(intptr_t pos) const { |
361 return (Start() <= pos) && (pos < End()); | 373 return (Start() <= pos) && (pos < End()); |
362 } | 374 } |
363 | 375 |
| 376 Location spill_slot() const { |
| 377 return spill_slot_; |
| 378 } |
| 379 |
364 private: | 380 private: |
365 LiveRange(intptr_t vreg, | 381 LiveRange(intptr_t vreg, |
366 UsePosition* uses, | 382 UsePosition* uses, |
367 UseInterval* first_use_interval, | 383 UseInterval* first_use_interval, |
368 UseInterval* last_use_interval, | 384 UseInterval* last_use_interval, |
369 LiveRange* next_sibling) | 385 LiveRange* next_sibling) |
370 : vreg_(vreg), | 386 : vreg_(vreg), |
371 assigned_location_(), | 387 assigned_location_(), |
372 uses_(uses), | 388 uses_(uses), |
373 first_use_interval_(first_use_interval), | 389 first_use_interval_(first_use_interval), |
374 last_use_interval_(last_use_interval), | 390 last_use_interval_(last_use_interval), |
375 next_sibling_(next_sibling), | 391 next_sibling_(next_sibling), |
376 finger_() { | 392 finger_() { |
377 } | 393 } |
378 | 394 |
379 const intptr_t vreg_; | 395 const intptr_t vreg_; |
380 Location assigned_location_; | 396 Location assigned_location_; |
| 397 Location spill_slot_; |
381 | 398 |
382 UsePosition* uses_; | 399 UsePosition* uses_; |
383 UseInterval* first_use_interval_; | 400 UseInterval* first_use_interval_; |
384 UseInterval* last_use_interval_; | 401 UseInterval* last_use_interval_; |
385 | 402 |
386 LiveRange* next_sibling_; | 403 LiveRange* next_sibling_; |
387 | 404 |
388 AllocationFinger finger_; | 405 AllocationFinger finger_; |
389 | 406 |
390 DISALLOW_COPY_AND_ASSIGN(LiveRange); | 407 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
391 }; | 408 }; |
392 | 409 |
393 | 410 |
394 } // namespace dart | 411 } // namespace dart |
395 | 412 |
396 #endif // VM_FLOW_GRAPH_ALLOCATOR_H_ | 413 #endif // VM_FLOW_GRAPH_ALLOCATOR_H_ |
OLD | NEW |