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) {
// jump). Generating a single Merge here, which joins all the deoptimizing
// controls would generate a lot of these basic blocks, however. So this
// 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
// type checks failed, or one of the assumptions inside one of the cases
// failes (i.e. failing prototype chain check).
......
......@@ -44,12 +44,14 @@ void CreateSplinter(TopLevelLiveRange *range, RegisterAllocationData *data,
if (range->MayRequireSpillRange()) {
data->CreateSpillRangeForLiveRange(range);
}
TopLevelLiveRange *result = data->NextLiveRange(range->machine_type());
DCHECK_NULL(data->live_ranges()[result->vreg()]);
data->live_ranges()[result->vreg()] = result;
if (range->splinter() == nullptr) {
TopLevelLiveRange *splinter = data->NextLiveRange(range->machine_type());
DCHECK_NULL(data->live_ranges()[splinter->vreg()]);
data->live_ranges()[splinter->vreg()] = splinter;
range->SetSplinter(splinter);
}
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)
spilled_in_deferred_blocks_(false),
spill_start_index_(kMaxInt),
last_child_(this),
last_insertion_point_(this) {
last_pos_(nullptr),
splinter_(nullptr) {
bits_ |= SpillTypeField::encode(SpillType::kNoSpillType);
}
......@@ -845,12 +846,12 @@ AllocatedOperand TopLevelLiveRange::GetSpillRangeOperand() const {
void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end,
TopLevelLiveRange* result, Zone* zone) {
Zone* zone) {
DCHECK(start != Start() || end != End());
DCHECK(start < end);
result->set_spill_type(spill_type());
TopLevelLiveRange splinter_temp(-1, machine_type());
UsePosition* last_in_splinter = nullptr;
if (start <= Start()) {
// 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
......@@ -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
// have access to the instruction sequence.
DCHECK(end < End());
DetachAt(end, result, zone);
DetachAt(end, &splinter_temp, zone);
next_ = nullptr;
} else if (end >= End()) {
DCHECK(start > Start());
DetachAt(start, result, zone);
DetachAt(start, &splinter_temp, zone);
next_ = nullptr;
} else {
DCHECK(start < End() && Start() < end);
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);
result->DetachAt(end, &end_part, zone);
last_in_splinter = splinter_temp.DetachAt(end, &end_part, zone);
next_ = end_part.next_;
last_interval_->set_next(end_part.first_interval_);
......@@ -890,20 +891,39 @@ void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end,
if (last != nullptr) last->set_next(end_part.first_pos_);
}
}
result->next_ = nullptr;
result->top_level_ = result;
result->SetSplinteredFrom(this);
// Ensure the result's relative ID is unique within the IDs used for this
// virtual register's children and splinters.
result->relative_id_ = GetNextChildId();
if (splinter()->IsEmpty()) {
splinter()->first_interval_ = splinter_temp.first_interval_;
splinter()->last_interval_ = splinter_temp.last_interval_;
} 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) {
// The splinter parent is always the original "Top".
DCHECK(splinter_parent->Start() < Start());
splintered_from_ = splinter_parent;
if (!HasSpillOperand() && splinter_parent->spill_range_ != nullptr) {
SetSpillRange(splinter_parent->spill_range_);
......@@ -928,43 +948,55 @@ void TopLevelLiveRange::Merge(TopLevelLiveRange* other, Zone* zone) {
DCHECK(Start() < other->Start());
DCHECK(other->splintered_from() == this);
LiveRange* last_other = other->last_child();
LiveRange* last_me = last_child();
// Simple case: we just append at the end.
if (last_me->End() <= other->Start()) return last_me->AppendAsChild(other);
DCHECK(last_me->End() > last_other->End());
LiveRange* first = this;
LiveRange* second = other;
DCHECK(first->Start() < second->Start());
while (first != nullptr && second != nullptr) {
DCHECK(first != second);
// Make sure the ranges are in order each time we iterate.
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
// insert.
if (other->Start() < last_insertion_point_->Start()) {
last_insertion_point_ = this;
}
if (first->End() <= second->Start()) {
if (first->next() == nullptr ||
first->next()->Start() > second->Start()) {
// 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 &&
last_insertion_point_->next()->Start() <= other->Start();
last_insertion_point_ = last_insertion_point_->next()) {
}
DCHECK(first->Start() < second->Start());
// If first and second intersect, split first.
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
// 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 = last_insertion_point_->next();
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;
first->next_ = second;
first = temp;
continue;
}
DCHECK(first->End() <= second->Start());
}
last_other->next_ = after;
last_insertion_point_->next_ = other;
other->UpdateParentForAllChildren(TopLevel());
TopLevel()->UpdateParentForAllChildren(TopLevel());
TopLevel()->UpdateSpillRangePostMerge(other);
#if DEBUG
Verify();
#endif
}
......
......@@ -495,8 +495,7 @@ class TopLevelLiveRange final : public LiveRange {
// result.
// The current range is pointed to as "splintered_from". No parent/child
// relationship is established between this and result.
void Splinter(LifetimePosition start, LifetimePosition end,
TopLevelLiveRange* result, Zone* zone);
void Splinter(LifetimePosition start, LifetimePosition end, Zone* zone);
// Assuming other was splintered from this range, embeds other and its
// children as part of the children sequence of this range.
......@@ -540,7 +539,6 @@ class TopLevelLiveRange final : public LiveRange {
spill_start_index_ = Min(start, spill_start_index_);
}
void SetSplinteredFrom(TopLevelLiveRange* splinter_parent);
void CommitSpillsAtDefinition(InstructionSequence* sequence,
const InstructionOperand& operand,
bool might_be_duplicated);
......@@ -580,8 +578,20 @@ class TopLevelLiveRange final : public LiveRange {
}
void set_last_child(LiveRange* range) { last_child_ = range; }
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:
void SetSplinteredFrom(TopLevelLiveRange* splinter_parent);
typedef BitField<bool, 1, 1> HasSlotUseField;
typedef BitField<bool, 2, 1> IsPhiField;
typedef BitField<bool, 3, 1> IsNonLoopPhiField;
......@@ -601,7 +611,8 @@ class TopLevelLiveRange final : public LiveRange {
bool spilled_in_deferred_blocks_;
int spill_start_index_;
LiveRange* last_child_;
LiveRange* last_insertion_point_;
UsePosition* last_pos_;
TopLevelLiveRange* splinter_;
DISALLOW_COPY_AND_ASSIGN(TopLevelLiveRange);
};
......
......@@ -32,11 +32,14 @@ class LiveRangeUnitTest : public TestWithZone {
TopLevelLiveRange* Splinter(TopLevelLiveRange* top, int start, int end,
int new_id = 0) {
TopLevelLiveRange* ret =
new (zone()) TopLevelLiveRange(new_id, MachineType::kRepTagged);
if (top->splinter() == nullptr) {
TopLevelLiveRange* ret =
new (zone()) TopLevelLiveRange(new_id, MachineType::kRepTagged);
top->SetSplinter(ret);
}
top->Splinter(LifetimePosition::FromInt(start),
LifetimePosition::FromInt(end), ret, zone());
return ret;
LifetimePosition::FromInt(end), zone());
return top->splinter();
}
// Ranges first and second match structurally.
......@@ -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) {
TopLevelLiveRange* original =
TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build();
......@@ -416,8 +438,9 @@ TEST_F(LiveRangeUnitTest, IDGeneration) {
TopLevelLiveRange* splinter =
new (zone()) TopLevelLiveRange(101, MachineType::kRepTagged);
vreg->SetSplinter(splinter);
vreg->Splinter(LifetimePosition::FromInt(4), LifetimePosition::FromInt(12),
splinter, zone());
zone());
EXPECT_EQ(101, splinter->vreg());
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