| Index: src/compiler/register-allocator.cc
|
| diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
|
| index 101a10ae5b55ad4981d8c464df117d2c9d5ccae6..4c1aabd576fe35a0198208d2e89fd2b3eddfdb79 100644
|
| --- a/src/compiler/register-allocator.cc
|
| +++ b/src/compiler/register-allocator.cc
|
| @@ -253,6 +253,7 @@ LiveRange::LiveRange(int id, MachineType machine_type)
|
| first_pos_(nullptr),
|
| parent_(nullptr),
|
| next_(nullptr),
|
| + splintered_from_(nullptr),
|
| spill_operand_(nullptr),
|
| spills_at_definition_(nullptr),
|
| current_interval_(nullptr),
|
| @@ -447,9 +448,9 @@ void LiveRange::SetSpillOperand(InstructionOperand* operand) {
|
|
|
|
|
| void LiveRange::SetSpillRange(SpillRange* spill_range) {
|
| - DCHECK(HasNoSpillType() || HasSpillRange());
|
| + DCHECK(!HasSpillOperand());
|
| DCHECK(spill_range);
|
| - set_spill_type(SpillType::kSpillRange);
|
| + DCHECK(!IsChild());
|
| spill_range_ = spill_range;
|
| }
|
|
|
| @@ -668,6 +669,146 @@ void LiveRange::SplitAt(LifetimePosition position, LiveRange* result,
|
| }
|
|
|
|
|
| +void LiveRange::Splinter(LifetimePosition start, LifetimePosition end,
|
| + LiveRange* result, Zone* zone) {
|
| + DCHECK(start != Start() || end != End());
|
| + DCHECK(start < end);
|
| +
|
| + result->set_spill_type(spill_type());
|
| +
|
| + if (start <= Start()) {
|
| + DCHECK(end < End());
|
| + SplitAt(end, result, zone);
|
| + next_ = nullptr;
|
| + } else if (end >= End()) {
|
| + DCHECK(start > Start());
|
| + SplitAt(start, result, zone);
|
| + next_ = nullptr;
|
| + } else {
|
| + DCHECK(start < End() && Start() < end);
|
| +
|
| + const int kInvalidId = std::numeric_limits<int>::max();
|
| +
|
| + SplitAt(start, result, zone);
|
| +
|
| + LiveRange end_part(kInvalidId, this->machine_type());
|
| + result->SplitAt(end, &end_part, zone);
|
| +
|
| + next_ = end_part.next_;
|
| + last_interval_->set_next(end_part.first_interval_);
|
| + last_interval_ = end_part.last_interval_;
|
| +
|
| +
|
| + if (first_pos_ == nullptr) {
|
| + first_pos_ = end_part.first_pos_;
|
| + } else {
|
| + UsePosition* pos = first_pos_;
|
| + for (; pos->next() != nullptr; pos = pos->next()) {
|
| + }
|
| + pos->set_next(end_part.first_pos_);
|
| + }
|
| + }
|
| + result->next_ = nullptr;
|
| + result->parent_ = nullptr;
|
| +
|
| + result->SetSplinteredFrom(this);
|
| +}
|
| +
|
| +
|
| +void LiveRange::SetSplinteredFrom(LiveRange* splinter_parent) {
|
| + // The splinter parent is always the original "Top".
|
| + DCHECK(splinter_parent->Start() < Start());
|
| + DCHECK(!splinter_parent->IsChild());
|
| +
|
| + splintered_from_ = splinter_parent;
|
| + if (!HasSpillOperand()) {
|
| + SetSpillRange(splinter_parent->spill_range_);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LiveRange::AppendChild(LiveRange* other) {
|
| + DCHECK(!other->IsChild());
|
| + next_ = other;
|
| +
|
| + other->UpdateParentForAllChildren(TopLevel());
|
| + TopLevel()->UpdateSpillRangePostMerge(other);
|
| +}
|
| +
|
| +
|
| +void LiveRange::UpdateSpillRangePostMerge(LiveRange* merged) {
|
| + DCHECK(!IsChild());
|
| + DCHECK(merged->TopLevel() == this);
|
| +
|
| + if (HasNoSpillType() && merged->HasSpillRange()) {
|
| + set_spill_type(merged->spill_type());
|
| + DCHECK(GetSpillRange()->live_ranges().size() > 0);
|
| + merged->spill_range_ = nullptr;
|
| + merged->bits_ = SpillTypeField::update(merged->bits_,
|
| + LiveRange::SpillType::kNoSpillType);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LiveRange::UpdateParentForAllChildren(LiveRange* new_parent) {
|
| + LiveRange* child = this;
|
| + for (; child != nullptr; child = child->next()) {
|
| + child->parent_ = new_parent;
|
| + }
|
| +}
|
| +
|
| +
|
| +LiveRange* LiveRange::GetLastChild() {
|
| + LiveRange* ret = this;
|
| + for (; ret->next() != nullptr; ret = ret->next()) {
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +
|
| +void LiveRange::Merge(LiveRange* other, RegisterAllocationData* data) {
|
| + DCHECK(!IsChild());
|
| + DCHECK(!other->IsChild());
|
| + DCHECK(Start() < other->Start());
|
| +
|
| + LiveRange* last_other = other->GetLastChild();
|
| + LiveRange* last_me = GetLastChild();
|
| +
|
| + // Simple case: we just append at the end.
|
| + if (last_me->End() <= other->Start()) return last_me->AppendChild(other);
|
| +
|
| + DCHECK(last_me->End() > last_other->End());
|
| +
|
| + // In the more general case, we need to find the ranges between which to
|
| + // insert.
|
| + LiveRange* insertion_point = this;
|
| + for (; insertion_point->next() != nullptr &&
|
| + insertion_point->next()->Start() <= other->Start();
|
| + insertion_point = insertion_point->next()) {
|
| + }
|
| +
|
| + // When we splintered the original range, we reconstituted the original range
|
| + // into one range without children, but with discontinuities. To merge the
|
| + // splinter back in, we need to split the range - or a child obtained after
|
| + // register allocation splitting.
|
| + LiveRange* after = insertion_point->next();
|
| + if (insertion_point->End() > other->Start()) {
|
| + LiveRange* new_after = data->NewChildRangeFor(insertion_point);
|
| + insertion_point->SplitAt(other->Start(), new_after,
|
| + data->allocation_zone());
|
| + new_after->set_spilled(insertion_point->spilled());
|
| + if (!new_after->spilled())
|
| + new_after->set_assigned_register(insertion_point->assigned_register());
|
| + after = new_after;
|
| + }
|
| +
|
| + last_other->next_ = after;
|
| + insertion_point->next_ = other;
|
| + other->UpdateParentForAllChildren(TopLevel());
|
| + TopLevel()->UpdateSpillRangePostMerge(other);
|
| +}
|
| +
|
| +
|
| // This implements an ordering on live ranges so that they are ordered by their
|
| // start positions. This is needed for the correctness of the register
|
| // allocation algorithm. If two live ranges start at the same offset then there
|
| @@ -913,8 +1054,15 @@ std::ostream& operator<<(std::ostream& os,
|
|
|
|
|
| SpillRange::SpillRange(LiveRange* parent, Zone* zone)
|
| - : live_ranges_(zone), assigned_slot_(kUnassignedSlot) {
|
| + : live_ranges_(zone),
|
| + assigned_slot_(kUnassignedSlot),
|
| + byte_width_(GetByteWidth(parent->machine_type())),
|
| + kind_(parent->kind()) {
|
| + // Spill ranges are created for top level, non-splintered ranges. This is so
|
| + // that, when merging decisions are made, we consider the full extent of the
|
| + // virtual register, and avoid clobbering it.
|
| DCHECK(!parent->IsChild());
|
| + DCHECK(!parent->IsSplinter());
|
| UseInterval* result = nullptr;
|
| UseInterval* node = nullptr;
|
| // Copy the intervals for all ranges.
|
| @@ -934,7 +1082,6 @@ SpillRange::SpillRange(LiveRange* parent, Zone* zone)
|
| use_interval_ = result;
|
| live_ranges().push_back(parent);
|
| end_position_ = node->end();
|
| - DCHECK(!parent->HasSpillRange());
|
| parent->SetSpillRange(this);
|
| }
|
|
|
| @@ -1056,7 +1203,6 @@ RegisterAllocationData::RegisterAllocationData(
|
| RegisterConfiguration::kMaxGeneralRegisters);
|
| DCHECK(this->config()->num_double_registers() <=
|
| RegisterConfiguration::kMaxDoubleRegisters);
|
| - spill_ranges().reserve(8);
|
| assigned_registers_ = new (code_zone())
|
| BitVector(this->config()->num_general_registers(), code_zone());
|
| assigned_double_registers_ = new (code_zone())
|
| @@ -1100,14 +1246,20 @@ LiveRange* RegisterAllocationData::NewLiveRange(int index,
|
| }
|
|
|
|
|
| -LiveRange* RegisterAllocationData::NewChildRangeFor(LiveRange* range) {
|
| +LiveRange* RegisterAllocationData::NextLiveRange(MachineType machine_type) {
|
| int vreg = virtual_register_count_++;
|
| if (vreg >= static_cast<int>(live_ranges().size())) {
|
| live_ranges().resize(vreg + 1, nullptr);
|
| }
|
| - auto child = new (allocation_zone()) LiveRange(vreg, range->machine_type());
|
| - DCHECK_NULL(live_ranges()[vreg]);
|
| - live_ranges()[vreg] = child;
|
| + LiveRange* ret = NewLiveRange(vreg, machine_type);
|
| + return ret;
|
| +}
|
| +
|
| +
|
| +LiveRange* RegisterAllocationData::NewChildRangeFor(LiveRange* range) {
|
| + auto child = NextLiveRange(range->machine_type());
|
| + DCHECK_NULL(live_ranges()[child->id()]);
|
| + live_ranges()[child->id()] = child;
|
| return child;
|
| }
|
|
|
| @@ -1155,9 +1307,28 @@ bool RegisterAllocationData::ExistsUseWithoutDefinition() {
|
|
|
| SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange(
|
| LiveRange* range) {
|
| + DCHECK(!range->IsChild());
|
| + DCHECK(!range->HasSpillOperand());
|
| +
|
| + SpillRange* spill_range = range->GetAllocatedSpillRange();
|
| + if (spill_range == nullptr) {
|
| + DCHECK(!range->IsSplinter());
|
| + spill_range = new (allocation_zone()) SpillRange(range, allocation_zone());
|
| + }
|
| + range->set_spill_type(LiveRange::SpillType::kSpillRange);
|
| +
|
| + spill_ranges().insert(spill_range);
|
| + return spill_range;
|
| +}
|
| +
|
| +
|
| +SpillRange* RegisterAllocationData::CreateSpillRangeForLiveRange(
|
| + LiveRange* range) {
|
| + DCHECK(!range->HasSpillOperand());
|
| + DCHECK(!range->IsChild());
|
| + DCHECK(!range->IsSplinter());
|
| auto spill_range =
|
| new (allocation_zone()) SpillRange(range, allocation_zone());
|
| - spill_ranges().push_back(spill_range);
|
| return spill_range;
|
| }
|
|
|
| @@ -1230,6 +1401,23 @@ void RegisterAllocationData::Print(const MoveOperands* move) {
|
| }
|
|
|
|
|
| +void RegisterAllocationData::Print(const SpillRange* spill_range) {
|
| + OFStream os(stdout);
|
| + os << "{" << std::endl;
|
| + for (LiveRange* range : spill_range->live_ranges()) {
|
| + os << range->id() << " ";
|
| + }
|
| + os << std::endl;
|
| +
|
| + for (UseInterval* interval = spill_range->interval(); interval != nullptr;
|
| + interval = interval->next()) {
|
| + os << '[' << interval->start() << ", " << interval->end() << ')'
|
| + << std::endl;
|
| + }
|
| + os << "}" << std::endl;
|
| +}
|
| +
|
| +
|
| ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data)
|
| : data_(data) {}
|
|
|
| @@ -1474,22 +1662,25 @@ LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data,
|
| : data_(data), phi_hints_(local_zone) {}
|
|
|
|
|
| -BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) {
|
| +BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block,
|
| + RegisterAllocationData* data) {
|
| // Compute live out for the given block, except not including backward
|
| // successor edges.
|
| - auto live_out = new (allocation_zone())
|
| - BitVector(code()->VirtualRegisterCount(), allocation_zone());
|
| + Zone* zone = data->allocation_zone();
|
| + const InstructionSequence* code = data->code();
|
| +
|
| + auto live_out = new (zone) BitVector(code->VirtualRegisterCount(), zone);
|
|
|
| // Process all successor blocks.
|
| for (auto succ : block->successors()) {
|
| - // Add values live on entry to the successor. Note the successor's
|
| - // live_in will not be computed yet for backwards edges.
|
| - auto live_in = live_in_sets()[succ.ToSize()];
|
| + // Add values live on entry to the successor.
|
| + if (succ <= block->rpo_number()) continue;
|
| + auto live_in = data->live_in_sets()[succ.ToSize()];
|
| if (live_in != nullptr) live_out->Union(*live_in);
|
|
|
| // All phi input operands corresponding to this successor edge are live
|
| // out from this block.
|
| - auto successor = code()->InstructionBlockAt(succ);
|
| + auto successor = code->InstructionBlockAt(succ);
|
| size_t index = successor->PredecessorIndexOf(block->rpo_number());
|
| DCHECK(index < successor->PredecessorCount());
|
| for (auto phi : successor->phis()) {
|
| @@ -1834,7 +2025,7 @@ void LiveRangeBuilder::BuildLiveRanges() {
|
| for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0;
|
| --block_id) {
|
| auto block = code()->InstructionBlockAt(RpoNumber::FromInt(block_id));
|
| - auto live = ComputeLiveOut(block);
|
| + auto live = ComputeLiveOut(block, data());
|
| // Initially consider all live_out values live for the entire block. We
|
| // will shorten these intervals if necessary.
|
| AddInitialIntervals(block, live);
|
| @@ -2597,13 +2788,15 @@ OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {}
|
|
|
|
|
| void OperandAssigner::AssignSpillSlots() {
|
| - auto& spill_ranges = data()->spill_ranges();
|
| + ZoneSet<SpillRange*>& spill_ranges = data()->spill_ranges();
|
| // Merge disjoint spill ranges
|
| - for (size_t i = 0; i < spill_ranges.size(); i++) {
|
| - auto range = spill_ranges[i];
|
| + for (auto i = spill_ranges.begin(), end = spill_ranges.end(); i != end; ++i) {
|
| + SpillRange* range = *i;
|
| if (range->IsEmpty()) continue;
|
| - for (size_t j = i + 1; j < spill_ranges.size(); j++) {
|
| - auto other = spill_ranges[j];
|
| + auto j = i;
|
| + j++;
|
| + for (; j != end; ++j) {
|
| + SpillRange* other = *j;
|
| if (!other->IsEmpty()) {
|
| range->TryMerge(other);
|
| }
|
|
|