Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: runtime/vm/flow_graph_allocator.cc

Issue 10696151: Skeleton of a linear scan register allocator. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #include "vm/flow_graph_allocator.h" 5 #include "vm/flow_graph_allocator.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 #include "vm/il_printer.h"
10 #include "vm/flow_graph_builder.h"
9 #include "vm/flow_graph_compiler.h" 11 #include "vm/flow_graph_compiler.h"
10 12
11 namespace dart { 13 namespace dart {
12 14
13 DEFINE_FLAG(bool, print_ssa_liveness, false, 15 DEFINE_FLAG(bool, print_ssa_liveness, false,
14 "Print liveness for ssa variables."); 16 "Print liveness for ssa variables.");
17 DEFINE_FLAG(bool, trace_ssa_allocator, false,
18 "Trace register allocation over SSA.");
19
20 #ifdef DEBUG
21 #define TRACE_ALLOC(m) do { \
22 if (FLAG_trace_ssa_allocator) OS::Print m ; \
23 } while (0)
24 #else
25 #define TRACE_ALLOC(m)
26 #endif
15 27
16 FlowGraphAllocator::FlowGraphAllocator( 28 FlowGraphAllocator::FlowGraphAllocator(
17 const GrowableArray<BlockEntryInstr*>& postorder, 29 const GrowableArray<BlockEntryInstr*>& block_order,
18 intptr_t max_ssa_temp_index) 30 FlowGraphBuilder* builder)
19 : live_out_(postorder.length()), 31 : builder_(builder),
20 kill_(postorder.length()), 32 block_order_(block_order),
21 live_in_(postorder.length()), 33 postorder_(builder->postorder_block_entries()),
22 postorder_(postorder), 34 live_out_(block_order.length()),
23 vreg_count_(max_ssa_temp_index) { 35 kill_(block_order.length()),
36 live_in_(block_order.length()),
37 vreg_count_(builder->current_ssa_temp_index()),
38 live_ranges_(builder->current_ssa_temp_index()) {
39 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL);
srdjan 2012/07/11 17:22:32 Initialize cpu_regs_ elements to NULL
24 } 40 }
25 41
26 42
27 void FlowGraphAllocator::ResolveConstraints() {
28 // TODO(fschneider): Resolve register constraints.
29 }
30
31
32 void FlowGraphAllocator::ComputeInitialSets() { 43 void FlowGraphAllocator::ComputeInitialSets() {
33 const intptr_t block_count = postorder_.length(); 44 const intptr_t block_count = postorder_.length();
34 for (intptr_t i = 0; i < block_count; i++) { 45 for (intptr_t i = 0; i < block_count; i++) {
35 BlockEntryInstr* block = postorder_[i]; 46 BlockEntryInstr* block = postorder_[i];
36 47
37 BitVector* kill = kill_[i]; 48 BitVector* kill = kill_[i];
38 BitVector* live_in = live_in_[i]; 49 BitVector* live_in = live_in_[i];
39 50
40 if (block->IsJoinEntry()) { 51 if (block->IsJoinEntry()) {
41 JoinEntryInstr* join = block->AsJoinEntry(); 52 JoinEntryInstr* join = block->AsJoinEntry();
(...skipping 19 matching lines...) Expand all
61 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 72 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
62 Instruction* current = it.Current(); 73 Instruction* current = it.Current();
63 for (intptr_t j = 0; j < current->InputCount(); j++) { 74 for (intptr_t j = 0; j < current->InputCount(); j++) {
64 Value* input = current->InputAt(j); 75 Value* input = current->InputAt(j);
65 if (input->IsUse()) { 76 if (input->IsUse()) {
66 const intptr_t use = input->AsUse()->definition()->ssa_temp_index(); 77 const intptr_t use = input->AsUse()->definition()->ssa_temp_index();
67 if (!kill->Contains(use)) live_in->Add(use); 78 if (!kill->Contains(use)) live_in->Add(use);
68 } 79 }
69 } 80 }
70 81
82 // Add uses from the deoptimization environment.
83 if (current->env() != NULL) {
84 const ZoneGrowableArray<Value*>& values = current->env()->values();
85 for (intptr_t j = 0; j < values.length(); j++) {
86 Value* val = values[j];
87 if (val->IsUse()) {
88 const intptr_t use = val->AsUse()->definition()->ssa_temp_index();
89 if (!kill->Contains(use)) live_in->Add(use);
90 }
91 }
92 }
93
71 Definition* current_def = current->AsDefinition(); 94 Definition* current_def = current->AsDefinition();
72 if ((current_def != NULL) && (current_def->ssa_temp_index() >= 0)) { 95 if ((current_def != NULL) && (current_def->ssa_temp_index() >= 0)) {
73 kill->Add(current_def->ssa_temp_index()); 96 kill->Add(current_def->ssa_temp_index());
74 } 97 }
75 } 98 }
76 } 99 }
77 100
78 // Update initial live_in sets to match live_out sets. Has to be 101 // Update initial live_in sets to match live_out sets. Has to be
79 // done in a separate path because of backwards branches. 102 // done in a separate path because of backwards branches.
80 for (intptr_t i = 0; i < block_count; i++) { 103 for (intptr_t i = 0; i < block_count; i++) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 void FlowGraphAllocator::AnalyzeLiveness() { 154 void FlowGraphAllocator::AnalyzeLiveness() {
132 const intptr_t block_count = postorder_.length(); 155 const intptr_t block_count = postorder_.length();
133 for (intptr_t i = 0; i < block_count; i++) { 156 for (intptr_t i = 0; i < block_count; i++) {
134 live_out_.Add(new BitVector(vreg_count_)); 157 live_out_.Add(new BitVector(vreg_count_));
135 kill_.Add(new BitVector(vreg_count_)); 158 kill_.Add(new BitVector(vreg_count_));
136 live_in_.Add(new BitVector(vreg_count_)); 159 live_in_.Add(new BitVector(vreg_count_));
137 } 160 }
138 161
139 ComputeInitialSets(); 162 ComputeInitialSets();
140 ComputeLiveInAndLiveOutSets(); 163 ComputeLiveInAndLiveOutSets();
141
142 if (FLAG_print_ssa_liveness) {
143 DumpLiveness();
144 }
145 } 164 }
146 165
147 166
148 static void PrintBitVector(const char* tag, BitVector* v) { 167 static void PrintBitVector(const char* tag, BitVector* v) {
149 OS::Print("%s:", tag); 168 OS::Print("%s:", tag);
150 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) { 169 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) {
151 OS::Print(" %d", it.Current()); 170 OS::Print(" %d", it.Current());
152 } 171 }
153 OS::Print("\n"); 172 OS::Print("\n");
154 } 173 }
(...skipping 12 matching lines...) Expand all
167 } 186 }
168 OS::Print("\n"); 187 OS::Print("\n");
169 188
170 PrintBitVector(" live out", live_out_[i]); 189 PrintBitVector(" live out", live_out_[i]);
171 PrintBitVector(" kill", kill_[i]); 190 PrintBitVector(" kill", kill_[i]);
172 PrintBitVector(" live in", live_in_[i]); 191 PrintBitVector(" live in", live_in_[i]);
173 } 192 }
174 } 193 }
175 194
176 195
196 void UseInterval::Print() {
197 OS::Print(" [%d, %d) uses {", start_, end_);
198 for (UsePosition* use_pos = uses_;
199 use_pos != NULL && use_pos->pos() <= end();
200 use_pos = use_pos->next()) {
201 if (use_pos != uses_) OS::Print(", ");
202 OS::Print("%d", use_pos->pos());
203 }
204 OS::Print("}\n");
205 }
206
207
208 void UseInterval::AddUse(Instruction* instr,
209 intptr_t pos,
210 Location* location_slot) {
211 ASSERT((start_ <= pos) && (pos <= end_));
212 ASSERT((instr == NULL) || (instr->lifetime_position() == pos));
213 if ((uses_ != NULL) && (uses_->pos() == pos)) {
214 if ((location_slot == NULL) || (uses_->location_slot() == location_slot)) {
215 return;
216 } else if ((uses_->location_slot() == NULL) && (instr == NULL)) {
217 uses_->set_location_slot(location_slot);
218 return;
219 }
220 }
221 uses_ = new UsePosition(instr, pos, uses_, location_slot);
222 }
223
224
225 void LiveRange::Print() {
226 OS::Print("vreg %d live intervals:\n", vreg_);
227 for (UseInterval* interval = head_;
228 interval != NULL;
229 interval = interval->next_) {
230 interval->Print();
231 }
232 }
233
234
235 void LiveRange::AddUseInterval(intptr_t start, intptr_t end) {
236 if ((head_ != NULL) && (head_->start_ == end)) {
237 head_->start_ = start;
238 return;
239 }
240
241 head_ = new UseInterval(vreg_, start, end, head_);
242 }
243
244
245 void LiveRange::DefineAt(Instruction* instr, intptr_t pos, Location* loc) {
246 if (head_ != NULL) {
247 ASSERT(head_->start_ <= pos);
248 head_->start_ = pos;
249 } else {
250 // Definition without a use.
251 head_ = new UseInterval(vreg_, pos, pos + 1, NULL);
252 }
253 head_->AddUse(instr, pos, loc);
254 }
255
256
257 // TODO(vegorov): encode use_at_start vs. use_at_end in the location itself?
258 void LiveRange::UseAt(Instruction* instr,
259 intptr_t def, intptr_t use,
260 bool use_at_end,
261 Location* loc) {
262 if (head_ == NULL || head_->start_ != def) {
263 AddUseInterval(def, use + (use_at_end ? 1 : 0));
264 }
265 head_->AddUse(instr, use, loc);
266 }
267
268
269 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) {
270 if (live_ranges_[vreg] == NULL) {
271 live_ranges_[vreg] = new LiveRange(vreg);
272 }
273 return live_ranges_[vreg];
274 }
275
276
277 static const intptr_t kNoVirtualRegister = -1;
278 static const intptr_t kTempVirtualRegister = -2;
279 static UseInterval* const kPermanentlyBlocked =
280 reinterpret_cast<UseInterval*>(-1);
281 static const intptr_t kIllegalPosition = -1;
282 static const intptr_t kMaxPosition = 0x7FFFFFFF;
283
284
285 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) {
286 ASSERT(loc.IsRegister());
287 const Register reg = loc.reg();
288 UseInterval* last = cpu_regs_[reg];
289 if (last == kPermanentlyBlocked) return;
290 if ((last != NULL) && (last->start() == pos)) return;
291 cpu_regs_[reg] = new UseInterval(kNoVirtualRegister, pos, pos + 1, last);
292 }
293
294
295 void FlowGraphAllocator::Define(Instruction* instr,
296 intptr_t pos,
297 intptr_t vreg,
298 Location* loc) {
299 LiveRange* range = GetLiveRange(vreg);
300 ASSERT(loc != NULL);
301 if (loc->IsRegister()) {
302 BlockLocation(*loc, pos);
303 range->DefineAt(instr, pos + 1, loc);
304 } else if (loc->IsUnallocated()) {
305 range->DefineAt(instr, pos, loc);
306 } else {
307 UNREACHABLE();
308 }
309
310 AddToUnallocated(range->head());
311 }
312
313
314 void FlowGraphAllocator::UseValue(Instruction* instr,
315 intptr_t def_pos,
316 intptr_t use_pos,
317 intptr_t vreg,
318 Location* loc,
319 bool use_at_end) {
320 LiveRange* range = GetLiveRange(vreg);
321 if (loc == NULL) {
322 range->UseAt(NULL, def_pos, use_pos, true, loc);
323 } else if (loc->IsRegister()) {
324 // We have a fixed use.
325 BlockLocation(*loc, use_pos);
326 range->UseAt(instr, def_pos, use_pos, false, loc);
327 } else if (loc->IsUnallocated()) {
328 ASSERT(loc->policy() == Location::kRequiresRegister);
329 range->UseAt(use_at_end ? NULL : instr, def_pos, use_pos, use_at_end, loc);
330 }
331 }
332
333
334 static void PrintChain(UseInterval* chain) {
335 if (chain == kPermanentlyBlocked) {
336 OS::Print(" not for allocation\n");
337 return;
338 }
339
340 while (chain != NULL) {
341 chain->Print();
342 chain = chain->next();
343 }
344 }
345
346
347 void FlowGraphAllocator::PrintLiveRanges() {
348 for (intptr_t i = 0; i < unallocated_.length(); i++) {
349 OS::Print("unallocated chain for vr%d\n", unallocated_[i]->vreg());
350 PrintChain(unallocated_[i]);
351 }
352
353 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
354 OS::Print("blocking chain for %s\n",
355 Location::RegisterLocation(static_cast<Register>(reg)).Name());
356 PrintChain(cpu_regs_[reg]);
357 }
358 }
359
360
361 void FlowGraphAllocator::BuildLiveRanges() {
362 NumberInstructions();
363
364 const intptr_t block_count = postorder_.length();
365 for (intptr_t i = 0; i < block_count; i++) {
366 BlockEntryInstr* block = postorder_[i];
367
368 // For every SSA value that is live out of this block create an interval
369 // that covers the hole block. It will be shortened if we encounter a
370 // definition of this value in this block.
371 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) {
372 LiveRange* range = GetLiveRange(it.Current());
373 range->AddUseInterval(block->start_pos(), block->end_pos());
374 }
375
376 // Position corresponding to the end of the last instruction in the block.
377 intptr_t pos = block->end_pos() - 1;
378
379 Instruction* current = block->last_instruction();
380
381 // If last instruction is a parallel move we need to perform phi resolution.
382 if (current->IsParallelMove()) {
383 ParallelMoveInstr* parallel_move = current->AsParallelMove();
384 JoinEntryInstr* join = current->next()->AsJoinEntry();
385 ASSERT(join != NULL);
386
387 // Find index of the current block in predecessors of join.
388 intptr_t pred_idx = -1;
389 for (intptr_t j = 0; j < join->PredecessorCount(); j++) {
390 BlockEntryInstr* pred = join->PredecessorAt(j);
391 if (pred == block) {
392 pred_idx = j;
393 break;
394 }
395 }
396 ASSERT(pred_idx != -1);
397
398 // For every phi we have a reserved phi resolution move and we need
399 // to either initialize its source with constant or to register a use, so
400 // that register allocator will populate source slot with location of
401 // the appropriate SSA value.
402 ZoneGrowableArray<PhiInstr*>* phis = join->phis();
403 intptr_t move_idx = 0;
404 for (intptr_t j = 0; j < phis->length(); j++) {
405 PhiInstr* phi = (*phis)[j];
406 if (phi == NULL) continue;
407
408 Value* val = phi->InputAt(pred_idx);
409
410 MoveOperands move = parallel_move->moves()[move_idx];
411 if (val->IsUse()) {
412 const intptr_t use = val->AsUse()->definition()->ssa_temp_index();
413 Location* slot = move.src_slot();
414 *slot = Location::RequiresRegister();
415 GetLiveRange(use)->head()->AddUse(NULL, pos, slot);
416 } else {
417 ASSERT(val->IsConstant());
418 move.set_src(Location::Constant(val->AsConstant()->value()));
419 }
420
421 move_idx++;
422 }
423
424 current = current->previous();
425 }
426
427 // Now process all instructions in reverse order.
428 // Advance position to the start of the last instruction in the block.
429 pos -= 1;
430 while (current != block) {
431 LocationSummary* locs = current->locs();
432
433 const bool output_same_as_first_input =
434 locs->out().IsUnallocated() &&
435 locs->out().policy() == Location::kSameAsFirstInput;
436
437 // TODO(vegorov): number of inputs should match number of input locations.
438 // TODO(vegorov): generic support for writable registers?
439 for (intptr_t j = 0; j < current->InputCount(); j++) {
440 Value* input = current->InputAt(j);
441 if (input->IsUse()) {
442 const intptr_t use = input->AsUse()->definition()->ssa_temp_index();
443
444 Location* in_ref = (j < locs->input_count()) ?
445 locs->in_slot(j) : NULL;
446 const bool use_at_end = (j > 0) || (in_ref == NULL) ||
447 !output_same_as_first_input;
448 UseValue(current, block->start_pos(), pos, use, in_ref, use_at_end);
449 }
450 }
451
452 // Add uses from the deoptimization environment.
453 // TODO(vegorov): these uses should _not_ require register but for now
454 // they do because we don't support spilling at all.
455 if (current->env() != NULL) {
456 const ZoneGrowableArray<Value*>& values = current->env()->values();
457 GrowableArray<Location>* locations = current->env()->locations();
458
459 for (intptr_t j = 0; j < values.length(); j++) {
460 Value* val = values[j];
461 if (val->IsUse()) {
462 locations->Add(Location::RequiresRegister());
463 const intptr_t use = val->AsUse()->definition()->ssa_temp_index();
464 UseValue(current,
465 block->start_pos(),
466 pos,
467 use,
468 &(*locations)[j],
469 true);
470 } else {
471 locations->Add(Location::NoLocation());
472 }
473 }
474 }
475
476 // Process temps.
477 for (intptr_t j = 0; j < locs->temp_count(); j++) {
478 Location temp = locs->temp(j);
479 if (temp.IsRegister()) {
480 BlockLocation(temp, pos);
481 } else if (temp.IsUnallocated()) {
482 UseInterval* temp_interval = new UseInterval(
483 kTempVirtualRegister, pos, pos + 1, NULL);
484 temp_interval->AddUse(NULL, pos, locs->temp_slot(j));
485 AddToUnallocated(temp_interval);
486 } else {
487 UNREACHABLE();
488 }
489 }
490
491 // Block all allocatable registers for calls.
492 if (locs->is_call()) {
493 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
494 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)),
495 pos);
496 }
497 }
498
499 if (locs->out().IsRegister()) {
500 builder_->Bailout("ssa allocator: fixed outputs are not supported");
501 }
502
503 Definition* def = current->AsDefinition();
504 if ((def != NULL) && (def->ssa_temp_index() >= 0)) {
505 Define(output_same_as_first_input ? current : NULL,
506 pos,
507 def->ssa_temp_index(),
508 locs->out_slot());
509 }
510
511 current = current->previous();
512 pos -= 2;
513 }
514
515 // If this block is a join we need to add destinations of phi
516 // resolution moves to phi's live range so that register allocator will
517 // fill them with moves.
518 if (block->IsJoinEntry() && block->AsJoinEntry()->phis() != NULL) {
519 ZoneGrowableArray<PhiInstr*>* phis = block->AsJoinEntry()->phis();
520
521 intptr_t move_idx = 0;
522 for (intptr_t j = 0; j < phis->length(); j++) {
523 PhiInstr* phi = (*phis)[j];
524 if (phi == NULL) continue;
525
526 const intptr_t def = phi->ssa_temp_index();
527 ASSERT(def != -1);
528
529 LiveRange* range = GetLiveRange(def);
530 range->DefineAt(NULL, pos, NULL);
531 UseInterval* interval = GetLiveRange(def)->head();
532
533 for (intptr_t k = 0; k < phi->InputCount(); k++) {
534 BlockEntryInstr* pred = block->PredecessorAt(k);
535 ASSERT(pred->last_instruction()->IsParallelMove());
536
537 Location* slot = pred->last_instruction()->AsParallelMove()->
538 moves()[move_idx].dest_slot();
539 *slot = Location::RequiresRegister();
540 interval->AddUse(NULL, pos, slot);
541 }
542
543 // All phi resolution moves are connected. Phi's live range is complete.
544 AddToUnallocated(interval);
545
546 move_idx++;
547 }
548 }
549 }
550 }
551
552
553 void FlowGraphAllocator::NumberInstructions() {
554 intptr_t pos = 0;
555
556 const intptr_t block_count = postorder_.length();
557 for (intptr_t i = block_count - 1; i >= 0; i--) {
558 BlockEntryInstr* block = postorder_[i];
559
560 block->set_start_pos(pos);
561 pos += 2;
562 Instruction* current = block->next();
563
564 Instruction* last = block->last_instruction();
565 if (!last->IsParallelMove()) last = last->next();
566
567 while (current != last) {
568 current->set_lifetime_position(pos);
569 current = current->next();
570 pos += 2;
571 }
572 block->set_end_pos(pos);
573
574 // For join entry predecessors create phi resolution moves if
575 // necessary. They will be populated by the register allocator.
576 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) {
577 const intptr_t phi_count = block->AsJoinEntry()->phi_count();
578 for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
579 BlockEntryInstr* pred = block->PredecessorAt(i);
580 ASSERT(!pred->last_instruction()->IsParallelMove());
581
582 ParallelMoveInstr* move = new ParallelMoveInstr();
583 move->set_next(block);
584 move->set_previous(pred->last_instruction());
585 pred->last_instruction()->set_next(move);
586 pred->set_last_instruction(move);
587
588 // Populate ParallelMove with empty moves.
589 for (intptr_t j = 0; j < phi_count; j++) {
590 move->AddMove(Location::NoLocation(), Location::NoLocation());
591 }
592 }
593 }
594 }
595 }
596
597
598 intptr_t UseInterval::Intersect(UseInterval* other) {
599 if (this->start() <= other->start()) {
600 if (other->start() < this->end()) return other->start();
601 } else if (this->start() < other->end()) {
602 return this->start();
603 }
604 return kIllegalPosition;
605 }
606
607
608 static intptr_t FirstIntersection(UseInterval* a, UseInterval* u) {
609 while (a != NULL && u != NULL) {
610 const intptr_t pos = a->Intersect(u);
611 if (pos != kIllegalPosition) return pos;
612
613 if (a->start() < u->start()) {
614 a = a->next_allocated();
615 } else {
616 u = u->next();
617 }
618 }
619
620 return kMaxPosition;
621 }
622
623
624 static Location LookAheadForHint(UseInterval* interval) {
625 UsePosition* use = interval->first_use();
626
627 while (use != NULL) {
628 if (use->HasHint()) return use->hint();
629 use = use->next();
630 }
631
632 return Location::NoLocation();
633 }
634
635
636 bool FlowGraphAllocator::AllocateFreeRegister(UseInterval* unallocated) {
637 Register candidate = kNoRegister;
638 intptr_t free_until = 0;
639
640 // If hint is available try hint first.
641 // TODO(vegorov): ensure that phis are hinted on the backedge.
642 Location hint = LookAheadForHint(unallocated);
643 if (!hint.IsInvalid()) {
644 ASSERT(hint.IsRegister());
645
646 if (cpu_regs_[hint.reg()] != kPermanentlyBlocked) {
647 free_until = FirstIntersection(cpu_regs_[hint.reg()], unallocated);
648 candidate = hint.reg();
649 }
650
651 TRACE_ALLOC(("found hint %s for %d: free until %d\n",
652 hint.Name(), unallocated->vreg(), free_until));
653 }
654
655 if (free_until != kMaxPosition) {
656 for (int reg = 0; reg < kNumberOfCpuRegisters; ++reg) {
657 if (cpu_regs_[reg] == NULL) {
658 candidate = static_cast<Register>(reg);
659 free_until = kMaxPosition;
660 break;
661 }
662 }
663 }
664
665 ASSERT(0 <= kMaxPosition);
666 if (free_until != kMaxPosition) {
667 for (int reg = 0; reg < kNumberOfCpuRegisters; ++reg) {
668 if (cpu_regs_[reg] == kPermanentlyBlocked) continue;
669 if (reg == candidate) continue;
670
671 const intptr_t pos = FirstIntersection(cpu_regs_[reg], unallocated);
672
673 if (pos > free_until) {
674 candidate = static_cast<Register>(reg);
675 free_until = pos;
676 if (free_until == kMaxPosition) break;
677 }
678 }
679 }
680
681 // All registers are blocked by active ranges.
682 if (free_until <= unallocated->start()) return false;
683
684 AssignFreeRegister(unallocated, candidate);
685 return true;
686 }
687
688
689 UseInterval* UseInterval::Split(intptr_t pos) {
690 if (pos == start()) return this;
691 ASSERT(Contains(pos));
692 UseInterval* tail = new UseInterval(vreg(), pos, end(), next());
693
694 UsePosition* use = uses_;
695 while (use != NULL && use->pos() <= pos) {
696 use = use->next();
697 }
698
699 tail->uses_ = use;
700
701 end_ = pos;
702
703 return tail;
704 }
705
706
707 void FlowGraphAllocator::AssignFreeRegister(UseInterval* unallocated,
708 Register reg) {
709 TRACE_ALLOC(("assigning free register %s to %d\n",
710 Location::RegisterLocation(reg).Name(),
711 unallocated->vreg()));
712
713 UseInterval* a = cpu_regs_[reg];
714 if (a == NULL) {
715 // Register is completely free.
716 cpu_regs_[reg] = unallocated;
717 return;
718 }
719
720 UseInterval* u = unallocated;
721 ASSERT(u->start() < a->start()); // Register is free.
722 cpu_regs_[reg] = u;
723 if (u->next() == NULL || u->next()->start() >= a->start()) {
724 u->set_next_allocated(a);
725 }
726
727 while (a != NULL && u != NULL) {
728 const intptr_t pos = a->Intersect(u);
729 if (pos != kIllegalPosition) {
730 // TODO(vegorov): split live ranges might require control flow resolution
731 // which is not implemented yet.
732 builder_->Bailout("ssa allocator: control flow resolution required");
733
734 TRACE_ALLOC((" splitting at %d\n", pos));
735 // Reached intersection
736 UseInterval* tail = u->Split(pos);
737 AddToUnallocated(tail);
738 ASSERT(tail == u || u->next_allocated() == a);
739 return;
740 }
741
742 if (a->start() < u->start()) {
743 if (a->next_allocated() == NULL) {
744 a->set_next_allocated(u);
745 break;
746 }
747
748 UseInterval* next = a->next_allocated();
749 if (next->start() > u->start()) {
750 a->set_next_allocated(u);
751 u->set_next_allocated(next);
752 }
753
754 a = next;
755 } else {
756 UseInterval* next = u->next();
757
758 if (next == NULL || next->start() >= a->start()) {
759 u->set_next_allocated(a);
760 }
761 u = next;
762 }
763 }
764 }
765
766
767 static void InsertMoveBefore(Instruction* instr, Location to, Location from) {
768 Instruction* prev = instr->previous();
769 ParallelMoveInstr* move = prev->AsParallelMove();
770 if (move == NULL) {
771 move = new ParallelMoveInstr();
772 move->set_next(prev->next());
773 prev->set_next(move);
774 move->next()->set_previous(move);
775 move->set_previous(prev);
776 }
777 move->AddMove(to, from);
778 }
779
780
781 void UsePosition::AssignLocation(Location loc) {
782 if (location_slot_ == NULL) return;
783
784 if (location_slot_->IsUnallocated()) {
785 if (location_slot_->policy() == Location::kSameAsFirstInput) {
786 Instruction* instr = this->instr();
787 LocationSummary* locs = instr->locs();
788 if (!locs->in(0).IsUnallocated()) {
789 InsertMoveBefore(instr, loc, locs->in(0));
790 }
791 locs->set_in(0, loc);
792 }
793 TRACE_ALLOC((" use at %d converted to %s\n", pos(), loc.Name()));
794 *location_slot_ = loc;
795 } else if (location_slot_->IsRegister()) {
796 InsertMoveBefore(this->instr(), *location_slot_, loc);
797 }
798 }
799
800
801 void FlowGraphAllocator::FinalizeInterval(UseInterval* interval, Location loc) {
802 if (interval->vreg() == kNoVirtualRegister) return;
803
804 TRACE_ALLOC(("assigning location %s to interval [%d, %d)\n", loc.Name(),
805 interval->start(), interval->end()));
806
807 for (UsePosition* use = interval->first_use();
808 use != NULL && use->pos() <= interval->end();
809 use = use->next()) {
810 use->AssignLocation(loc);
811 }
812 }
813
814
815 void FlowGraphAllocator::AdvanceActiveIntervals(const intptr_t start) {
816 for (int reg = 0; reg < kNumberOfCpuRegisters; reg++) {
817 if (cpu_regs_[reg] == NULL) continue;
818 if (cpu_regs_[reg] == kPermanentlyBlocked) continue;
819
820 UseInterval* a = cpu_regs_[reg];
821 while (a != NULL && a->end() <= start) {
822 FinalizeInterval(a,
823 Location::RegisterLocation(static_cast<Register>(reg)));
824 a = a->next_allocated();
825 }
826
827 cpu_regs_[reg] = a;
828 }
829 }
830
831
832 static inline bool ShouldBeAllocatedBefore(UseInterval* a, UseInterval* b) {
833 return a->start() <= b->start();
834 }
835
836
837 void FlowGraphAllocator::AddToUnallocated(UseInterval* chain) {
838 if (unallocated_.is_empty()) {
839 unallocated_.Add(chain);
840 return;
841 }
842
843 for (intptr_t i = unallocated_.length() - 1; i >= 0; i--) {
844 if (ShouldBeAllocatedBefore(chain, unallocated_[i])) {
845 unallocated_.InsertAt(i + 1, chain);
846 return;
847 }
848 }
849 unallocated_.InsertAt(0, chain);
850 }
851
852
853 bool FlowGraphAllocator::UnallocatedIsSorted() {
854 for (intptr_t i = unallocated_.length() - 1; i >= 1; i--) {
855 UseInterval* a = unallocated_[i];
856 UseInterval* b = unallocated_[i - 1];
857 if (!ShouldBeAllocatedBefore(a, b)) return false;
858 }
859 return true;
860 }
861
862
863 void FlowGraphAllocator::AllocateCPURegisters() {
864 ASSERT(UnallocatedIsSorted());
865
866 while (!unallocated_.is_empty()) {
867 UseInterval* range = unallocated_.Last();
868 unallocated_.RemoveLast();
869 const intptr_t start = range->start();
870 TRACE_ALLOC(("Processing interval chain for vreg %d starting at %d\n",
871 range->vreg(),
872 start));
873
874 // TODO(vegorov): eagerly spill liveranges without register uses.
875 AdvanceActiveIntervals(start);
876
877 if (!AllocateFreeRegister(range)) {
878 builder_->Bailout("ssa allocator: spilling required");
879 return;
880 }
881 }
882
883 // All allocation decisions were done.
884 ASSERT(unallocated_.is_empty());
885
886 // Finish allocation.
887 AdvanceActiveIntervals(kMaxPosition);
888 TRACE_ALLOC(("Allocation completed\n"));
889 }
890
891
892 void FlowGraphAllocator::AllocateRegisters() {
893 GraphEntryInstr* entry = block_order_[0]->AsGraphEntry();
894 ASSERT(entry != NULL);
895
896 for (intptr_t i = 0; i < entry->start_env()->values().length(); i++) {
897 if (entry->start_env()->values()[i]->IsUse()) {
898 builder_->Bailout("ssa allocator: unsupported start environment");
899 }
900 }
901
902 AnalyzeLiveness();
903
904 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
905 cpu_regs_[reg] = NULL;
906 }
907
908 cpu_regs_[CTX] = kPermanentlyBlocked;
909 if (TMP != kNoRegister) {
910 cpu_regs_[TMP] = kPermanentlyBlocked;
911 }
912 cpu_regs_[SPREG] = kPermanentlyBlocked;
913 cpu_regs_[FPREG] = kPermanentlyBlocked;
914
915 BuildLiveRanges();
916
917 if (FLAG_print_ssa_liveness) {
918 DumpLiveness();
919 }
920
921 if (FLAG_trace_ssa_allocator) {
922 PrintLiveRanges();
923 }
924
925 AllocateCPURegisters();
926
927 if (FLAG_trace_ssa_allocator) {
928 OS::Print("-- ir after allocation -------------------------\n");
929 FlowGraphPrinter printer(Function::Handle(), block_order_, true);
930 printer.PrintBlocks();
931 }
932 }
933
934
177 } // namespace dart 935 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698