Index: src/compiler/scheduler.cc |
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc |
index 1599152f95f47dfa557882b735e0d0357044a0c0..c43ed812f9c5cb4f02cef9502102aa2a2399ed51 100644 |
--- a/src/compiler/scheduler.cc |
+++ b/src/compiler/scheduler.cc |
@@ -52,6 +52,8 @@ Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { |
scheduler.ScheduleEarly(); |
scheduler.ScheduleLate(); |
+ scheduler.SealFinalSchedule(); |
+ |
return schedule; |
} |
@@ -211,20 +213,11 @@ void Scheduler::DecrementUnscheduledUseCount(Node* node, int index, |
} |
-int Scheduler::GetRPONumber(BasicBlock* block) { |
- DCHECK(block->rpo_number() >= 0 && |
- block->rpo_number() < static_cast<int>(schedule_->rpo_order_.size())); |
- DCHECK(schedule_->rpo_order_[block->rpo_number()] == block); |
- return block->rpo_number(); |
-} |
- |
- |
BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { |
while (b1 != b2) { |
- int b1_rpo = GetRPONumber(b1); |
- int b2_rpo = GetRPONumber(b2); |
- DCHECK(b1_rpo != b2_rpo); |
- if (b1_rpo < b2_rpo) { |
+ int32_t b1_depth = b1->dominator_depth(); |
+ int32_t b2_depth = b2->dominator_depth(); |
+ if (b1_depth < b2_depth) { |
b2 = b2->dominator(); |
} else { |
b1 = b1->dominator(); |
@@ -529,23 +522,164 @@ void Scheduler::BuildCFG() { |
// 2. All loops are contiguous in the order (i.e. no intervening blocks that |
// do not belong to the loop.) |
// Note a simple RPO traversal satisfies (1) but not (2). |
-class SpecialRPONumberer { |
+class SpecialRPONumberer : public ZoneObject { |
public: |
SpecialRPONumberer(Zone* zone, Schedule* schedule) |
- : zone_(zone), schedule_(schedule) {} |
- |
+ : zone_(zone), |
+ schedule_(schedule), |
+ order_(NULL), |
+ loops_(zone), |
+ beyond_end_(NULL) {} |
+ |
+ // Computes the special reverse-post-order for the main control flow graph, |
+ // that is for the graph spanned between the schedule's start and end blocks. |
void ComputeSpecialRPO() { |
- // RPO should not have been computed for this schedule yet. |
+ DCHECK_EQ(NULL, order_); // Main order does not exist yet. |
+ // TODO(mstarzinger): Should use Schedule::end() after tests are fixed. |
+ ComputeAndInsertSpecialRPO(schedule_->start(), NULL); |
+ } |
+ |
+ // Computes the special reverse-post-order for a partial control flow graph, |
+ // that is for the graph spanned between the given {entry} and {end} blocks, |
+ // then updates the existing ordering with this new information. |
+ void UpdateSpecialRPO(BasicBlock* entry, BasicBlock* end) { |
+ DCHECK_NE(NULL, order_); // Main order to be updated is present. |
+ ComputeAndInsertSpecialRPO(entry, end); |
+ } |
+ |
+ // Serialize the previously computed order as an assembly order (non-deferred |
+ // code first, deferred code afterwards) into the final schedule. |
+ void SerializeAOIntoSchedule() { |
+ int32_t number = 0; |
+ for (BlockList* l = order_; l != NULL; l = l->next) { |
+ if (l->block->deferred()) continue; |
+ l->block->set_ao_number(number++); |
+ } |
+ for (BlockList* l = order_; l != NULL; l = l->next) { |
+ if (!l->block->deferred()) continue; |
+ l->block->set_ao_number(number++); |
+ } |
+ } |
+ |
+ // Serialize the previously computed order as a special reverse-post-order |
+ // numbering for basic blocks into the final schedule. |
+ void SerializeRPOIntoSchedule() { |
+ int32_t number = 0; |
+ for (BlockList* l = order_; l != NULL; l = l->next) { |
+ l->block->set_rpo_number(number++); |
+ schedule_->rpo_order()->push_back(l->block); |
+ } |
+ BeyondEndSentinel()->set_rpo_number(number); |
+ } |
+ |
+ // Print and verify the special reverse-post-order. |
+ void PrintAndVerifySpecialRPO() { |
+#if DEBUG |
+ if (FLAG_trace_turbo_scheduler) PrintRPO(); |
+ VerifySpecialRPO(); |
+#endif |
+ } |
+ |
+ private: |
+ // TODO(mstarzinger): Only for Scheduler::GenerateImmediateDominatorTree. |
+ friend class Scheduler; |
+ |
+ // Numbering for BasicBlockData.rpo_number_ for this block traversal: |
+ static const int kBlockOnStack = -2; |
+ static const int kBlockVisited1 = -3; |
+ static const int kBlockVisited2 = -4; |
+ static const int kBlockUnvisited1 = -1; |
+ static const int kBlockUnvisited2 = kBlockVisited1; |
+ |
+ struct SpecialRPOStackFrame { |
+ BasicBlock* block; |
+ size_t index; |
+ }; |
+ |
+ struct BlockList { |
+ BasicBlock* block; |
+ BlockList* next; |
+ |
+ BlockList* Add(Zone* zone, BasicBlock* b) { |
+ BlockList* list = static_cast<BlockList*>(zone->New(sizeof(BlockList))); |
+ list->block = b; |
+ list->next = this; |
+ return list; |
+ } |
+ |
+ BlockList* FindForBlock(BasicBlock* b) { |
+ for (BlockList* l = this; l != NULL; l = l->next) { |
+ if (l->block == b) return l; |
+ } |
+ return NULL; |
+ } |
+ }; |
+ |
+ struct LoopInfo { |
+ BasicBlock* header; |
+ ZoneList<BasicBlock*>* outgoing; |
+ BitVector* members; |
+ LoopInfo* prev; |
+ BlockList* end; |
+ BlockList* start; |
+ |
+ void AddOutgoing(Zone* zone, BasicBlock* block) { |
+ if (outgoing == NULL) { |
+ outgoing = new (zone) ZoneList<BasicBlock*>(2, zone); |
+ } |
+ outgoing->Add(block, zone); |
+ } |
+ }; |
+ |
+ int Push(SpecialRPOStackFrame* stack, int depth, BasicBlock* child, |
+ int unvisited) { |
+ if (child->rpo_number() == unvisited) { |
+ stack[depth].block = child; |
+ stack[depth].index = 0; |
+ child->set_rpo_number(kBlockOnStack); |
+ return depth + 1; |
+ } |
+ return depth; |
+ } |
+ |
+ // We are hijacking the {ao_number} to enumerate loops temporarily. Note that |
+ // these numbers are only valid within this class. |
+ static int GetLoopNumber(BasicBlock* block) { return block->ao_number(); } |
+ static void SetLoopNumber(BasicBlock* block, int loop_number) { |
+ return block->set_ao_number(loop_number); |
+ } |
+ static bool HasLoopNumber(BasicBlock* block) { |
+ return block->ao_number() >= 0; |
+ } |
+ |
+ // TODO(mstarzinger): We only need this special sentinel because some tests |
+ // use the schedule's end block in actual control flow (e.g. with end having |
+ // successors). Once this has been cleaned up we can use the end block here. |
+ BasicBlock* BeyondEndSentinel() { |
+ if (beyond_end_ == NULL) { |
+ BasicBlock::Id id = BasicBlock::Id::FromInt(-1); |
+ beyond_end_ = new (schedule_->zone()) BasicBlock(schedule_->zone(), id); |
+ } |
+ return beyond_end_; |
+ } |
+ |
+ // Compute special RPO for the control flow graph between {entry} and {end}, |
+ // mutating any existing order so that the result is still valid. |
+ void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) { |
+ // RPO should not have been serialized for this schedule yet. |
+ CHECK_EQ(kBlockUnvisited1, schedule_->start()->ao_number()); |
CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number()); |
CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size())); |
+ // Find correct insertion point within existing order. |
+ BlockList* insert_before = order_->FindForBlock(entry); |
+ BlockList* insert_after = insert_before ? insert_before->next : NULL; |
+ |
// Perform an iterative RPO traversal using an explicit stack, |
// recording backedges that form cycles. O(|B|). |
ZoneList<std::pair<BasicBlock*, size_t> > backedges(1, zone_); |
SpecialRPOStackFrame* stack = zone_->NewArray<SpecialRPOStackFrame>( |
static_cast<int>(schedule_->BasicBlockCount())); |
- BasicBlock* entry = schedule_->start(); |
- BlockList* order = NULL; |
int stack_depth = Push(stack, 0, entry, kBlockUnvisited1); |
int num_loops = 0; |
@@ -553,7 +687,8 @@ class SpecialRPONumberer { |
int current = stack_depth - 1; |
SpecialRPOStackFrame* frame = stack + current; |
- if (frame->index < frame->block->SuccessorCount()) { |
+ if (frame->block != end && |
+ frame->index < frame->block->SuccessorCount()) { |
// Process the next successor. |
BasicBlock* succ = frame->block->SuccessorAt(frame->index++); |
if (succ->rpo_number() == kBlockVisited1) continue; |
@@ -562,9 +697,9 @@ class SpecialRPONumberer { |
backedges.Add( |
std::pair<BasicBlock*, size_t>(frame->block, frame->index - 1), |
zone_); |
- if (succ->loop_end() < 0) { |
+ if (!HasLoopNumber(succ)) { |
// Assign a new loop number to the header if it doesn't have one. |
- succ->set_loop_end(num_loops++); |
+ SetLoopNumber(succ, num_loops++); |
} |
} else { |
// Push the successor onto the stack. |
@@ -573,23 +708,32 @@ class SpecialRPONumberer { |
} |
} else { |
// Finished with all successors; pop the stack and add the block. |
- order = order->Add(zone_, frame->block); |
+ insert_after = insert_after->Add(zone_, frame->block); |
frame->block->set_rpo_number(kBlockVisited1); |
stack_depth--; |
} |
} |
+ // Insert the result into any existing order. |
+ if (insert_before == NULL) { |
+ order_ = insert_after; |
+ } else { |
+ // There already is a list element for the entry block in the list, hence |
+ // we skip the first element of the sub-list to compensate duplication. |
+ DCHECK_EQ(insert_before->block, insert_after->block); |
+ insert_before->next = insert_after->next; |
+ } |
+ |
// If no loops were encountered, then the order we computed was correct. |
- LoopInfo* loops = NULL; |
if (num_loops != 0) { |
// Otherwise, compute the loop information from the backedges in order |
// to perform a traversal that groups loop bodies together. |
- loops = ComputeLoopInfo(stack, num_loops, schedule_->BasicBlockCount(), |
- &backedges); |
+ ComputeLoopInfo(stack, num_loops, &backedges); |
// Initialize the "loop stack". Note the entry could be a loop header. |
- LoopInfo* loop = entry->IsLoopHeader() ? &loops[entry->loop_end()] : NULL; |
- order = NULL; |
+ LoopInfo* loop = |
+ HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : NULL; |
+ order_ = NULL; |
// Perform an iterative post-order traversal, visiting loop bodies before |
// edges that lead out of loops. Visits each block once, but linking loop |
@@ -604,14 +748,14 @@ class SpecialRPONumberer { |
if (frame->index < block->SuccessorCount()) { |
// Process the next normal successor. |
succ = block->SuccessorAt(frame->index++); |
- } else if (block->IsLoopHeader()) { |
+ } else if (HasLoopNumber(block)) { |
// Process additional outgoing edges from the loop header. |
if (block->rpo_number() == kBlockOnStack) { |
// Finish the loop body the first time the header is left on the |
// stack. |
DCHECK(loop != NULL && loop->header == block); |
- loop->start = order->Add(zone_, block); |
- order = loop->end; |
+ loop->start = order_->Add(zone_, block); |
+ order_ = loop->end; |
block->set_rpo_number(kBlockVisited2); |
// Pop the loop stack and continue visiting outgoing edges within |
// the context of the outer loop, if any. |
@@ -623,7 +767,7 @@ class SpecialRPONumberer { |
// Use the next outgoing edge if there are any. |
int outgoing_index = |
static_cast<int>(frame->index - block->SuccessorCount()); |
- LoopInfo* info = &loops[block->loop_end()]; |
+ LoopInfo* info = &loops_[GetLoopNumber(block)]; |
DCHECK(loop != info); |
if (info->outgoing != NULL && |
outgoing_index < info->outgoing->length()) { |
@@ -644,31 +788,31 @@ class SpecialRPONumberer { |
} else { |
// Push the successor onto the stack. |
stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2); |
- if (succ->IsLoopHeader()) { |
+ if (HasLoopNumber(succ)) { |
// Push the inner loop onto the loop stack. |
- DCHECK(succ->loop_end() >= 0 && succ->loop_end() < num_loops); |
- LoopInfo* next = &loops[succ->loop_end()]; |
- next->end = order; |
+ DCHECK(GetLoopNumber(succ) < num_loops); |
+ LoopInfo* next = &loops_[GetLoopNumber(succ)]; |
+ next->end = order_; |
next->prev = loop; |
loop = next; |
} |
} |
} else { |
// Finished with all successors of the current block. |
- if (block->IsLoopHeader()) { |
+ if (HasLoopNumber(block)) { |
// If we are going to pop a loop header, then add its entire body. |
- LoopInfo* info = &loops[block->loop_end()]; |
+ LoopInfo* info = &loops_[GetLoopNumber(block)]; |
for (BlockList* l = info->start; true; l = l->next) { |
if (l->next == info->end) { |
- l->next = order; |
- info->end = order; |
+ l->next = order_; |
+ info->end = order_; |
break; |
} |
} |
- order = info->start; |
+ order_ = info->start; |
} else { |
// Pop a single node off the stack and add it to the order. |
- order = order->Add(zone_, block); |
+ order_ = order_->Add(zone_, block); |
block->set_rpo_number(kBlockVisited2); |
} |
stack_depth--; |
@@ -676,21 +820,15 @@ class SpecialRPONumberer { |
} |
} |
- // Construct the final order from the list. |
- BasicBlockVector* final_order = schedule_->rpo_order(); |
- order->Serialize(final_order); |
- |
// Compute the correct loop headers and set the correct loop ends. |
LoopInfo* current_loop = NULL; |
BasicBlock* current_header = NULL; |
int loop_depth = 0; |
- for (BasicBlockVectorIter i = final_order->begin(); i != final_order->end(); |
- ++i) { |
- BasicBlock* current = *i; |
+ for (BlockList* l = order_; l != NULL; l = l->next) { |
+ BasicBlock* current = l->block; |
// Finish the previous loop(s) if we just exited them. |
- while (current_header != NULL && |
- current->rpo_number() >= current_header->loop_end()) { |
+ while (current_header != NULL && current == current_header->loop_end()) { |
DCHECK(current_header->IsLoopHeader()); |
DCHECK(current_loop != NULL); |
current_loop = current_loop->prev; |
@@ -700,13 +838,11 @@ class SpecialRPONumberer { |
current->set_loop_header(current_header); |
// Push a new loop onto the stack if this loop is a loop header. |
- if (current->IsLoopHeader()) { |
+ if (HasLoopNumber(current)) { |
loop_depth++; |
- current_loop = &loops[current->loop_end()]; |
+ current_loop = &loops_[GetLoopNumber(current)]; |
BlockList* end = current_loop->end; |
- current->set_loop_end(end == NULL |
- ? static_cast<int>(final_order->size()) |
- : end->block->rpo_number()); |
+ current->set_loop_end(end == NULL ? BeyondEndSentinel() : end->block); |
current_header = current_loop->header; |
Trace("B%d is a loop header, increment loop depth to %d\n", |
current->id().ToInt(), loop_depth); |
@@ -722,109 +858,31 @@ class SpecialRPONumberer { |
current->loop_header()->id().ToInt(), current->loop_depth()); |
} |
} |
- |
- // Compute the assembly order (non-deferred code first, deferred code |
- // afterwards). |
- int32_t number = 0; |
- for (auto block : *final_order) { |
- if (block->deferred()) continue; |
- block->set_ao_number(number++); |
- } |
- for (auto block : *final_order) { |
- if (!block->deferred()) continue; |
- block->set_ao_number(number++); |
- } |
- |
-#if DEBUG |
- if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); |
- VerifySpecialRPO(num_loops, loops, final_order); |
-#endif |
- } |
- |
- private: |
- // Numbering for BasicBlockData.rpo_number_ for this block traversal: |
- static const int kBlockOnStack = -2; |
- static const int kBlockVisited1 = -3; |
- static const int kBlockVisited2 = -4; |
- static const int kBlockUnvisited1 = -1; |
- static const int kBlockUnvisited2 = kBlockVisited1; |
- |
- struct SpecialRPOStackFrame { |
- BasicBlock* block; |
- size_t index; |
- }; |
- |
- struct BlockList { |
- BasicBlock* block; |
- BlockList* next; |
- |
- BlockList* Add(Zone* zone, BasicBlock* b) { |
- BlockList* list = static_cast<BlockList*>(zone->New(sizeof(BlockList))); |
- list->block = b; |
- list->next = this; |
- return list; |
- } |
- |
- void Serialize(BasicBlockVector* final_order) { |
- for (BlockList* l = this; l != NULL; l = l->next) { |
- l->block->set_rpo_number(static_cast<int>(final_order->size())); |
- final_order->push_back(l->block); |
- } |
- } |
- }; |
- |
- struct LoopInfo { |
- BasicBlock* header; |
- ZoneList<BasicBlock*>* outgoing; |
- BitVector* members; |
- LoopInfo* prev; |
- BlockList* end; |
- BlockList* start; |
- |
- void AddOutgoing(Zone* zone, BasicBlock* block) { |
- if (outgoing == NULL) { |
- outgoing = new (zone) ZoneList<BasicBlock*>(2, zone); |
- } |
- outgoing->Add(block, zone); |
- } |
- }; |
- |
- int Push(SpecialRPOStackFrame* stack, int depth, BasicBlock* child, |
- int unvisited) { |
- if (child->rpo_number() == unvisited) { |
- stack[depth].block = child; |
- stack[depth].index = 0; |
- child->set_rpo_number(kBlockOnStack); |
- return depth + 1; |
- } |
- return depth; |
} |
// Computes loop membership from the backedges of the control flow graph. |
- LoopInfo* ComputeLoopInfo( |
- SpecialRPOStackFrame* queue, int num_loops, size_t num_blocks, |
- ZoneList<std::pair<BasicBlock*, size_t> >* backedges) { |
- LoopInfo* loops = zone_->NewArray<LoopInfo>(num_loops); |
- memset(loops, 0, num_loops * sizeof(LoopInfo)); |
+ void ComputeLoopInfo(SpecialRPOStackFrame* queue, size_t num_loops, |
+ ZoneList<std::pair<BasicBlock*, size_t> >* backedges) { |
+ loops_.resize(num_loops, LoopInfo()); |
// Compute loop membership starting from backedges. |
// O(max(loop_depth) * max(|loop|) |
for (int i = 0; i < backedges->length(); i++) { |
BasicBlock* member = backedges->at(i).first; |
BasicBlock* header = member->SuccessorAt(backedges->at(i).second); |
- int loop_num = header->loop_end(); |
- if (loops[loop_num].header == NULL) { |
- loops[loop_num].header = header; |
- loops[loop_num].members = |
- new (zone_) BitVector(static_cast<int>(num_blocks), zone_); |
+ size_t loop_num = GetLoopNumber(header); |
+ if (loops_[loop_num].header == NULL) { |
+ loops_[loop_num].header = header; |
+ loops_[loop_num].members = new (zone_) |
+ BitVector(static_cast<int>(schedule_->BasicBlockCount()), zone_); |
} |
int queue_length = 0; |
if (member != header) { |
// As long as the header doesn't have a backedge to itself, |
// Push the member onto the queue and process its predecessors. |
- if (!loops[loop_num].members->Contains(member->id().ToInt())) { |
- loops[loop_num].members->Add(member->id().ToInt()); |
+ if (!loops_[loop_num].members->Contains(member->id().ToInt())) { |
+ loops_[loop_num].members->Add(member->id().ToInt()); |
} |
queue[queue_length++].block = member; |
} |
@@ -836,47 +894,46 @@ class SpecialRPONumberer { |
for (size_t i = 0; i < block->PredecessorCount(); i++) { |
BasicBlock* pred = block->PredecessorAt(i); |
if (pred != header) { |
- if (!loops[loop_num].members->Contains(pred->id().ToInt())) { |
- loops[loop_num].members->Add(pred->id().ToInt()); |
+ if (!loops_[loop_num].members->Contains(pred->id().ToInt())) { |
+ loops_[loop_num].members->Add(pred->id().ToInt()); |
queue[queue_length++].block = pred; |
} |
} |
} |
} |
} |
- return loops; |
} |
#if DEBUG |
- void PrintRPO(int num_loops, LoopInfo* loops, BasicBlockVector* order) { |
+ void PrintRPO() { |
OFStream os(stdout); |
- os << "-- RPO with " << num_loops << " loops "; |
- if (num_loops > 0) { |
- os << "("; |
- for (int i = 0; i < num_loops; i++) { |
+ os << "RPO with " << loops_.size() << " loops"; |
+ if (loops_.size() > 0) { |
+ os << " ("; |
+ for (size_t i = 0; i < loops_.size(); i++) { |
if (i > 0) os << " "; |
- os << "B" << loops[i].header->id(); |
+ os << "B" << loops_[i].header->id(); |
} |
- os << ") "; |
+ os << ")"; |
} |
- os << "-- \n"; |
+ os << ":\n"; |
- for (size_t i = 0; i < order->size(); i++) { |
- BasicBlock* block = (*order)[i]; |
+ for (BlockList* l = order_; l != NULL; l = l->next) { |
+ BasicBlock* block = l->block; |
BasicBlock::Id bid = block->id(); |
// TODO(jarin,svenpanne): Add formatting here once we have support for |
- // that in streams (we want an equivalent of PrintF("%5d:", i) here). |
- os << i << ":"; |
- for (int j = 0; j < num_loops; j++) { |
- bool membership = loops[j].members->Contains(bid.ToInt()); |
- bool range = loops[j].header->LoopContains(block); |
+ // that in streams (we want an equivalent of PrintF("%5d:", x) here). |
+ os << " " << block->rpo_number() << ":"; |
+ for (size_t j = 0; j < loops_.size(); j++) { |
+ bool membership = loops_[j].members->Contains(bid.ToInt()); |
+ bool range = loops_[j].header->LoopContains(block); |
os << (membership ? " |" : " "); |
os << (range ? "x" : " "); |
} |
os << " B" << bid << ": "; |
- if (block->loop_end() >= 0) { |
- os << " range: [" << block->rpo_number() << ", " << block->loop_end() |
- << ")"; |
+ if (block->loop_end() != NULL) { |
+ os << " range: [" << block->rpo_number() << ", " |
+ << block->loop_end()->rpo_number() << ")"; |
} |
if (block->loop_header() != NULL) { |
os << " header: B" << block->loop_header()->id(); |
@@ -888,21 +945,22 @@ class SpecialRPONumberer { |
} |
} |
- void VerifySpecialRPO(int num_loops, LoopInfo* loops, |
- BasicBlockVector* order) { |
+ void VerifySpecialRPO() { |
+ BasicBlockVector* order = schedule_->rpo_order(); |
DCHECK(order->size() > 0); |
DCHECK((*order)[0]->id().ToInt() == 0); // entry should be first. |
- for (int i = 0; i < num_loops; i++) { |
- LoopInfo* loop = &loops[i]; |
+ for (size_t i = 0; i < loops_.size(); i++) { |
+ LoopInfo* loop = &loops_[i]; |
BasicBlock* header = loop->header; |
+ BasicBlock* end = header->loop_end(); |
DCHECK(header != NULL); |
DCHECK(header->rpo_number() >= 0); |
DCHECK(header->rpo_number() < static_cast<int>(order->size())); |
- DCHECK(header->loop_end() >= 0); |
- DCHECK(header->loop_end() <= static_cast<int>(order->size())); |
- DCHECK(header->loop_end() > header->rpo_number()); |
+ DCHECK(end != NULL); |
+ DCHECK(end->rpo_number() <= static_cast<int>(order->size())); |
+ DCHECK(end->rpo_number() > header->rpo_number()); |
DCHECK(header->loop_header() != header); |
// Verify the start ... end list relationship. |
@@ -922,15 +980,16 @@ class SpecialRPONumberer { |
DCHECK(links < static_cast<int>(2 * order->size())); // cycle? |
} |
DCHECK(links > 0); |
- DCHECK(links == (header->loop_end() - header->rpo_number())); |
+ DCHECK(links == end->rpo_number() - header->rpo_number()); |
DCHECK(end_found); |
// Check the contiguousness of loops. |
- int count = 0; |
+ // TODO(mstarzinger): Loop membership bit-vector becomes stale. |
+ /*int count = 0; |
for (int j = 0; j < static_cast<int>(order->size()); j++) { |
BasicBlock* block = order->at(j); |
DCHECK(block->rpo_number() == j); |
- if (j < header->rpo_number() || j >= header->loop_end()) { |
+ if (j < header->rpo_number() || j >= end->rpo_number()) { |
DCHECK(!loop->members->Contains(block->id().ToInt())); |
} else { |
if (block == header) { |
@@ -941,13 +1000,16 @@ class SpecialRPONumberer { |
count++; |
} |
} |
- DCHECK(links == count); |
+ DCHECK(links == count);*/ |
} |
} |
#endif // DEBUG |
Zone* zone_; |
Schedule* schedule_; |
+ BlockList* order_; |
+ ZoneVector<LoopInfo> loops_; |
+ BasicBlock* beyond_end_; |
}; |
@@ -958,6 +1020,9 @@ BasicBlockVector* Scheduler::ComputeSpecialRPO(ZonePool* zone_pool, |
SpecialRPONumberer numberer(zone, schedule); |
numberer.ComputeSpecialRPO(); |
+ numberer.SerializeAOIntoSchedule(); |
+ numberer.SerializeRPOIntoSchedule(); |
+ numberer.PrintAndVerifySpecialRPO(); |
return schedule->rpo_order(); |
} |
@@ -965,40 +1030,39 @@ BasicBlockVector* Scheduler::ComputeSpecialRPO(ZonePool* zone_pool, |
void Scheduler::ComputeSpecialRPONumbering() { |
Trace("--- COMPUTING SPECIAL RPO ----------------------------------\n"); |
- SpecialRPONumberer numberer(zone_, schedule_); |
- numberer.ComputeSpecialRPO(); |
+ // Compute the special reverse-post-order for basic blocks. |
+ special_rpo_ = new (zone_) SpecialRPONumberer(zone_, schedule_); |
+ special_rpo_->ComputeSpecialRPO(); |
} |
void Scheduler::GenerateImmediateDominatorTree() { |
Trace("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n"); |
- // Build the dominator graph. |
- // TODO(danno): consider using Lengauer & Tarjan's if this becomes too slow. |
- for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { |
- BasicBlock* current_rpo = schedule_->rpo_order_[i]; |
- if (current_rpo != schedule_->start()) { |
- BasicBlock::Predecessors::iterator current_pred = |
- current_rpo->predecessors_begin(); |
- BasicBlock::Predecessors::iterator end = current_rpo->predecessors_end(); |
- DCHECK(current_pred != end); |
- BasicBlock* dominator = *current_pred; |
- ++current_pred; |
- // For multiple predecessors, walk up the RPO ordering until a common |
- // dominator is found. |
- int current_rpo_pos = GetRPONumber(current_rpo); |
- while (current_pred != end) { |
- // Don't examine backwards edges |
- BasicBlock* pred = *current_pred; |
- if (GetRPONumber(pred) < current_rpo_pos) { |
- dominator = GetCommonDominator(dominator, *current_pred); |
- } |
- ++current_pred; |
- } |
- current_rpo->set_dominator(dominator); |
- Trace("Block %d's idom is %d\n", current_rpo->id().ToInt(), |
- dominator->id().ToInt()); |
+ // TODO(danno): Consider using Lengauer & Tarjan's if this becomes too slow. |
+ |
+ // Build the block dominator tree. |
+ schedule_->start()->set_dominator_depth(0); |
+ typedef SpecialRPONumberer::BlockList BlockList; |
+ for (BlockList* l = special_rpo_->order_; l != NULL; l = l->next) { |
+ BasicBlock* current = l->block; |
+ if (current == schedule_->start()) continue; |
+ BasicBlock::Predecessors::iterator pred = current->predecessors_begin(); |
+ BasicBlock::Predecessors::iterator end = current->predecessors_end(); |
+ DCHECK(pred != end); // All blocks except start have predecessors. |
+ BasicBlock* dominator = *pred; |
+ // For multiple predecessors, walk up the dominator tree until a common |
+ // dominator is found. Visitation order guarantees that all predecessors |
+ // except for backwards edges have been visited. |
+ for (++pred; pred != end; ++pred) { |
+ // Don't examine backwards edges. |
+ if ((*pred)->dominator_depth() < 0) continue; |
+ dominator = GetCommonDominator(dominator, *pred); |
} |
+ current->set_dominator(dominator); |
+ current->set_dominator_depth(dominator->dominator_depth() + 1); |
+ Trace("Block B%d's idom is B%d, depth = %d\n", current->id().ToInt(), |
+ dominator->id().ToInt(), current->dominator_depth()); |
} |
} |
@@ -1087,8 +1151,10 @@ class ScheduleEarlyNodeVisitor { |
if (scheduler_->GetPlacement(node) == Scheduler::kFixed) { |
DCHECK_EQ(schedule_->start(), data->minimum_block_); |
data->minimum_block_ = schedule_->block(node); |
- Trace("Fixing #%d:%s minimum_rpo = %d\n", node->id(), |
- node->op()->mnemonic(), data->minimum_block_->rpo_number()); |
+ Trace("Fixing #%d:%s minimum_block = B%d, dominator_depth = %d\n", |
+ node->id(), node->op()->mnemonic(), |
+ data->minimum_block_->id().ToInt(), |
+ data->minimum_block_->dominator_depth()); |
} |
// No need to propagate unconstrained schedule early positions. |
@@ -1098,14 +1164,14 @@ class ScheduleEarlyNodeVisitor { |
DCHECK(data->minimum_block_ != NULL); |
Node::Uses uses = node->uses(); |
for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) { |
- PropagateMinimumRPOToNode(data->minimum_block_, *i); |
+ PropagateMinimumPositionToNode(data->minimum_block_, *i); |
} |
} |
- // Propagates {block} as another minimum RPO placement into the given {node}. |
- // This has the net effect of computing the maximum of the minimum RPOs for |
- // all inputs to {node} when the queue has been fully processed. |
- void PropagateMinimumRPOToNode(BasicBlock* block, Node* node) { |
+ // Propagates {block} as another minimum position into the given {node}. This |
+ // has the net effect of computing the minimum dominator block of {node} that |
+ // still post-dominates all inputs to {node} when the queue is processed. |
+ void PropagateMinimumPositionToNode(BasicBlock* block, Node* node) { |
Scheduler::SchedulerData* data = scheduler_->GetData(node); |
// No need to propagate to fixed node, it's guaranteed to be a root. |
@@ -1114,18 +1180,30 @@ class ScheduleEarlyNodeVisitor { |
// Coupled nodes influence schedule early position of their control. |
if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) { |
Node* control = NodeProperties::GetControlInput(node); |
- PropagateMinimumRPOToNode(block, control); |
+ PropagateMinimumPositionToNode(block, control); |
} |
- // Propagate new position if it is larger than the current. |
- if (block->rpo_number() > data->minimum_block_->rpo_number()) { |
+ // Propagate new position if it is deeper down the dominator tree than the |
+ // current. Note that all inputs need to have minimum block position inside |
+ // the dominator chain of {node}'s minimum block position. |
+ DCHECK(InsideSameDominatorChain(block, data->minimum_block_)); |
+ if (block->dominator_depth() > data->minimum_block_->dominator_depth()) { |
data->minimum_block_ = block; |
queue_.push(node); |
- Trace("Propagating #%d:%s minimum_rpo = %d\n", node->id(), |
- node->op()->mnemonic(), data->minimum_block_->rpo_number()); |
+ Trace("Propagating #%d:%s minimum_block = B%d, dominator_depth = %d\n", |
+ node->id(), node->op()->mnemonic(), |
+ data->minimum_block_->id().ToInt(), |
+ data->minimum_block_->dominator_depth()); |
} |
} |
+#if DEBUG |
+ bool InsideSameDominatorChain(BasicBlock* b1, BasicBlock* b2) { |
+ BasicBlock* dominator = scheduler_->GetCommonDominator(b1, b2); |
+ return dominator == b1 || dominator == b2; |
+ } |
+#endif |
+ |
Scheduler* scheduler_; |
Schedule* schedule_; |
ZoneQueue<Node*> queue_; |
@@ -1136,14 +1214,13 @@ void Scheduler::ScheduleEarly() { |
Trace("--- SCHEDULE EARLY -----------------------------------------\n"); |
if (FLAG_trace_turbo_scheduler) { |
Trace("roots: "); |
- for (NodeVectorIter i = schedule_root_nodes_.begin(); |
- i != schedule_root_nodes_.end(); ++i) { |
- Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic()); |
+ for (Node* node : schedule_root_nodes_) { |
+ Trace("#%d:%s ", node->id(), node->op()->mnemonic()); |
} |
Trace("\n"); |
} |
- // Compute the minimum RPO for each node thereby determining the earliest |
+ // Compute the minimum block for each node thereby determining the earliest |
// position each node could be placed within a valid schedule. |
ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this); |
schedule_early_visitor.Run(&schedule_root_nodes_); |
@@ -1204,17 +1281,20 @@ class ScheduleLateNodeVisitor { |
BasicBlock* block = GetCommonDominatorOfUses(node); |
DCHECK_NOT_NULL(block); |
- int min_rpo = scheduler_->GetData(node)->minimum_block_->rpo_number(); |
- Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n", |
+ // The schedule early block dominates the schedule late block. |
+ BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_; |
+ DCHECK_EQ(min_block, scheduler_->GetCommonDominator(block, min_block)); |
+ Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum = B%d\n", |
node->id(), node->op()->mnemonic(), block->id().ToInt(), |
- block->loop_depth(), min_rpo); |
+ block->loop_depth(), min_block->id().ToInt()); |
// Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
- // into enclosing loop pre-headers until they would preceed their |
- // ScheduleEarly position. |
+ // into enclosing loop pre-headers until they would preceed their schedule |
+ // early position. |
BasicBlock* hoist_block = GetPreHeader(block); |
- while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { |
- Trace(" hoisting #%d:%s to block %d\n", node->id(), |
+ while (hoist_block != NULL && |
+ hoist_block->dominator_depth() >= min_block->dominator_depth()) { |
+ Trace(" hoisting #%d:%s to block B%d\n", node->id(), |
node->op()->mnemonic(), hoist_block->id().ToInt()); |
DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); |
block = hoist_block; |
@@ -1302,9 +1382,8 @@ void Scheduler::ScheduleLate() { |
Trace("--- SCHEDULE LATE ------------------------------------------\n"); |
if (FLAG_trace_turbo_scheduler) { |
Trace("roots: "); |
- for (NodeVectorIter i = schedule_root_nodes_.begin(); |
- i != schedule_root_nodes_.end(); ++i) { |
- Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic()); |
+ for (Node* node : schedule_root_nodes_) { |
+ Trace("#%d:%s ", node->id(), node->op()->mnemonic()); |
} |
Trace("\n"); |
} |
@@ -1312,15 +1391,29 @@ void Scheduler::ScheduleLate() { |
// Schedule: Places nodes in dominator block of all their uses. |
ScheduleLateNodeVisitor schedule_late_visitor(zone_, this); |
schedule_late_visitor.Run(&schedule_root_nodes_); |
+} |
+ |
+ |
+// ----------------------------------------------------------------------------- |
+// Phase 6: Seal the final schedule. |
+ |
+ |
+void Scheduler::SealFinalSchedule() { |
+ Trace("--- SEAL FINAL SCHEDULE ------------------------------------\n"); |
+ |
+ // Serialize the assembly order and reverse-post-order numbering. |
+ special_rpo_->SerializeAOIntoSchedule(); |
+ special_rpo_->SerializeRPOIntoSchedule(); |
+ special_rpo_->PrintAndVerifySpecialRPO(); |
// Add collected nodes for basic blocks to their blocks in the right order. |
int block_num = 0; |
- for (NodeVectorVectorIter i = scheduled_nodes_.begin(); |
- i != scheduled_nodes_.end(); ++i) { |
- for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) { |
- schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); |
+ for (NodeVector& nodes : scheduled_nodes_) { |
+ BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++); |
+ BasicBlock* block = schedule_->GetBlockById(id); |
+ for (NodeVectorRIter i = nodes.rbegin(); i != nodes.rend(); ++i) { |
+ schedule_->AddNode(block, *i); |
} |
- block_num++; |
} |
} |
@@ -1341,27 +1434,22 @@ void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) { |
// Iterate on phase 2: Compute special RPO and dominator tree. |
// TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that. |
- BasicBlockVector* rpo = schedule_->rpo_order(); |
- for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) { |
- BasicBlock* block = *i; |
+ for (BasicBlock* block : schedule_->all_blocks_) { |
block->set_rpo_number(-1); |
- block->set_loop_header(NULL); |
- block->set_loop_depth(0); |
- block->set_loop_end(-1); |
+ block->set_dominator_depth(-1); |
+ block->set_dominator(NULL); |
} |
- schedule_->rpo_order()->clear(); |
- SpecialRPONumberer numberer(zone_, schedule_); |
- numberer.ComputeSpecialRPO(); |
+ special_rpo_->UpdateSpecialRPO(block, schedule_->block(node)); |
GenerateImmediateDominatorTree(); |
- scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); |
// Move previously planned nodes. |
// TODO(mstarzinger): Improve that by supporting bulk moves. |
+ scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); |
MovePlannedNodes(block, schedule_->block(node)); |
if (FLAG_trace_turbo_scheduler) { |
OFStream os(stdout); |
- os << "Schedule after control flow fusion:" << *schedule_; |
+ os << "Schedule after control flow fusion:\n" << *schedule_; |
} |
} |