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

Unified Diff: src/compiler/register-allocator.cc

Issue 1305393003: [turbofan] Deferred blocks splintering. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/register-allocator.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
« no previous file with comments | « src/compiler/register-allocator.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698