OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/compiler/linkage.h" | 6 #include "src/compiler/linkage.h" |
7 #include "src/compiler/register-allocator.h" | 7 #include "src/compiler/register-allocator.h" |
8 #include "src/string-stream.h" | 8 #include "src/string-stream.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 16 matching lines...) Expand all Loading... |
27 return a.Value() > b.Value() ? a : b; | 27 return a.Value() > b.Value() ? a : b; |
28 } | 28 } |
29 | 29 |
30 | 30 |
31 void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { | 31 void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { |
32 auto it = std::find(v->begin(), v->end(), range); | 32 auto it = std::find(v->begin(), v->end(), range); |
33 DCHECK(it != v->end()); | 33 DCHECK(it != v->end()); |
34 v->erase(it); | 34 v->erase(it); |
35 } | 35 } |
36 | 36 |
| 37 |
| 38 int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) { |
| 39 return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers() |
| 40 : cfg->num_general_registers(); |
| 41 } |
| 42 |
| 43 |
| 44 const ZoneVector<LiveRange*>& GetFixedRegisters( |
| 45 const RegisterAllocationData* data, RegisterKind kind) { |
| 46 return kind == DOUBLE_REGISTERS ? data->fixed_double_live_ranges() |
| 47 : data->fixed_live_ranges(); |
| 48 } |
| 49 |
| 50 |
| 51 const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence, |
| 52 const InstructionBlock* block) { |
| 53 auto index = block->loop_header(); |
| 54 if (!index.IsValid()) return nullptr; |
| 55 return sequence->InstructionBlockAt(index); |
| 56 } |
| 57 |
| 58 |
| 59 const InstructionBlock* GetInstructionBlock(const InstructionSequence* code, |
| 60 LifetimePosition pos) { |
| 61 return code->GetInstructionBlock(pos.ToInstructionIndex()); |
| 62 } |
| 63 |
| 64 |
| 65 bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) { |
| 66 return pos.IsFullStart() && |
| 67 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == |
| 68 pos.ToInstructionIndex(); |
| 69 } |
| 70 |
| 71 |
37 } // namespace | 72 } // namespace |
38 | 73 |
39 | 74 |
40 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 75 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
41 InstructionOperand* hint) | 76 InstructionOperand* hint) |
42 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { | 77 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { |
43 bool register_beneficial = true; | 78 bool register_beneficial = true; |
44 UsePositionType type = UsePositionType::kAny; | 79 UsePositionType type = UsePositionType::kAny; |
45 if (operand_ != nullptr && operand_->IsUnallocated()) { | 80 if (operand_ != nullptr && operand_->IsUnallocated()) { |
46 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); | 81 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 struct LiveRange::SpillAtDefinitionList : ZoneObject { | 118 struct LiveRange::SpillAtDefinitionList : ZoneObject { |
84 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, | 119 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, |
85 SpillAtDefinitionList* next) | 120 SpillAtDefinitionList* next) |
86 : gap_index(gap_index), operand(operand), next(next) {} | 121 : gap_index(gap_index), operand(operand), next(next) {} |
87 const int gap_index; | 122 const int gap_index; |
88 InstructionOperand* const operand; | 123 InstructionOperand* const operand; |
89 SpillAtDefinitionList* const next; | 124 SpillAtDefinitionList* const next; |
90 }; | 125 }; |
91 | 126 |
92 | 127 |
93 LiveRange::LiveRange(int id, Zone* zone) | 128 LiveRange::LiveRange(int id) |
94 : id_(id), | 129 : id_(id), |
95 spilled_(false), | 130 spilled_(false), |
96 has_slot_use_(false), | 131 has_slot_use_(false), |
97 is_phi_(false), | 132 is_phi_(false), |
98 is_non_loop_phi_(false), | 133 is_non_loop_phi_(false), |
99 kind_(UNALLOCATED_REGISTERS), | 134 kind_(UNALLOCATED_REGISTERS), |
100 assigned_register_(kInvalidAssignment), | 135 assigned_register_(kInvalidAssignment), |
101 last_interval_(nullptr), | 136 last_interval_(nullptr), |
102 first_interval_(nullptr), | 137 first_interval_(nullptr), |
103 first_pos_(nullptr), | 138 first_pos_(nullptr), |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 } else { | 397 } else { |
363 while (use_after != nullptr && | 398 while (use_after != nullptr && |
364 use_after->pos().Value() <= position.Value()) { | 399 use_after->pos().Value() <= position.Value()) { |
365 use_before = use_after; | 400 use_before = use_after; |
366 use_after = use_after->next(); | 401 use_after = use_after->next(); |
367 } | 402 } |
368 } | 403 } |
369 | 404 |
370 // Partition original use positions to the two live ranges. | 405 // Partition original use positions to the two live ranges. |
371 if (use_before != nullptr) { | 406 if (use_before != nullptr) { |
372 use_before->next_ = nullptr; | 407 use_before->set_next(nullptr); |
373 } else { | 408 } else { |
374 first_pos_ = nullptr; | 409 first_pos_ = nullptr; |
375 } | 410 } |
376 result->first_pos_ = use_after; | 411 result->first_pos_ = use_after; |
377 | 412 |
378 // Discard cached iteration state. It might be pointing | 413 // Discard cached iteration state. It might be pointing |
379 // to the use that no longer belongs to this live range. | 414 // to the use that no longer belongs to this live range. |
380 last_processed_use_ = nullptr; | 415 last_processed_use_ = nullptr; |
381 current_interval_ = nullptr; | 416 current_interval_ = nullptr; |
382 | 417 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
429 auto new_end = end; | 464 auto new_end = end; |
430 while (first_interval_ != nullptr && | 465 while (first_interval_ != nullptr && |
431 first_interval_->start().Value() <= end.Value()) { | 466 first_interval_->start().Value() <= end.Value()) { |
432 if (first_interval_->end().Value() > end.Value()) { | 467 if (first_interval_->end().Value() > end.Value()) { |
433 new_end = first_interval_->end(); | 468 new_end = first_interval_->end(); |
434 } | 469 } |
435 first_interval_ = first_interval_->next(); | 470 first_interval_ = first_interval_->next(); |
436 } | 471 } |
437 | 472 |
438 auto new_interval = new (zone) UseInterval(start, new_end); | 473 auto new_interval = new (zone) UseInterval(start, new_end); |
439 new_interval->next_ = first_interval_; | 474 new_interval->set_next(first_interval_); |
440 first_interval_ = new_interval; | 475 first_interval_ = new_interval; |
441 if (new_interval->next() == nullptr) { | 476 if (new_interval->next() == nullptr) { |
442 last_interval_ = new_interval; | 477 last_interval_ = new_interval; |
443 } | 478 } |
444 } | 479 } |
445 | 480 |
446 | 481 |
447 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end, | 482 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end, |
448 Zone* zone) { | 483 Zone* zone) { |
449 TRACE("Add to live range %d interval [%d %d[\n", id_, start.Value(), | 484 TRACE("Add to live range %d interval [%d %d[\n", id_, start.Value(), |
450 end.Value()); | 485 end.Value()); |
451 if (first_interval_ == nullptr) { | 486 if (first_interval_ == nullptr) { |
452 auto interval = new (zone) UseInterval(start, end); | 487 auto interval = new (zone) UseInterval(start, end); |
453 first_interval_ = interval; | 488 first_interval_ = interval; |
454 last_interval_ = interval; | 489 last_interval_ = interval; |
455 } else { | 490 } else { |
456 if (end.Value() == first_interval_->start().Value()) { | 491 if (end.Value() == first_interval_->start().Value()) { |
457 first_interval_->set_start(start); | 492 first_interval_->set_start(start); |
458 } else if (end.Value() < first_interval_->start().Value()) { | 493 } else if (end.Value() < first_interval_->start().Value()) { |
459 auto interval = new (zone) UseInterval(start, end); | 494 auto interval = new (zone) UseInterval(start, end); |
460 interval->set_next(first_interval_); | 495 interval->set_next(first_interval_); |
461 first_interval_ = interval; | 496 first_interval_ = interval; |
462 } else { | 497 } else { |
463 // Order of instruction's processing (see ProcessInstructions) guarantees | 498 // Order of instruction's processing (see ProcessInstructions) guarantees |
464 // that each new use interval either precedes or intersects with | 499 // that each new use interval either precedes or intersects with |
465 // last added interval. | 500 // last added interval. |
466 DCHECK(start.Value() < first_interval_->end().Value()); | 501 DCHECK(start.Value() < first_interval_->end().Value()); |
467 first_interval_->start_ = Min(start, first_interval_->start_); | 502 first_interval_->set_start(Min(start, first_interval_->start())); |
468 first_interval_->end_ = Max(end, first_interval_->end_); | 503 first_interval_->set_end(Max(end, first_interval_->end())); |
469 } | 504 } |
470 } | 505 } |
471 } | 506 } |
472 | 507 |
473 | 508 |
474 void LiveRange::AddUsePosition(LifetimePosition pos, | 509 void LiveRange::AddUsePosition(LifetimePosition pos, |
475 InstructionOperand* operand, | 510 InstructionOperand* operand, |
476 InstructionOperand* hint, Zone* zone) { | 511 InstructionOperand* hint, Zone* zone) { |
477 TRACE("Add to live range %d use position %d\n", id_, pos.Value()); | 512 TRACE("Add to live range %d use position %d\n", id_, pos.Value()); |
478 auto use_pos = new (zone) UsePosition(pos, operand, hint); | 513 auto use_pos = new (zone) UsePosition(pos, operand, hint); |
479 UsePosition* prev_hint = nullptr; | 514 UsePosition* prev_hint = nullptr; |
480 UsePosition* prev = nullptr; | 515 UsePosition* prev = nullptr; |
481 auto current = first_pos_; | 516 auto current = first_pos_; |
482 while (current != nullptr && current->pos().Value() < pos.Value()) { | 517 while (current != nullptr && current->pos().Value() < pos.Value()) { |
483 prev_hint = current->HasHint() ? current : prev_hint; | 518 prev_hint = current->HasHint() ? current : prev_hint; |
484 prev = current; | 519 prev = current; |
485 current = current->next(); | 520 current = current->next(); |
486 } | 521 } |
487 | 522 |
488 if (prev == nullptr) { | 523 if (prev == nullptr) { |
489 use_pos->set_next(first_pos_); | 524 use_pos->set_next(first_pos_); |
490 first_pos_ = use_pos; | 525 first_pos_ = use_pos; |
491 } else { | 526 } else { |
492 use_pos->next_ = prev->next_; | 527 use_pos->set_next(prev->next()); |
493 prev->next_ = use_pos; | 528 prev->set_next(use_pos); |
494 } | 529 } |
495 | 530 |
496 if (prev_hint == nullptr && use_pos->HasHint()) { | 531 if (prev_hint == nullptr && use_pos->HasHint()) { |
497 current_hint_operand_ = hint; | 532 current_hint_operand_ = hint; |
498 } | 533 } |
499 } | 534 } |
500 | 535 |
501 | 536 |
502 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, | 537 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
503 InstructionOperand* spill_op) { | 538 InstructionOperand* spill_op) { |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
741 DCHECK(range->is_phi()); | 776 DCHECK(range->is_phi()); |
742 auto it = phi_map().find(range->id()); | 777 auto it = phi_map().find(range->id()); |
743 DCHECK(it != phi_map().end()); | 778 DCHECK(it != phi_map().end()); |
744 for (auto move : it->second->incoming_moves) { | 779 for (auto move : it->second->incoming_moves) { |
745 move->set_destination(assignment); | 780 move->set_destination(assignment); |
746 } | 781 } |
747 } | 782 } |
748 | 783 |
749 | 784 |
750 LiveRange* RegisterAllocationData::NewLiveRange(int index) { | 785 LiveRange* RegisterAllocationData::NewLiveRange(int index) { |
751 // The LiveRange object itself can go in the local zone, but the | 786 return new (allocation_zone()) LiveRange(index); |
752 // InstructionOperand needs to go in the code zone, since it may survive | |
753 // register allocation. | |
754 return new (allocation_zone()) LiveRange(index, code_zone()); | |
755 } | 787 } |
756 | 788 |
757 | 789 |
758 bool RegisterAllocationData::ExistsUseWithoutDefinition() { | 790 bool RegisterAllocationData::ExistsUseWithoutDefinition() { |
759 bool found = false; | 791 bool found = false; |
760 BitVector::Iterator iterator(live_in_sets()[0]); | 792 BitVector::Iterator iterator(live_in_sets()[0]); |
761 while (!iterator.Done()) { | 793 while (!iterator.Done()) { |
762 found = true; | 794 found = true; |
763 int operand_index = iterator.Current(); | 795 int operand_index = iterator.Current(); |
764 PrintF("Register allocator error: live v%d reached first block.\n", | 796 PrintF("Register allocator error: live v%d reached first block.\n", |
(...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1388 range->set_kind(RequiredRegisterKind(range->id())); | 1420 range->set_kind(RequiredRegisterKind(range->id())); |
1389 // Give slots to all ranges with a non fixed slot use. | 1421 // Give slots to all ranges with a non fixed slot use. |
1390 if (range->has_slot_use() && range->HasNoSpillType()) { | 1422 if (range->has_slot_use() && range->HasNoSpillType()) { |
1391 data()->AssignSpillRangeToLiveRange(range); | 1423 data()->AssignSpillRangeToLiveRange(range); |
1392 } | 1424 } |
1393 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1425 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
1394 // live ranges, every use requires the constant to be in a register. | 1426 // live ranges, every use requires the constant to be in a register. |
1395 // Without this hack, all uses with "any" policy would get the constant | 1427 // Without this hack, all uses with "any" policy would get the constant |
1396 // operand assigned. | 1428 // operand assigned. |
1397 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1429 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
1398 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { | 1430 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) { |
1399 if (pos->type() == UsePositionType::kRequiresSlot) continue; | 1431 if (pos->type() == UsePositionType::kRequiresSlot) continue; |
1400 UsePositionType new_type = UsePositionType::kAny; | 1432 UsePositionType new_type = UsePositionType::kAny; |
1401 // Can't mark phis as needing a register. | 1433 // Can't mark phis as needing a register. |
1402 if (!pos->pos().IsGapPosition()) { | 1434 if (!pos->pos().IsGapPosition()) { |
1403 new_type = UsePositionType::kRequiresRegister; | 1435 new_type = UsePositionType::kRequiresRegister; |
1404 } | 1436 } |
1405 pos->set_type(new_type, true); | 1437 pos->set_type(new_type, true); |
1406 } | 1438 } |
1407 } | 1439 } |
1408 } | 1440 } |
(...skipping 12 matching lines...) Expand all Loading... |
1421 | 1453 |
1422 | 1454 |
1423 void LiveRangeBuilder::Verify() const { | 1455 void LiveRangeBuilder::Verify() const { |
1424 for (auto current : data()->live_ranges()) { | 1456 for (auto current : data()->live_ranges()) { |
1425 if (current != nullptr) current->Verify(); | 1457 if (current != nullptr) current->Verify(); |
1426 } | 1458 } |
1427 } | 1459 } |
1428 | 1460 |
1429 | 1461 |
1430 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, | 1462 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, |
1431 RegisterKind kind) | 1463 RegisterKind kind, Zone* local_zone) |
1432 : data_(data), | 1464 : data_(data), |
1433 mode_(kind), | 1465 mode_(kind), |
1434 num_registers_(kind == DOUBLE_REGISTERS | 1466 num_registers_(GetRegisterCount(data->config(), kind)), |
1435 ? config()->num_aliased_double_registers() | 1467 unhandled_live_ranges_(local_zone), |
1436 : config()->num_general_registers()), | 1468 active_live_ranges_(local_zone), |
1437 unhandled_live_ranges_(allocation_zone()), | 1469 inactive_live_ranges_(local_zone) { |
1438 active_live_ranges_(allocation_zone()), | |
1439 inactive_live_ranges_(allocation_zone()) { | |
1440 unhandled_live_ranges().reserve( | 1470 unhandled_live_ranges().reserve( |
1441 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); | 1471 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); |
1442 active_live_ranges().reserve(8); | 1472 active_live_ranges().reserve(8); |
1443 inactive_live_ranges().reserve(8); | 1473 inactive_live_ranges().reserve(8); |
1444 // TryAllocateFreeReg and AllocateBlockedReg assume this | 1474 // TryAllocateFreeReg and AllocateBlockedReg assume this |
1445 // when allocating local arrays. | 1475 // when allocating local arrays. |
1446 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= | 1476 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= |
1447 config()->num_general_registers()); | 1477 config()->num_general_registers()); |
1448 } | 1478 } |
1449 | 1479 |
1450 | 1480 |
1451 void LinearScanAllocator::AllocateRegisters() { | 1481 void LinearScanAllocator::AllocateRegisters() { |
1452 DCHECK(unhandled_live_ranges().empty()); | 1482 DCHECK(unhandled_live_ranges().empty()); |
1453 | 1483 |
1454 for (auto range : live_ranges()) { | 1484 for (auto range : live_ranges()) { |
1455 if (range == nullptr) continue; | 1485 if (range == nullptr) continue; |
1456 if (range->Kind() == mode_) { | 1486 if (range->Kind() == mode_) { |
1457 AddToUnhandledUnsorted(range); | 1487 AddToUnhandledUnsorted(range); |
1458 } | 1488 } |
1459 } | 1489 } |
1460 SortUnhandled(); | 1490 SortUnhandled(); |
1461 DCHECK(UnhandledIsSorted()); | 1491 DCHECK(UnhandledIsSorted()); |
1462 | 1492 |
1463 DCHECK(active_live_ranges().empty()); | 1493 DCHECK(active_live_ranges().empty()); |
1464 DCHECK(inactive_live_ranges().empty()); | 1494 DCHECK(inactive_live_ranges().empty()); |
1465 | 1495 |
1466 if (mode_ == DOUBLE_REGISTERS) { | 1496 auto& fixed_ranges = GetFixedRegisters(data(), mode_); |
1467 for (auto current : fixed_double_live_ranges()) { | 1497 for (auto current : fixed_ranges) { |
1468 if (current != nullptr) AddToInactive(current); | 1498 if (current != nullptr) { |
1469 } | 1499 DCHECK_EQ(mode_, current->Kind()); |
1470 } else { | 1500 AddToInactive(current); |
1471 DCHECK(mode_ == GENERAL_REGISTERS); | |
1472 for (auto current : fixed_live_ranges()) { | |
1473 if (current != nullptr) AddToInactive(current); | |
1474 } | 1501 } |
1475 } | 1502 } |
1476 | 1503 |
1477 while (!unhandled_live_ranges().empty()) { | 1504 while (!unhandled_live_ranges().empty()) { |
1478 DCHECK(UnhandledIsSorted()); | 1505 DCHECK(UnhandledIsSorted()); |
1479 auto current = unhandled_live_ranges().back(); | 1506 auto current = unhandled_live_ranges().back(); |
1480 unhandled_live_ranges().pop_back(); | 1507 unhandled_live_ranges().pop_back(); |
1481 DCHECK(UnhandledIsSorted()); | 1508 DCHECK(UnhandledIsSorted()); |
1482 auto position = current->Start(); | 1509 auto position = current->Start(); |
1483 #ifdef DEBUG | 1510 #ifdef DEBUG |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1537 if (current->HasRegisterAssigned()) { | 1564 if (current->HasRegisterAssigned()) { |
1538 AddToActive(current); | 1565 AddToActive(current); |
1539 } | 1566 } |
1540 } | 1567 } |
1541 | 1568 |
1542 active_live_ranges().clear(); | 1569 active_live_ranges().clear(); |
1543 inactive_live_ranges().clear(); | 1570 inactive_live_ranges().clear(); |
1544 } | 1571 } |
1545 | 1572 |
1546 | 1573 |
1547 const char* LinearScanAllocator::RegisterName(int allocation_index) { | 1574 const char* LinearScanAllocator::RegisterName(int allocation_index) const { |
1548 if (mode_ == GENERAL_REGISTERS) { | 1575 if (mode_ == GENERAL_REGISTERS) { |
1549 return config()->general_register_name(allocation_index); | 1576 return config()->general_register_name(allocation_index); |
1550 } else { | 1577 } else { |
1551 return config()->double_register_name(allocation_index); | 1578 return config()->double_register_name(allocation_index); |
1552 } | 1579 } |
1553 } | 1580 } |
1554 | 1581 |
1555 | 1582 |
1556 void LinearScanAllocator::AddToActive(LiveRange* range) { | 1583 void LinearScanAllocator::AddToActive(LiveRange* range) { |
1557 TRACE("Add live range %d to active\n", range->id()); | 1584 TRACE("Add live range %d to active\n", range->id()); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1644 void LinearScanAllocator::InactiveToActive(LiveRange* range) { | 1671 void LinearScanAllocator::InactiveToActive(LiveRange* range) { |
1645 RemoveElement(&inactive_live_ranges(), range); | 1672 RemoveElement(&inactive_live_ranges(), range); |
1646 active_live_ranges().push_back(range); | 1673 active_live_ranges().push_back(range); |
1647 TRACE("Moving live range %d from inactive to active\n", range->id()); | 1674 TRACE("Moving live range %d from inactive to active\n", range->id()); |
1648 } | 1675 } |
1649 | 1676 |
1650 | 1677 |
1651 bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) { | 1678 bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) { |
1652 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1679 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
1653 | 1680 |
1654 for (int i = 0; i < num_registers_; i++) { | 1681 for (int i = 0; i < num_registers(); i++) { |
1655 free_until_pos[i] = LifetimePosition::MaxPosition(); | 1682 free_until_pos[i] = LifetimePosition::MaxPosition(); |
1656 } | 1683 } |
1657 | 1684 |
1658 for (auto cur_active : active_live_ranges()) { | 1685 for (auto cur_active : active_live_ranges()) { |
1659 free_until_pos[cur_active->assigned_register()] = | 1686 free_until_pos[cur_active->assigned_register()] = |
1660 LifetimePosition::GapFromInstructionIndex(0); | 1687 LifetimePosition::GapFromInstructionIndex(0); |
1661 } | 1688 } |
1662 | 1689 |
1663 for (auto cur_inactive : inactive_live_ranges()) { | 1690 for (auto cur_inactive : inactive_live_ranges()) { |
1664 DCHECK(cur_inactive->End().Value() > current->Start().Value()); | 1691 DCHECK(cur_inactive->End().Value() > current->Start().Value()); |
1665 auto next_intersection = cur_inactive->FirstIntersection(current); | 1692 auto next_intersection = cur_inactive->FirstIntersection(current); |
1666 if (!next_intersection.IsValid()) continue; | 1693 if (!next_intersection.IsValid()) continue; |
1667 int cur_reg = cur_inactive->assigned_register(); | 1694 int cur_reg = cur_inactive->assigned_register(); |
1668 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); | 1695 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); |
1669 } | 1696 } |
1670 | 1697 |
1671 auto hint = current->FirstHint(); | 1698 auto hint = current->FirstHint(); |
1672 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { | 1699 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { |
1673 int register_index = AllocatedOperand::cast(hint)->index(); | 1700 int register_index = AllocatedOperand::cast(hint)->index(); |
1674 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", | 1701 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", |
1675 RegisterName(register_index), free_until_pos[register_index].Value(), | 1702 RegisterName(register_index), free_until_pos[register_index].Value(), |
1676 current->id(), current->End().Value()); | 1703 current->id(), current->End().Value()); |
1677 | 1704 |
1678 // The desired register is free until the end of the current live range. | 1705 // The desired register is free until the end of the current live range. |
1679 if (free_until_pos[register_index].Value() >= current->End().Value()) { | 1706 if (free_until_pos[register_index].Value() >= current->End().Value()) { |
1680 TRACE("Assigning preferred reg %s to live range %d\n", | 1707 TRACE("Assigning preferred reg %s to live range %d\n", |
1681 RegisterName(register_index), current->id()); | 1708 RegisterName(register_index), current->id()); |
1682 SetLiveRangeAssignedRegister(current, register_index); | 1709 data()->SetLiveRangeAssignedRegister(current, register_index); |
1683 return true; | 1710 return true; |
1684 } | 1711 } |
1685 } | 1712 } |
1686 | 1713 |
1687 // Find the register which stays free for the longest time. | 1714 // Find the register which stays free for the longest time. |
1688 int reg = 0; | 1715 int reg = 0; |
1689 for (int i = 1; i < RegisterCount(); ++i) { | 1716 for (int i = 1; i < num_registers(); ++i) { |
1690 if (free_until_pos[i].Value() > free_until_pos[reg].Value()) { | 1717 if (free_until_pos[i].Value() > free_until_pos[reg].Value()) { |
1691 reg = i; | 1718 reg = i; |
1692 } | 1719 } |
1693 } | 1720 } |
1694 | 1721 |
1695 auto pos = free_until_pos[reg]; | 1722 auto pos = free_until_pos[reg]; |
1696 | 1723 |
1697 if (pos.Value() <= current->Start().Value()) { | 1724 if (pos.Value() <= current->Start().Value()) { |
1698 // All registers are blocked. | 1725 // All registers are blocked. |
1699 return false; | 1726 return false; |
1700 } | 1727 } |
1701 | 1728 |
1702 if (pos.Value() < current->End().Value()) { | 1729 if (pos.Value() < current->End().Value()) { |
1703 // Register reg is available at the range start but becomes blocked before | 1730 // Register reg is available at the range start but becomes blocked before |
1704 // the range end. Split current at position where it becomes blocked. | 1731 // the range end. Split current at position where it becomes blocked. |
1705 auto tail = SplitRangeAt(current, pos); | 1732 auto tail = SplitRangeAt(current, pos); |
1706 AddToUnhandledSorted(tail); | 1733 AddToUnhandledSorted(tail); |
1707 } | 1734 } |
1708 | 1735 |
1709 // Register reg is available at the range start and is free until | 1736 // Register reg is available at the range start and is free until |
1710 // the range end. | 1737 // the range end. |
1711 DCHECK(pos.Value() >= current->End().Value()); | 1738 DCHECK(pos.Value() >= current->End().Value()); |
1712 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), | 1739 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), |
1713 current->id()); | 1740 current->id()); |
1714 SetLiveRangeAssignedRegister(current, reg); | 1741 data()->SetLiveRangeAssignedRegister(current, reg); |
1715 | 1742 |
1716 return true; | 1743 return true; |
1717 } | 1744 } |
1718 | 1745 |
1719 | 1746 |
1720 void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { | 1747 void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { |
1721 auto register_use = current->NextRegisterPosition(current->Start()); | 1748 auto register_use = current->NextRegisterPosition(current->Start()); |
1722 if (register_use == nullptr) { | 1749 if (register_use == nullptr) { |
1723 // There is no use in the current live range that requires a register. | 1750 // There is no use in the current live range that requires a register. |
1724 // We can just spill it. | 1751 // We can just spill it. |
1725 Spill(current); | 1752 Spill(current); |
1726 return; | 1753 return; |
1727 } | 1754 } |
1728 | 1755 |
1729 LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1756 LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
1730 LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1757 LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
1731 | 1758 |
1732 for (int i = 0; i < num_registers_; i++) { | 1759 for (int i = 0; i < num_registers(); i++) { |
1733 use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition(); | 1760 use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition(); |
1734 } | 1761 } |
1735 | 1762 |
1736 for (auto range : active_live_ranges()) { | 1763 for (auto range : active_live_ranges()) { |
1737 int cur_reg = range->assigned_register(); | 1764 int cur_reg = range->assigned_register(); |
1738 if (range->IsFixed() || !range->CanBeSpilled(current->Start())) { | 1765 if (range->IsFixed() || !range->CanBeSpilled(current->Start())) { |
1739 block_pos[cur_reg] = use_pos[cur_reg] = | 1766 block_pos[cur_reg] = use_pos[cur_reg] = |
1740 LifetimePosition::GapFromInstructionIndex(0); | 1767 LifetimePosition::GapFromInstructionIndex(0); |
1741 } else { | 1768 } else { |
1742 auto next_use = | 1769 auto next_use = |
(...skipping 13 matching lines...) Expand all Loading... |
1756 int cur_reg = range->assigned_register(); | 1783 int cur_reg = range->assigned_register(); |
1757 if (range->IsFixed()) { | 1784 if (range->IsFixed()) { |
1758 block_pos[cur_reg] = Min(block_pos[cur_reg], next_intersection); | 1785 block_pos[cur_reg] = Min(block_pos[cur_reg], next_intersection); |
1759 use_pos[cur_reg] = Min(block_pos[cur_reg], use_pos[cur_reg]); | 1786 use_pos[cur_reg] = Min(block_pos[cur_reg], use_pos[cur_reg]); |
1760 } else { | 1787 } else { |
1761 use_pos[cur_reg] = Min(use_pos[cur_reg], next_intersection); | 1788 use_pos[cur_reg] = Min(use_pos[cur_reg], next_intersection); |
1762 } | 1789 } |
1763 } | 1790 } |
1764 | 1791 |
1765 int reg = 0; | 1792 int reg = 0; |
1766 for (int i = 1; i < RegisterCount(); ++i) { | 1793 for (int i = 1; i < num_registers(); ++i) { |
1767 if (use_pos[i].Value() > use_pos[reg].Value()) { | 1794 if (use_pos[i].Value() > use_pos[reg].Value()) { |
1768 reg = i; | 1795 reg = i; |
1769 } | 1796 } |
1770 } | 1797 } |
1771 | 1798 |
1772 auto pos = use_pos[reg]; | 1799 auto pos = use_pos[reg]; |
1773 | 1800 |
1774 if (pos.Value() < register_use->pos().Value()) { | 1801 if (pos.Value() < register_use->pos().Value()) { |
1775 // All registers are blocked before the first use that requires a register. | 1802 // All registers are blocked before the first use that requires a register. |
1776 // Spill starting part of live range up to that use. | 1803 // Spill starting part of live range up to that use. |
1777 SpillBetween(current, current->Start(), register_use->pos()); | 1804 SpillBetween(current, current->Start(), register_use->pos()); |
1778 return; | 1805 return; |
1779 } | 1806 } |
1780 | 1807 |
1781 if (block_pos[reg].Value() < current->End().Value()) { | 1808 if (block_pos[reg].Value() < current->End().Value()) { |
1782 // Register becomes blocked before the current range end. Split before that | 1809 // Register becomes blocked before the current range end. Split before that |
1783 // position. | 1810 // position. |
1784 LiveRange* tail = | 1811 LiveRange* tail = |
1785 SplitBetween(current, current->Start(), block_pos[reg].Start()); | 1812 SplitBetween(current, current->Start(), block_pos[reg].Start()); |
1786 AddToUnhandledSorted(tail); | 1813 AddToUnhandledSorted(tail); |
1787 } | 1814 } |
1788 | 1815 |
1789 // Register reg is not blocked for the whole range. | 1816 // Register reg is not blocked for the whole range. |
1790 DCHECK(block_pos[reg].Value() >= current->End().Value()); | 1817 DCHECK(block_pos[reg].Value() >= current->End().Value()); |
1791 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), | 1818 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), |
1792 current->id()); | 1819 current->id()); |
1793 SetLiveRangeAssignedRegister(current, reg); | 1820 data()->SetLiveRangeAssignedRegister(current, reg); |
1794 | 1821 |
1795 // This register was not free. Thus we need to find and spill | 1822 // This register was not free. Thus we need to find and spill |
1796 // parts of active and inactive live regions that use the same register | 1823 // parts of active and inactive live regions that use the same register |
1797 // at the same lifetime positions as current. | 1824 // at the same lifetime positions as current. |
1798 SplitAndSpillIntersecting(current); | 1825 SplitAndSpillIntersecting(current); |
1799 } | 1826 } |
1800 | 1827 |
1801 | 1828 |
1802 static const InstructionBlock* GetContainingLoop( | |
1803 const InstructionSequence* sequence, const InstructionBlock* block) { | |
1804 auto index = block->loop_header(); | |
1805 if (!index.IsValid()) return nullptr; | |
1806 return sequence->InstructionBlockAt(index); | |
1807 } | |
1808 | |
1809 | |
1810 LifetimePosition LinearScanAllocator::FindOptimalSpillingPos( | 1829 LifetimePosition LinearScanAllocator::FindOptimalSpillingPos( |
1811 LiveRange* range, LifetimePosition pos) { | 1830 LiveRange* range, LifetimePosition pos) { |
1812 auto block = GetInstructionBlock(pos.Start()); | 1831 auto block = GetInstructionBlock(code(), pos.Start()); |
1813 auto loop_header = | 1832 auto loop_header = |
1814 block->IsLoopHeader() ? block : GetContainingLoop(code(), block); | 1833 block->IsLoopHeader() ? block : GetContainingLoop(code(), block); |
1815 | 1834 |
1816 if (loop_header == nullptr) return pos; | 1835 if (loop_header == nullptr) return pos; |
1817 | 1836 |
1818 auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos); | 1837 auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos); |
1819 | 1838 |
1820 while (loop_header != nullptr) { | 1839 while (loop_header != nullptr) { |
1821 // We are going to spill live range inside the loop. | 1840 // We are going to spill live range inside the loop. |
1822 // If possible try to move spilling position backwards to loop header. | 1841 // If possible try to move spilling position backwards to loop header. |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1894 auto lookup = phi_map().find(range->id()); | 1913 auto lookup = phi_map().find(range->id()); |
1895 DCHECK(lookup != phi_map().end()); | 1914 DCHECK(lookup != phi_map().end()); |
1896 auto phi = lookup->second->phi; | 1915 auto phi = lookup->second->phi; |
1897 auto block = lookup->second->block; | 1916 auto block = lookup->second->block; |
1898 // Count the number of spilled operands. | 1917 // Count the number of spilled operands. |
1899 size_t spilled_count = 0; | 1918 size_t spilled_count = 0; |
1900 LiveRange* first_op = nullptr; | 1919 LiveRange* first_op = nullptr; |
1901 for (size_t i = 0; i < phi->operands().size(); i++) { | 1920 for (size_t i = 0; i < phi->operands().size(); i++) { |
1902 int op = phi->operands()[i]; | 1921 int op = phi->operands()[i]; |
1903 LiveRange* op_range = LiveRangeFor(op); | 1922 LiveRange* op_range = LiveRangeFor(op); |
1904 if (op_range->GetSpillRange() == nullptr) continue; | 1923 if (!op_range->HasSpillRange()) continue; |
1905 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); | 1924 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
1906 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | 1925 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
1907 pred->last_instruction_index()); | 1926 pred->last_instruction_index()); |
1908 while (op_range != nullptr && !op_range->CanCover(pred_end)) { | 1927 while (op_range != nullptr && !op_range->CanCover(pred_end)) { |
1909 op_range = op_range->next(); | 1928 op_range = op_range->next(); |
1910 } | 1929 } |
1911 if (op_range != nullptr && op_range->IsSpilled()) { | 1930 if (op_range != nullptr && op_range->IsSpilled()) { |
1912 spilled_count++; | 1931 spilled_count++; |
1913 if (first_op == nullptr) { | 1932 if (first_op == nullptr) { |
1914 first_op = op_range->TopLevel(); | 1933 first_op = op_range->TopLevel(); |
1915 } | 1934 } |
1916 } | 1935 } |
1917 } | 1936 } |
1918 | 1937 |
1919 // Only continue if more than half of the operands are spilled. | 1938 // Only continue if more than half of the operands are spilled. |
1920 if (spilled_count * 2 <= phi->operands().size()) { | 1939 if (spilled_count * 2 <= phi->operands().size()) { |
1921 return false; | 1940 return false; |
1922 } | 1941 } |
1923 | 1942 |
1924 // Try to merge the spilled operands and count the number of merged spilled | 1943 // Try to merge the spilled operands and count the number of merged spilled |
1925 // operands. | 1944 // operands. |
1926 DCHECK(first_op != nullptr); | 1945 DCHECK(first_op != nullptr); |
1927 auto first_op_spill = first_op->GetSpillRange(); | 1946 auto first_op_spill = first_op->GetSpillRange(); |
1928 size_t num_merged = 1; | 1947 size_t num_merged = 1; |
1929 for (size_t i = 1; i < phi->operands().size(); i++) { | 1948 for (size_t i = 1; i < phi->operands().size(); i++) { |
1930 int op = phi->operands()[i]; | 1949 int op = phi->operands()[i]; |
1931 auto op_range = LiveRangeFor(op); | 1950 auto op_range = LiveRangeFor(op); |
| 1951 if (!op_range->HasSpillRange()) continue; |
1932 auto op_spill = op_range->GetSpillRange(); | 1952 auto op_spill = op_range->GetSpillRange(); |
1933 if (op_spill != nullptr && | 1953 if (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill)) { |
1934 (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) { | |
1935 num_merged++; | 1954 num_merged++; |
1936 } | 1955 } |
1937 } | 1956 } |
1938 | 1957 |
1939 // Only continue if enough operands could be merged to the | 1958 // Only continue if enough operands could be merged to the |
1940 // same spill slot. | 1959 // same spill slot. |
1941 if (num_merged * 2 <= phi->operands().size() || | 1960 if (num_merged * 2 <= phi->operands().size() || |
1942 AreUseIntervalsIntersecting(first_op_spill->interval(), | 1961 AreUseIntervalsIntersecting(first_op_spill->interval(), |
1943 range->first_interval())) { | 1962 range->first_interval())) { |
1944 return false; | 1963 return false; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1976 LiveRange* LinearScanAllocator::SplitRangeAt(LiveRange* range, | 1995 LiveRange* LinearScanAllocator::SplitRangeAt(LiveRange* range, |
1977 LifetimePosition pos) { | 1996 LifetimePosition pos) { |
1978 DCHECK(!range->IsFixed()); | 1997 DCHECK(!range->IsFixed()); |
1979 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); | 1998 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); |
1980 | 1999 |
1981 if (pos.Value() <= range->Start().Value()) return range; | 2000 if (pos.Value() <= range->Start().Value()) return range; |
1982 | 2001 |
1983 // We can't properly connect liveranges if splitting occurred at the end | 2002 // We can't properly connect liveranges if splitting occurred at the end |
1984 // a block. | 2003 // a block. |
1985 DCHECK(pos.IsStart() || pos.IsGapPosition() || | 2004 DCHECK(pos.IsStart() || pos.IsGapPosition() || |
1986 (code()->GetInstructionBlock(pos.ToInstructionIndex())) | 2005 (GetInstructionBlock(code(), pos)->last_instruction_index() != |
1987 ->last_instruction_index() != pos.ToInstructionIndex()); | 2006 pos.ToInstructionIndex())); |
1988 | 2007 |
1989 int vreg = GetVirtualRegister(); | 2008 int vreg = code()->NextVirtualRegister(); |
1990 auto result = LiveRangeFor(vreg); | 2009 auto result = LiveRangeFor(vreg); |
1991 range->SplitAt(pos, result, allocation_zone()); | 2010 range->SplitAt(pos, result, allocation_zone()); |
1992 return result; | 2011 return result; |
1993 } | 2012 } |
1994 | 2013 |
1995 | 2014 |
1996 LiveRange* LinearScanAllocator::SplitBetween(LiveRange* range, | 2015 LiveRange* LinearScanAllocator::SplitBetween(LiveRange* range, |
1997 LifetimePosition start, | 2016 LifetimePosition start, |
1998 LifetimePosition end) { | 2017 LifetimePosition end) { |
1999 DCHECK(!range->IsFixed()); | 2018 DCHECK(!range->IsFixed()); |
2000 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), | 2019 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), |
2001 start.Value(), end.Value()); | 2020 start.Value(), end.Value()); |
2002 | 2021 |
2003 auto split_pos = FindOptimalSplitPos(start, end); | 2022 auto split_pos = FindOptimalSplitPos(start, end); |
2004 DCHECK(split_pos.Value() >= start.Value()); | 2023 DCHECK(split_pos.Value() >= start.Value()); |
2005 return SplitRangeAt(range, split_pos); | 2024 return SplitRangeAt(range, split_pos); |
2006 } | 2025 } |
2007 | 2026 |
2008 | 2027 |
2009 LifetimePosition LinearScanAllocator::FindOptimalSplitPos( | 2028 LifetimePosition LinearScanAllocator::FindOptimalSplitPos( |
2010 LifetimePosition start, LifetimePosition end) { | 2029 LifetimePosition start, LifetimePosition end) { |
2011 int start_instr = start.ToInstructionIndex(); | 2030 int start_instr = start.ToInstructionIndex(); |
2012 int end_instr = end.ToInstructionIndex(); | 2031 int end_instr = end.ToInstructionIndex(); |
2013 DCHECK(start_instr <= end_instr); | 2032 DCHECK(start_instr <= end_instr); |
2014 | 2033 |
2015 // We have no choice | 2034 // We have no choice |
2016 if (start_instr == end_instr) return end; | 2035 if (start_instr == end_instr) return end; |
2017 | 2036 |
2018 auto start_block = GetInstructionBlock(start); | 2037 auto start_block = GetInstructionBlock(code(), start); |
2019 auto end_block = GetInstructionBlock(end); | 2038 auto end_block = GetInstructionBlock(code(), end); |
2020 | 2039 |
2021 if (end_block == start_block) { | 2040 if (end_block == start_block) { |
2022 // The interval is split in the same basic block. Split at the latest | 2041 // The interval is split in the same basic block. Split at the latest |
2023 // possible position. | 2042 // possible position. |
2024 return end; | 2043 return end; |
2025 } | 2044 } |
2026 | 2045 |
2027 auto block = end_block; | 2046 auto block = end_block; |
2028 // Find header of outermost loop. | 2047 // Find header of outermost loop. |
2029 // TODO(titzer): fix redundancy below. | 2048 // TODO(titzer): fix redundancy below. |
(...skipping 29 matching lines...) Expand all Loading... |
2059 LifetimePosition until, | 2078 LifetimePosition until, |
2060 LifetimePosition end) { | 2079 LifetimePosition end) { |
2061 CHECK(start.Value() < end.Value()); | 2080 CHECK(start.Value() < end.Value()); |
2062 auto second_part = SplitRangeAt(range, start); | 2081 auto second_part = SplitRangeAt(range, start); |
2063 | 2082 |
2064 if (second_part->Start().Value() < end.Value()) { | 2083 if (second_part->Start().Value() < end.Value()) { |
2065 // The split result intersects with [start, end[. | 2084 // The split result intersects with [start, end[. |
2066 // Split it at position between ]start+1, end[, spill the middle part | 2085 // Split it at position between ]start+1, end[, spill the middle part |
2067 // and put the rest to unhandled. | 2086 // and put the rest to unhandled. |
2068 auto third_part_end = end.PrevStart().End(); | 2087 auto third_part_end = end.PrevStart().End(); |
2069 if (data()->IsBlockBoundary(end.Start())) { | 2088 if (IsBlockBoundary(code(), end.Start())) { |
2070 third_part_end = end.Start(); | 2089 third_part_end = end.Start(); |
2071 } | 2090 } |
2072 auto third_part = SplitBetween( | 2091 auto third_part = SplitBetween( |
2073 second_part, Max(second_part->Start().End(), until), third_part_end); | 2092 second_part, Max(second_part->Start().End(), until), third_part_end); |
2074 | 2093 |
2075 DCHECK(third_part != second_part); | 2094 DCHECK(third_part != second_part); |
2076 | 2095 |
2077 Spill(second_part); | 2096 Spill(second_part); |
2078 AddToUnhandledSorted(third_part); | 2097 AddToUnhandledSorted(third_part); |
2079 } else { | 2098 } else { |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2334 private: | 2353 private: |
2335 size_t length_; | 2354 size_t length_; |
2336 LiveRangeBound* start_; | 2355 LiveRangeBound* start_; |
2337 | 2356 |
2338 DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray); | 2357 DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray); |
2339 }; | 2358 }; |
2340 | 2359 |
2341 | 2360 |
2342 class LiveRangeFinder { | 2361 class LiveRangeFinder { |
2343 public: | 2362 public: |
2344 explicit LiveRangeFinder(const RegisterAllocationData* data) | 2363 explicit LiveRangeFinder(const RegisterAllocationData* data, Zone* zone) |
2345 : data_(data), | 2364 : data_(data), |
2346 bounds_length_(static_cast<int>(data_->live_ranges().size())), | 2365 bounds_length_(static_cast<int>(data_->live_ranges().size())), |
2347 bounds_(data_->allocation_zone()->NewArray<LiveRangeBoundArray>( | 2366 bounds_(zone->NewArray<LiveRangeBoundArray>(bounds_length_)), |
2348 bounds_length_)) { | 2367 zone_(zone) { |
2349 for (int i = 0; i < bounds_length_; ++i) { | 2368 for (int i = 0; i < bounds_length_; ++i) { |
2350 new (&bounds_[i]) LiveRangeBoundArray(); | 2369 new (&bounds_[i]) LiveRangeBoundArray(); |
2351 } | 2370 } |
2352 } | 2371 } |
2353 | 2372 |
2354 LiveRangeBoundArray* ArrayFor(int operand_index) { | 2373 LiveRangeBoundArray* ArrayFor(int operand_index) { |
2355 DCHECK(operand_index < bounds_length_); | 2374 DCHECK(operand_index < bounds_length_); |
2356 auto range = data_->live_ranges()[operand_index]; | 2375 auto range = data_->live_ranges()[operand_index]; |
2357 DCHECK(range != nullptr && !range->IsEmpty()); | 2376 DCHECK(range != nullptr && !range->IsEmpty()); |
2358 auto array = &bounds_[operand_index]; | 2377 auto array = &bounds_[operand_index]; |
2359 if (array->ShouldInitialize()) { | 2378 if (array->ShouldInitialize()) { |
2360 array->Initialize(data_->allocation_zone(), range); | 2379 array->Initialize(zone_, range); |
2361 } | 2380 } |
2362 return array; | 2381 return array; |
2363 } | 2382 } |
2364 | 2383 |
2365 private: | 2384 private: |
2366 const RegisterAllocationData* const data_; | 2385 const RegisterAllocationData* const data_; |
2367 const int bounds_length_; | 2386 const int bounds_length_; |
2368 LiveRangeBoundArray* const bounds_; | 2387 LiveRangeBoundArray* const bounds_; |
| 2388 Zone* const zone_; |
2369 | 2389 |
2370 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); | 2390 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); |
2371 }; | 2391 }; |
2372 | 2392 |
2373 } // namespace | 2393 } // namespace |
2374 | 2394 |
2375 | 2395 |
2376 LiveRangeConnector::LiveRangeConnector(RegisterAllocationData* data) | 2396 LiveRangeConnector::LiveRangeConnector(RegisterAllocationData* data) |
2377 : data_(data) {} | 2397 : data_(data) {} |
2378 | 2398 |
2379 | 2399 |
2380 bool LiveRangeConnector::CanEagerlyResolveControlFlow( | 2400 bool LiveRangeConnector::CanEagerlyResolveControlFlow( |
2381 const InstructionBlock* block) const { | 2401 const InstructionBlock* block) const { |
2382 if (block->PredecessorCount() != 1) return false; | 2402 if (block->PredecessorCount() != 1) return false; |
2383 return block->predecessors()[0].IsNext(block->rpo_number()); | 2403 return block->predecessors()[0].IsNext(block->rpo_number()); |
2384 } | 2404 } |
2385 | 2405 |
2386 | 2406 |
2387 void LiveRangeConnector::ResolveControlFlow() { | 2407 void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { |
2388 // Lazily linearize live ranges in memory for fast lookup. | 2408 // Lazily linearize live ranges in memory for fast lookup. |
2389 LiveRangeFinder finder(data()); | 2409 LiveRangeFinder finder(data(), local_zone); |
2390 auto& live_in_sets = data()->live_in_sets(); | 2410 auto& live_in_sets = data()->live_in_sets(); |
2391 for (auto block : code()->instruction_blocks()) { | 2411 for (auto block : code()->instruction_blocks()) { |
2392 if (CanEagerlyResolveControlFlow(block)) continue; | 2412 if (CanEagerlyResolveControlFlow(block)) continue; |
2393 auto live = live_in_sets[block->rpo_number().ToInt()]; | 2413 auto live = live_in_sets[block->rpo_number().ToInt()]; |
2394 BitVector::Iterator iterator(live); | 2414 BitVector::Iterator iterator(live); |
2395 while (!iterator.Done()) { | 2415 while (!iterator.Done()) { |
2396 auto* array = finder.ArrayFor(iterator.Current()); | 2416 auto* array = finder.ArrayFor(iterator.Current()); |
2397 for (auto pred : block->predecessors()) { | 2417 for (auto pred : block->predecessors()) { |
2398 FindResult result; | 2418 FindResult result; |
2399 const auto* pred_block = code()->InstructionBlockAt(pred); | 2419 const auto* pred_block = code()->InstructionBlockAt(pred); |
(...skipping 27 matching lines...) Expand all Loading... |
2427 DCHECK(!data() | 2447 DCHECK(!data() |
2428 ->InstructionAt(pred->last_instruction_index()) | 2448 ->InstructionAt(pred->last_instruction_index()) |
2429 ->HasReferenceMap()); | 2449 ->HasReferenceMap()); |
2430 gap_index = pred->last_instruction_index(); | 2450 gap_index = pred->last_instruction_index(); |
2431 position = Instruction::END; | 2451 position = Instruction::END; |
2432 } | 2452 } |
2433 data()->AddGapMove(gap_index, position, pred_op, cur_op); | 2453 data()->AddGapMove(gap_index, position, pred_op, cur_op); |
2434 } | 2454 } |
2435 | 2455 |
2436 | 2456 |
2437 void LiveRangeConnector::ConnectRanges(Zone* temp_zone) { | 2457 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { |
2438 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> | 2458 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> |
2439 delayed_insertion_map(temp_zone); | 2459 delayed_insertion_map(local_zone); |
2440 for (auto first_range : data()->live_ranges()) { | 2460 for (auto first_range : data()->live_ranges()) { |
2441 if (first_range == nullptr || first_range->IsChild()) continue; | 2461 if (first_range == nullptr || first_range->IsChild()) continue; |
2442 for (auto second_range = first_range->next(); second_range != nullptr; | 2462 for (auto second_range = first_range->next(); second_range != nullptr; |
2443 first_range = second_range, second_range = second_range->next()) { | 2463 first_range = second_range, second_range = second_range->next()) { |
2444 auto pos = second_range->Start(); | 2464 auto pos = second_range->Start(); |
2445 // Add gap move if the two live ranges touch and there is no block | 2465 // Add gap move if the two live ranges touch and there is no block |
2446 // boundary. | 2466 // boundary. |
2447 if (second_range->IsSpilled()) continue; | 2467 if (second_range->IsSpilled()) continue; |
2448 if (first_range->End().Value() != pos.Value()) continue; | 2468 if (first_range->End().Value() != pos.Value()) continue; |
2449 if (data()->IsBlockBoundary(pos) && | 2469 if (IsBlockBoundary(code(), pos) && |
2450 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { | 2470 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { |
2451 continue; | 2471 continue; |
2452 } | 2472 } |
2453 auto prev_operand = first_range->GetAssignedOperand(); | 2473 auto prev_operand = first_range->GetAssignedOperand(); |
2454 auto cur_operand = second_range->GetAssignedOperand(); | 2474 auto cur_operand = second_range->GetAssignedOperand(); |
2455 if (prev_operand == cur_operand) continue; | 2475 if (prev_operand == cur_operand) continue; |
2456 bool delay_insertion = false; | 2476 bool delay_insertion = false; |
2457 Instruction::GapPosition gap_pos; | 2477 Instruction::GapPosition gap_pos; |
2458 int gap_index = pos.ToInstructionIndex(); | 2478 int gap_index = pos.ToInstructionIndex(); |
2459 if (pos.IsGapPosition()) { | 2479 if (pos.IsGapPosition()) { |
2460 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; | 2480 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
(...skipping 10 matching lines...) Expand all Loading... |
2471 if (!delay_insertion) { | 2491 if (!delay_insertion) { |
2472 move->AddMove(prev_operand, cur_operand); | 2492 move->AddMove(prev_operand, cur_operand); |
2473 } else { | 2493 } else { |
2474 delayed_insertion_map.insert( | 2494 delayed_insertion_map.insert( |
2475 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); | 2495 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); |
2476 } | 2496 } |
2477 } | 2497 } |
2478 } | 2498 } |
2479 if (delayed_insertion_map.empty()) return; | 2499 if (delayed_insertion_map.empty()) return; |
2480 // Insert all the moves which should occur after the stored move. | 2500 // Insert all the moves which should occur after the stored move. |
2481 ZoneVector<MoveOperands*> to_insert(temp_zone); | 2501 ZoneVector<MoveOperands*> to_insert(local_zone); |
2482 ZoneVector<MoveOperands*> to_eliminate(temp_zone); | 2502 ZoneVector<MoveOperands*> to_eliminate(local_zone); |
2483 to_insert.reserve(4); | 2503 to_insert.reserve(4); |
2484 to_eliminate.reserve(4); | 2504 to_eliminate.reserve(4); |
2485 auto moves = delayed_insertion_map.begin()->first.first; | 2505 auto moves = delayed_insertion_map.begin()->first.first; |
2486 for (auto it = delayed_insertion_map.begin();; ++it) { | 2506 for (auto it = delayed_insertion_map.begin();; ++it) { |
2487 bool done = it == delayed_insertion_map.end(); | 2507 bool done = it == delayed_insertion_map.end(); |
2488 if (done || it->first.first != moves) { | 2508 if (done || it->first.first != moves) { |
2489 // Commit the MoveOperands for current ParallelMove. | 2509 // Commit the MoveOperands for current ParallelMove. |
2490 for (auto move : to_eliminate) { | 2510 for (auto move : to_eliminate) { |
2491 move->Eliminate(); | 2511 move->Eliminate(); |
2492 } | 2512 } |
(...skipping 10 matching lines...) Expand all Loading... |
2503 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); | 2523 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); |
2504 auto eliminate = moves->PrepareInsertAfter(move); | 2524 auto eliminate = moves->PrepareInsertAfter(move); |
2505 to_insert.push_back(move); | 2525 to_insert.push_back(move); |
2506 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 2526 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
2507 } | 2527 } |
2508 } | 2528 } |
2509 | 2529 |
2510 } // namespace compiler | 2530 } // namespace compiler |
2511 } // namespace internal | 2531 } // namespace internal |
2512 } // namespace v8 | 2532 } // namespace v8 |
OLD | NEW |