Commit 3e2e2062 authored by mtrofin's avatar mtrofin Committed by Commit bot

[Turbofan] Re-enable single splinter.

Revert "Revert of [turbofan] Splinter into one range.
(patchset #2 id:80001 of https://codereview.chromium.org/1391023007/ )"

This reverts commit 23a8837f.

Also added a CHECK in Merge to validate that splitting yields a different
range and thus advances the algorithm. Ran stress bots successfully. Likely my earlier change in Splintering addressed the stress test scenario
that was looping infinitely.

BUG=

Review URL: https://codereview.chromium.org/1406983004

Cr-Commit-Position: refs/heads/master@{#31430}
parent d2dd8fbd
...@@ -608,7 +608,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { ...@@ -608,7 +608,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
// jump). Generating a single Merge here, which joins all the deoptimizing // jump). Generating a single Merge here, which joins all the deoptimizing
// controls would generate a lot of these basic blocks, however. So this // controls would generate a lot of these basic blocks, however. So this
// is disabled for now until splintering is fixed. // is disabled for now until splintering is fixed.
#if 0 #if 1
// Generate the single "exit" point, where we get if either all map/instance // Generate the single "exit" point, where we get if either all map/instance
// type checks failed, or one of the assumptions inside one of the cases // type checks failed, or one of the assumptions inside one of the cases
// failes (i.e. failing prototype chain check). // failes (i.e. failing prototype chain check).
......
...@@ -44,12 +44,14 @@ void CreateSplinter(TopLevelLiveRange *range, RegisterAllocationData *data, ...@@ -44,12 +44,14 @@ void CreateSplinter(TopLevelLiveRange *range, RegisterAllocationData *data,
if (range->MayRequireSpillRange()) { if (range->MayRequireSpillRange()) {
data->CreateSpillRangeForLiveRange(range); data->CreateSpillRangeForLiveRange(range);
} }
TopLevelLiveRange *result = data->NextLiveRange(range->machine_type()); if (range->splinter() == nullptr) {
DCHECK_NULL(data->live_ranges()[result->vreg()]); TopLevelLiveRange *splinter = data->NextLiveRange(range->machine_type());
data->live_ranges()[result->vreg()] = result; DCHECK_NULL(data->live_ranges()[splinter->vreg()]);
data->live_ranges()[splinter->vreg()] = splinter;
range->SetSplinter(splinter);
}
Zone *zone = data->allocation_zone(); Zone *zone = data->allocation_zone();
range->Splinter(start, end, result, zone); range->Splinter(start, end, zone);
} }
} }
......
...@@ -698,7 +698,8 @@ TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineType machine_type) ...@@ -698,7 +698,8 @@ TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineType machine_type)
spilled_in_deferred_blocks_(false), spilled_in_deferred_blocks_(false),
spill_start_index_(kMaxInt), spill_start_index_(kMaxInt),
last_child_(this), last_child_(this),
last_insertion_point_(this) { last_pos_(nullptr),
splinter_(nullptr) {
bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); bits_ |= SpillTypeField::encode(SpillType::kNoSpillType);
} }
...@@ -845,12 +846,12 @@ AllocatedOperand TopLevelLiveRange::GetSpillRangeOperand() const { ...@@ -845,12 +846,12 @@ AllocatedOperand TopLevelLiveRange::GetSpillRangeOperand() const {
void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end,
TopLevelLiveRange* result, Zone* zone) { Zone* zone) {
DCHECK(start != Start() || end != End()); DCHECK(start != Start() || end != End());
DCHECK(start < end); DCHECK(start < end);
result->set_spill_type(spill_type()); TopLevelLiveRange splinter_temp(-1, machine_type());
UsePosition* last_in_splinter = nullptr;
if (start <= Start()) { if (start <= Start()) {
// TODO(mtrofin): here, the TopLevel part is in the deferred range, so we // TODO(mtrofin): here, the TopLevel part is in the deferred range, so we
// may want to continue processing the splinter. However, if the value is // may want to continue processing the splinter. However, if the value is
...@@ -859,21 +860,21 @@ void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, ...@@ -859,21 +860,21 @@ void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end,
// should check this, however, this may not be the place, because we don't // should check this, however, this may not be the place, because we don't
// have access to the instruction sequence. // have access to the instruction sequence.
DCHECK(end < End()); DCHECK(end < End());
DetachAt(end, result, zone); DetachAt(end, &splinter_temp, zone);
next_ = nullptr; next_ = nullptr;
} else if (end >= End()) { } else if (end >= End()) {
DCHECK(start > Start()); DCHECK(start > Start());
DetachAt(start, result, zone); DetachAt(start, &splinter_temp, zone);
next_ = nullptr; next_ = nullptr;
} else { } else {
DCHECK(start < End() && Start() < end); DCHECK(start < End() && Start() < end);
const int kInvalidId = std::numeric_limits<int>::max(); const int kInvalidId = std::numeric_limits<int>::max();
UsePosition* last = DetachAt(start, result, zone); UsePosition* last = DetachAt(start, &splinter_temp, zone);
LiveRange end_part(kInvalidId, this->machine_type(), nullptr); LiveRange end_part(kInvalidId, this->machine_type(), nullptr);
result->DetachAt(end, &end_part, zone); last_in_splinter = splinter_temp.DetachAt(end, &end_part, zone);
next_ = end_part.next_; next_ = end_part.next_;
last_interval_->set_next(end_part.first_interval_); last_interval_->set_next(end_part.first_interval_);
...@@ -890,20 +891,39 @@ void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, ...@@ -890,20 +891,39 @@ void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end,
if (last != nullptr) last->set_next(end_part.first_pos_); if (last != nullptr) last->set_next(end_part.first_pos_);
} }
} }
result->next_ = nullptr;
result->top_level_ = result;
result->SetSplinteredFrom(this); if (splinter()->IsEmpty()) {
// Ensure the result's relative ID is unique within the IDs used for this splinter()->first_interval_ = splinter_temp.first_interval_;
// virtual register's children and splinters. splinter()->last_interval_ = splinter_temp.last_interval_;
result->relative_id_ = GetNextChildId(); } else {
splinter()->last_interval_->set_next(splinter_temp.first_interval_);
splinter()->last_interval_ = splinter_temp.last_interval_;
}
if (splinter()->first_pos() == nullptr) {
splinter()->first_pos_ = splinter_temp.first_pos_;
} else {
splinter()->last_pos_->set_next(splinter_temp.first_pos_);
}
if (last_in_splinter != nullptr) {
splinter()->last_pos_ = last_in_splinter;
} else {
if (splinter()->first_pos() != nullptr &&
splinter()->last_pos_ == nullptr) {
splinter()->last_pos_ = splinter()->first_pos();
for (UsePosition* pos = splinter()->first_pos(); pos != nullptr;
pos = pos->next()) {
splinter()->last_pos_ = pos;
}
}
}
#if DEBUG
Verify();
splinter()->Verify();
#endif
} }
void TopLevelLiveRange::SetSplinteredFrom(TopLevelLiveRange* splinter_parent) { void TopLevelLiveRange::SetSplinteredFrom(TopLevelLiveRange* splinter_parent) {
// The splinter parent is always the original "Top".
DCHECK(splinter_parent->Start() < Start());
splintered_from_ = splinter_parent; splintered_from_ = splinter_parent;
if (!HasSpillOperand() && splinter_parent->spill_range_ != nullptr) { if (!HasSpillOperand() && splinter_parent->spill_range_ != nullptr) {
SetSpillRange(splinter_parent->spill_range_); SetSpillRange(splinter_parent->spill_range_);
...@@ -928,43 +948,55 @@ void TopLevelLiveRange::Merge(TopLevelLiveRange* other, Zone* zone) { ...@@ -928,43 +948,55 @@ void TopLevelLiveRange::Merge(TopLevelLiveRange* other, Zone* zone) {
DCHECK(Start() < other->Start()); DCHECK(Start() < other->Start());
DCHECK(other->splintered_from() == this); DCHECK(other->splintered_from() == this);
LiveRange* last_other = other->last_child(); LiveRange* first = this;
LiveRange* last_me = last_child(); LiveRange* second = other;
DCHECK(first->Start() < second->Start());
// Simple case: we just append at the end. while (first != nullptr && second != nullptr) {
if (last_me->End() <= other->Start()) return last_me->AppendAsChild(other); DCHECK(first != second);
// Make sure the ranges are in order each time we iterate.
DCHECK(last_me->End() > last_other->End()); if (second->Start() < first->Start()) {
LiveRange* tmp = second;
second = first;
first = tmp;
continue;
}
// In the more general case, we need to find the ranges between which to if (first->End() <= second->Start()) {
// insert. if (first->next() == nullptr ||
if (other->Start() < last_insertion_point_->Start()) { first->next()->Start() > second->Start()) {
last_insertion_point_ = this; // First is in order before second.
} LiveRange* temp = first->next();
first->next_ = second;
first = temp;
} else {
// First is in order before its successor (or second), so advance first.
first = first->next();
}
continue;
}
for (; last_insertion_point_->next() != nullptr && DCHECK(first->Start() < second->Start());
last_insertion_point_->next()->Start() <= other->Start(); // If first and second intersect, split first.
last_insertion_point_ = last_insertion_point_->next()) { if (first->Start() < second->End() && second->Start() < first->End()) {
} LiveRange* temp = first->SplitAt(second->Start(), zone);
CHECK(temp != first);
temp->set_spilled(first->spilled());
if (!temp->spilled())
temp->set_assigned_register(first->assigned_register());
// When we splintered the original range, we reconstituted the original range first->next_ = second;
// into one range without children, but with discontinuities. To merge the first = temp;
// splinter back in, we need to split the range - or a child obtained after continue;
// register allocation splitting. }
LiveRange* after = last_insertion_point_->next(); DCHECK(first->End() <= second->Start());
if (last_insertion_point_->End() > other->Start()) {
LiveRange* new_after = last_insertion_point_->SplitAt(other->Start(), zone);
new_after->set_spilled(last_insertion_point_->spilled());
if (!new_after->spilled())
new_after->set_assigned_register(
last_insertion_point_->assigned_register());
after = new_after;
} }
last_other->next_ = after; TopLevel()->UpdateParentForAllChildren(TopLevel());
last_insertion_point_->next_ = other;
other->UpdateParentForAllChildren(TopLevel());
TopLevel()->UpdateSpillRangePostMerge(other); TopLevel()->UpdateSpillRangePostMerge(other);
#if DEBUG
Verify();
#endif
} }
......
...@@ -495,8 +495,7 @@ class TopLevelLiveRange final : public LiveRange { ...@@ -495,8 +495,7 @@ class TopLevelLiveRange final : public LiveRange {
// result. // result.
// The current range is pointed to as "splintered_from". No parent/child // The current range is pointed to as "splintered_from". No parent/child
// relationship is established between this and result. // relationship is established between this and result.
void Splinter(LifetimePosition start, LifetimePosition end, void Splinter(LifetimePosition start, LifetimePosition end, Zone* zone);
TopLevelLiveRange* result, Zone* zone);
// Assuming other was splintered from this range, embeds other and its // Assuming other was splintered from this range, embeds other and its
// children as part of the children sequence of this range. // children as part of the children sequence of this range.
...@@ -540,7 +539,6 @@ class TopLevelLiveRange final : public LiveRange { ...@@ -540,7 +539,6 @@ class TopLevelLiveRange final : public LiveRange {
spill_start_index_ = Min(start, spill_start_index_); spill_start_index_ = Min(start, spill_start_index_);
} }
void SetSplinteredFrom(TopLevelLiveRange* splinter_parent);
void CommitSpillsAtDefinition(InstructionSequence* sequence, void CommitSpillsAtDefinition(InstructionSequence* sequence,
const InstructionOperand& operand, const InstructionOperand& operand,
bool might_be_duplicated); bool might_be_duplicated);
...@@ -580,8 +578,20 @@ class TopLevelLiveRange final : public LiveRange { ...@@ -580,8 +578,20 @@ class TopLevelLiveRange final : public LiveRange {
} }
void set_last_child(LiveRange* range) { last_child_ = range; } void set_last_child(LiveRange* range) { last_child_ = range; }
LiveRange* last_child() const { return last_child_; } LiveRange* last_child() const { return last_child_; }
TopLevelLiveRange* splinter() const { return splinter_; }
void SetSplinter(TopLevelLiveRange* splinter) {
DCHECK_NULL(splinter_);
DCHECK_NOT_NULL(splinter);
splinter_ = splinter;
splinter->relative_id_ = GetNextChildId();
splinter->set_spill_type(spill_type());
splinter->SetSplinteredFrom(this);
}
private: private:
void SetSplinteredFrom(TopLevelLiveRange* splinter_parent);
typedef BitField<bool, 1, 1> HasSlotUseField; typedef BitField<bool, 1, 1> HasSlotUseField;
typedef BitField<bool, 2, 1> IsPhiField; typedef BitField<bool, 2, 1> IsPhiField;
typedef BitField<bool, 3, 1> IsNonLoopPhiField; typedef BitField<bool, 3, 1> IsNonLoopPhiField;
...@@ -601,7 +611,8 @@ class TopLevelLiveRange final : public LiveRange { ...@@ -601,7 +611,8 @@ class TopLevelLiveRange final : public LiveRange {
bool spilled_in_deferred_blocks_; bool spilled_in_deferred_blocks_;
int spill_start_index_; int spill_start_index_;
LiveRange* last_child_; LiveRange* last_child_;
LiveRange* last_insertion_point_; UsePosition* last_pos_;
TopLevelLiveRange* splinter_;
DISALLOW_COPY_AND_ASSIGN(TopLevelLiveRange); DISALLOW_COPY_AND_ASSIGN(TopLevelLiveRange);
}; };
......
...@@ -32,11 +32,14 @@ class LiveRangeUnitTest : public TestWithZone { ...@@ -32,11 +32,14 @@ class LiveRangeUnitTest : public TestWithZone {
TopLevelLiveRange* Splinter(TopLevelLiveRange* top, int start, int end, TopLevelLiveRange* Splinter(TopLevelLiveRange* top, int start, int end,
int new_id = 0) { int new_id = 0) {
TopLevelLiveRange* ret = if (top->splinter() == nullptr) {
new (zone()) TopLevelLiveRange(new_id, MachineType::kRepTagged); TopLevelLiveRange* ret =
new (zone()) TopLevelLiveRange(new_id, MachineType::kRepTagged);
top->SetSplinter(ret);
}
top->Splinter(LifetimePosition::FromInt(start), top->Splinter(LifetimePosition::FromInt(start),
LifetimePosition::FromInt(end), ret, zone()); LifetimePosition::FromInt(end), zone());
return ret; return top->splinter();
} }
// Ranges first and second match structurally. // Ranges first and second match structurally.
...@@ -377,6 +380,25 @@ TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsRight) { ...@@ -377,6 +380,25 @@ TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsRight) {
} }
TEST_F(LiveRangeUnitTest, SplinterMergeMultipleTimes) {
TopLevelLiveRange* range =
TestRangeBuilder(zone()).Add(0, 3).Add(5, 10).Add(12, 16).Build();
Splinter(range, 4, 6);
Splinter(range, 8, 14);
TopLevelLiveRange* splinter = range->splinter();
EXPECT_EQ(nullptr, range->next());
EXPECT_EQ(nullptr, splinter->next());
EXPECT_EQ(range, splinter->splintered_from());
TopLevelLiveRange* expected_source =
TestRangeBuilder(zone()).Add(0, 3).Add(6, 8).Add(14, 16).Build();
TopLevelLiveRange* expected_splinter =
TestRangeBuilder(zone()).Add(5, 6).Add(8, 10).Add(12, 14).Build();
EXPECT_TRUE(RangesMatch(expected_source, range));
EXPECT_TRUE(RangesMatch(expected_splinter, splinter));
}
TEST_F(LiveRangeUnitTest, MergeMultipleIntervalsRight) { TEST_F(LiveRangeUnitTest, MergeMultipleIntervalsRight) {
TopLevelLiveRange* original = TopLevelLiveRange* original =
TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build();
...@@ -416,8 +438,9 @@ TEST_F(LiveRangeUnitTest, IDGeneration) { ...@@ -416,8 +438,9 @@ TEST_F(LiveRangeUnitTest, IDGeneration) {
TopLevelLiveRange* splinter = TopLevelLiveRange* splinter =
new (zone()) TopLevelLiveRange(101, MachineType::kRepTagged); new (zone()) TopLevelLiveRange(101, MachineType::kRepTagged);
vreg->SetSplinter(splinter);
vreg->Splinter(LifetimePosition::FromInt(4), LifetimePosition::FromInt(12), vreg->Splinter(LifetimePosition::FromInt(4), LifetimePosition::FromInt(12),
splinter, zone()); zone());
EXPECT_EQ(101, splinter->vreg()); EXPECT_EQ(101, splinter->vreg());
EXPECT_EQ(1, splinter->relative_id()); EXPECT_EQ(1, splinter->relative_id());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment