| Index: src/compiler/register-allocator.cc
|
| diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
|
| index 924a53e7bd7421bc20a51bff0817530d797224ce..c96a7e94f7fe333ecb78d546b27d90a40f012ba6 100644
|
| --- a/src/compiler/register-allocator.cc
|
| +++ b/src/compiler/register-allocator.cc
|
| @@ -34,6 +34,41 @@ void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) {
|
| v->erase(it);
|
| }
|
|
|
| +
|
| +int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) {
|
| + return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers()
|
| + : cfg->num_general_registers();
|
| +}
|
| +
|
| +
|
| +const ZoneVector<LiveRange*>& GetFixedRegisters(
|
| + const RegisterAllocationData* data, RegisterKind kind) {
|
| + return kind == DOUBLE_REGISTERS ? data->fixed_double_live_ranges()
|
| + : data->fixed_live_ranges();
|
| +}
|
| +
|
| +
|
| +const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence,
|
| + const InstructionBlock* block) {
|
| + auto index = block->loop_header();
|
| + if (!index.IsValid()) return nullptr;
|
| + return sequence->InstructionBlockAt(index);
|
| +}
|
| +
|
| +
|
| +const InstructionBlock* GetInstructionBlock(const InstructionSequence* code,
|
| + LifetimePosition pos) {
|
| + return code->GetInstructionBlock(pos.ToInstructionIndex());
|
| +}
|
| +
|
| +
|
| +bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) {
|
| + return pos.IsFullStart() &&
|
| + code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() ==
|
| + pos.ToInstructionIndex();
|
| +}
|
| +
|
| +
|
| } // namespace
|
|
|
|
|
| @@ -90,7 +125,7 @@ struct LiveRange::SpillAtDefinitionList : ZoneObject {
|
| };
|
|
|
|
|
| -LiveRange::LiveRange(int id, Zone* zone)
|
| +LiveRange::LiveRange(int id)
|
| : id_(id),
|
| spilled_(false),
|
| has_slot_use_(false),
|
| @@ -369,7 +404,7 @@ void LiveRange::SplitAt(LifetimePosition position, LiveRange* result,
|
|
|
| // Partition original use positions to the two live ranges.
|
| if (use_before != nullptr) {
|
| - use_before->next_ = nullptr;
|
| + use_before->set_next(nullptr);
|
| } else {
|
| first_pos_ = nullptr;
|
| }
|
| @@ -436,7 +471,7 @@ void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end,
|
| }
|
|
|
| auto new_interval = new (zone) UseInterval(start, new_end);
|
| - new_interval->next_ = first_interval_;
|
| + new_interval->set_next(first_interval_);
|
| first_interval_ = new_interval;
|
| if (new_interval->next() == nullptr) {
|
| last_interval_ = new_interval;
|
| @@ -464,8 +499,8 @@ void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end,
|
| // that each new use interval either precedes or intersects with
|
| // last added interval.
|
| DCHECK(start.Value() < first_interval_->end().Value());
|
| - first_interval_->start_ = Min(start, first_interval_->start_);
|
| - first_interval_->end_ = Max(end, first_interval_->end_);
|
| + first_interval_->set_start(Min(start, first_interval_->start()));
|
| + first_interval_->set_end(Max(end, first_interval_->end()));
|
| }
|
| }
|
| }
|
| @@ -489,8 +524,8 @@ void LiveRange::AddUsePosition(LifetimePosition pos,
|
| use_pos->set_next(first_pos_);
|
| first_pos_ = use_pos;
|
| } else {
|
| - use_pos->next_ = prev->next_;
|
| - prev->next_ = use_pos;
|
| + use_pos->set_next(prev->next());
|
| + prev->set_next(use_pos);
|
| }
|
|
|
| if (prev_hint == nullptr && use_pos->HasHint()) {
|
| @@ -748,10 +783,7 @@ void RegisterAllocationData::AssignPhiInput(
|
|
|
|
|
| LiveRange* RegisterAllocationData::NewLiveRange(int index) {
|
| - // The LiveRange object itself can go in the local zone, but the
|
| - // InstructionOperand needs to go in the code zone, since it may survive
|
| - // register allocation.
|
| - return new (allocation_zone()) LiveRange(index, code_zone());
|
| + return new (allocation_zone()) LiveRange(index);
|
| }
|
|
|
|
|
| @@ -1395,7 +1427,7 @@ void LiveRangeBuilder::BuildLiveRanges() {
|
| // Without this hack, all uses with "any" policy would get the constant
|
| // operand assigned.
|
| if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) {
|
| - for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) {
|
| + for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) {
|
| if (pos->type() == UsePositionType::kRequiresSlot) continue;
|
| UsePositionType new_type = UsePositionType::kAny;
|
| // Can't mark phis as needing a register.
|
| @@ -1428,15 +1460,13 @@ void LiveRangeBuilder::Verify() const {
|
|
|
|
|
| LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
|
| - RegisterKind kind)
|
| + RegisterKind kind, Zone* local_zone)
|
| : data_(data),
|
| mode_(kind),
|
| - num_registers_(kind == DOUBLE_REGISTERS
|
| - ? config()->num_aliased_double_registers()
|
| - : config()->num_general_registers()),
|
| - unhandled_live_ranges_(allocation_zone()),
|
| - active_live_ranges_(allocation_zone()),
|
| - inactive_live_ranges_(allocation_zone()) {
|
| + num_registers_(GetRegisterCount(data->config(), kind)),
|
| + unhandled_live_ranges_(local_zone),
|
| + active_live_ranges_(local_zone),
|
| + inactive_live_ranges_(local_zone) {
|
| unhandled_live_ranges().reserve(
|
| static_cast<size_t>(code()->VirtualRegisterCount() * 2));
|
| active_live_ranges().reserve(8);
|
| @@ -1463,14 +1493,11 @@ void LinearScanAllocator::AllocateRegisters() {
|
| DCHECK(active_live_ranges().empty());
|
| DCHECK(inactive_live_ranges().empty());
|
|
|
| - if (mode_ == DOUBLE_REGISTERS) {
|
| - for (auto current : fixed_double_live_ranges()) {
|
| - if (current != nullptr) AddToInactive(current);
|
| - }
|
| - } else {
|
| - DCHECK(mode_ == GENERAL_REGISTERS);
|
| - for (auto current : fixed_live_ranges()) {
|
| - if (current != nullptr) AddToInactive(current);
|
| + auto& fixed_ranges = GetFixedRegisters(data(), mode_);
|
| + for (auto current : fixed_ranges) {
|
| + if (current != nullptr) {
|
| + DCHECK_EQ(mode_, current->Kind());
|
| + AddToInactive(current);
|
| }
|
| }
|
|
|
| @@ -1544,7 +1571,7 @@ void LinearScanAllocator::AllocateRegisters() {
|
| }
|
|
|
|
|
| -const char* LinearScanAllocator::RegisterName(int allocation_index) {
|
| +const char* LinearScanAllocator::RegisterName(int allocation_index) const {
|
| if (mode_ == GENERAL_REGISTERS) {
|
| return config()->general_register_name(allocation_index);
|
| } else {
|
| @@ -1651,7 +1678,7 @@ void LinearScanAllocator::InactiveToActive(LiveRange* range) {
|
| bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
| LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters];
|
|
|
| - for (int i = 0; i < num_registers_; i++) {
|
| + for (int i = 0; i < num_registers(); i++) {
|
| free_until_pos[i] = LifetimePosition::MaxPosition();
|
| }
|
|
|
| @@ -1679,14 +1706,14 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
| if (free_until_pos[register_index].Value() >= current->End().Value()) {
|
| TRACE("Assigning preferred reg %s to live range %d\n",
|
| RegisterName(register_index), current->id());
|
| - SetLiveRangeAssignedRegister(current, register_index);
|
| + data()->SetLiveRangeAssignedRegister(current, register_index);
|
| return true;
|
| }
|
| }
|
|
|
| // Find the register which stays free for the longest time.
|
| int reg = 0;
|
| - for (int i = 1; i < RegisterCount(); ++i) {
|
| + for (int i = 1; i < num_registers(); ++i) {
|
| if (free_until_pos[i].Value() > free_until_pos[reg].Value()) {
|
| reg = i;
|
| }
|
| @@ -1711,7 +1738,7 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
|
| DCHECK(pos.Value() >= current->End().Value());
|
| TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg),
|
| current->id());
|
| - SetLiveRangeAssignedRegister(current, reg);
|
| + data()->SetLiveRangeAssignedRegister(current, reg);
|
|
|
| return true;
|
| }
|
| @@ -1729,7 +1756,7 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
| LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters];
|
| LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters];
|
|
|
| - for (int i = 0; i < num_registers_; i++) {
|
| + for (int i = 0; i < num_registers(); i++) {
|
| use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
|
| }
|
|
|
| @@ -1763,7 +1790,7 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
| }
|
|
|
| int reg = 0;
|
| - for (int i = 1; i < RegisterCount(); ++i) {
|
| + for (int i = 1; i < num_registers(); ++i) {
|
| if (use_pos[i].Value() > use_pos[reg].Value()) {
|
| reg = i;
|
| }
|
| @@ -1790,7 +1817,7 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
| DCHECK(block_pos[reg].Value() >= current->End().Value());
|
| TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
|
| current->id());
|
| - SetLiveRangeAssignedRegister(current, reg);
|
| + data()->SetLiveRangeAssignedRegister(current, reg);
|
|
|
| // This register was not free. Thus we need to find and spill
|
| // parts of active and inactive live regions that use the same register
|
| @@ -1799,17 +1826,9 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
| }
|
|
|
|
|
| -static const InstructionBlock* GetContainingLoop(
|
| - const InstructionSequence* sequence, const InstructionBlock* block) {
|
| - auto index = block->loop_header();
|
| - if (!index.IsValid()) return nullptr;
|
| - return sequence->InstructionBlockAt(index);
|
| -}
|
| -
|
| -
|
| LifetimePosition LinearScanAllocator::FindOptimalSpillingPos(
|
| LiveRange* range, LifetimePosition pos) {
|
| - auto block = GetInstructionBlock(pos.Start());
|
| + auto block = GetInstructionBlock(code(), pos.Start());
|
| auto loop_header =
|
| block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
|
|
|
| @@ -1901,7 +1920,7 @@ bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) {
|
| for (size_t i = 0; i < phi->operands().size(); i++) {
|
| int op = phi->operands()[i];
|
| LiveRange* op_range = LiveRangeFor(op);
|
| - if (op_range->GetSpillRange() == nullptr) continue;
|
| + if (!op_range->HasSpillRange()) continue;
|
| auto pred = code()->InstructionBlockAt(block->predecessors()[i]);
|
| auto pred_end = LifetimePosition::InstructionFromInstructionIndex(
|
| pred->last_instruction_index());
|
| @@ -1929,9 +1948,9 @@ bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) {
|
| for (size_t i = 1; i < phi->operands().size(); i++) {
|
| int op = phi->operands()[i];
|
| auto op_range = LiveRangeFor(op);
|
| + if (!op_range->HasSpillRange()) continue;
|
| auto op_spill = op_range->GetSpillRange();
|
| - if (op_spill != nullptr &&
|
| - (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) {
|
| + if (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill)) {
|
| num_merged++;
|
| }
|
| }
|
| @@ -1983,10 +2002,10 @@ LiveRange* LinearScanAllocator::SplitRangeAt(LiveRange* range,
|
| // We can't properly connect liveranges if splitting occurred at the end
|
| // a block.
|
| DCHECK(pos.IsStart() || pos.IsGapPosition() ||
|
| - (code()->GetInstructionBlock(pos.ToInstructionIndex()))
|
| - ->last_instruction_index() != pos.ToInstructionIndex());
|
| + (GetInstructionBlock(code(), pos)->last_instruction_index() !=
|
| + pos.ToInstructionIndex()));
|
|
|
| - int vreg = GetVirtualRegister();
|
| + int vreg = code()->NextVirtualRegister();
|
| auto result = LiveRangeFor(vreg);
|
| range->SplitAt(pos, result, allocation_zone());
|
| return result;
|
| @@ -2015,8 +2034,8 @@ LifetimePosition LinearScanAllocator::FindOptimalSplitPos(
|
| // We have no choice
|
| if (start_instr == end_instr) return end;
|
|
|
| - auto start_block = GetInstructionBlock(start);
|
| - auto end_block = GetInstructionBlock(end);
|
| + auto start_block = GetInstructionBlock(code(), start);
|
| + auto end_block = GetInstructionBlock(code(), end);
|
|
|
| if (end_block == start_block) {
|
| // The interval is split in the same basic block. Split at the latest
|
| @@ -2066,7 +2085,7 @@ void LinearScanAllocator::SpillBetweenUntil(LiveRange* range,
|
| // Split it at position between ]start+1, end[, spill the middle part
|
| // and put the rest to unhandled.
|
| auto third_part_end = end.PrevStart().End();
|
| - if (data()->IsBlockBoundary(end.Start())) {
|
| + if (IsBlockBoundary(code(), end.Start())) {
|
| third_part_end = end.Start();
|
| }
|
| auto third_part = SplitBetween(
|
| @@ -2341,11 +2360,11 @@ class LiveRangeBoundArray {
|
|
|
| class LiveRangeFinder {
|
| public:
|
| - explicit LiveRangeFinder(const RegisterAllocationData* data)
|
| + explicit LiveRangeFinder(const RegisterAllocationData* data, Zone* zone)
|
| : data_(data),
|
| bounds_length_(static_cast<int>(data_->live_ranges().size())),
|
| - bounds_(data_->allocation_zone()->NewArray<LiveRangeBoundArray>(
|
| - bounds_length_)) {
|
| + bounds_(zone->NewArray<LiveRangeBoundArray>(bounds_length_)),
|
| + zone_(zone) {
|
| for (int i = 0; i < bounds_length_; ++i) {
|
| new (&bounds_[i]) LiveRangeBoundArray();
|
| }
|
| @@ -2357,7 +2376,7 @@ class LiveRangeFinder {
|
| DCHECK(range != nullptr && !range->IsEmpty());
|
| auto array = &bounds_[operand_index];
|
| if (array->ShouldInitialize()) {
|
| - array->Initialize(data_->allocation_zone(), range);
|
| + array->Initialize(zone_, range);
|
| }
|
| return array;
|
| }
|
| @@ -2366,6 +2385,7 @@ class LiveRangeFinder {
|
| const RegisterAllocationData* const data_;
|
| const int bounds_length_;
|
| LiveRangeBoundArray* const bounds_;
|
| + Zone* const zone_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder);
|
| };
|
| @@ -2384,9 +2404,9 @@ bool LiveRangeConnector::CanEagerlyResolveControlFlow(
|
| }
|
|
|
|
|
| -void LiveRangeConnector::ResolveControlFlow() {
|
| +void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) {
|
| // Lazily linearize live ranges in memory for fast lookup.
|
| - LiveRangeFinder finder(data());
|
| + LiveRangeFinder finder(data(), local_zone);
|
| auto& live_in_sets = data()->live_in_sets();
|
| for (auto block : code()->instruction_blocks()) {
|
| if (CanEagerlyResolveControlFlow(block)) continue;
|
| @@ -2434,9 +2454,9 @@ void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block,
|
| }
|
|
|
|
|
| -void LiveRangeConnector::ConnectRanges(Zone* temp_zone) {
|
| +void LiveRangeConnector::ConnectRanges(Zone* local_zone) {
|
| ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand>
|
| - delayed_insertion_map(temp_zone);
|
| + delayed_insertion_map(local_zone);
|
| for (auto first_range : data()->live_ranges()) {
|
| if (first_range == nullptr || first_range->IsChild()) continue;
|
| for (auto second_range = first_range->next(); second_range != nullptr;
|
| @@ -2446,8 +2466,8 @@ void LiveRangeConnector::ConnectRanges(Zone* temp_zone) {
|
| // boundary.
|
| if (second_range->IsSpilled()) continue;
|
| if (first_range->End().Value() != pos.Value()) continue;
|
| - if (data()->IsBlockBoundary(pos) &&
|
| - !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) {
|
| + if (IsBlockBoundary(code(), pos) &&
|
| + !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) {
|
| continue;
|
| }
|
| auto prev_operand = first_range->GetAssignedOperand();
|
| @@ -2478,8 +2498,8 @@ void LiveRangeConnector::ConnectRanges(Zone* temp_zone) {
|
| }
|
| if (delayed_insertion_map.empty()) return;
|
| // Insert all the moves which should occur after the stored move.
|
| - ZoneVector<MoveOperands*> to_insert(temp_zone);
|
| - ZoneVector<MoveOperands*> to_eliminate(temp_zone);
|
| + ZoneVector<MoveOperands*> to_insert(local_zone);
|
| + ZoneVector<MoveOperands*> to_eliminate(local_zone);
|
| to_insert.reserve(4);
|
| to_eliminate.reserve(4);
|
| auto moves = delayed_insertion_map.begin()->first.first;
|
|
|