| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/scheduler.h" | 5 #include "src/compiler/scheduler.h" |
| 6 | 6 |
| 7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
| 8 #include "src/compiler/graph-inl.h" | 8 #include "src/compiler/graph-inl.h" |
| 9 #include "src/compiler/node.h" | 9 #include "src/compiler/node.h" |
| 10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
| 11 #include "src/compiler/node-properties-inl.h" | 11 #include "src/compiler/node-properties-inl.h" |
| 12 #include "src/data-flow.h" | 12 #include "src/data-flow.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 namespace compiler { | 16 namespace compiler { |
| 17 | 17 |
| 18 static inline void Trace(const char* msg, ...) { |
| 19 if (FLAG_trace_turbo_scheduler) { |
| 20 va_list arguments; |
| 21 va_start(arguments, msg); |
| 22 base::OS::VPrint(msg, arguments); |
| 23 va_end(arguments); |
| 24 } |
| 25 } |
| 26 |
| 27 |
| 28 // Internal class to build a control flow graph (i.e the basic blocks and edges |
| 29 // between them within a Schedule) from the node graph. |
| 30 // Visits the graph backwards from end, following control and data edges. |
| 31 class CFGBuilder : public NullNodeVisitor { |
| 32 public: |
| 33 Schedule* schedule_; |
| 34 |
| 35 explicit CFGBuilder(Schedule* schedule) : schedule_(schedule) {} |
| 36 |
| 37 // Create the blocks for the schedule in pre-order. |
| 38 void PreEdge(Node* from, int index, Node* node) { |
| 39 switch (node->opcode()) { |
| 40 case IrOpcode::kLoop: |
| 41 case IrOpcode::kMerge: |
| 42 BuildBlockForNode(node); |
| 43 break; |
| 44 case IrOpcode::kBranch: |
| 45 BuildBlocksForSuccessors(node, IrOpcode::kIfTrue, IrOpcode::kIfFalse); |
| 46 break; |
| 47 case IrOpcode::kCall: |
| 48 if (OperatorProperties::CanLazilyDeoptimize(node->op())) { |
| 49 BuildBlocksForSuccessors(node, IrOpcode::kContinuation, |
| 50 IrOpcode::kLazyDeoptimization); |
| 51 } |
| 52 break; |
| 53 default: |
| 54 break; |
| 55 } |
| 56 } |
| 57 |
| 58 // Connect the blocks after nodes have been visited in post-order. |
| 59 GenericGraphVisit::Control Post(Node* node) { |
| 60 switch (node->opcode()) { |
| 61 case IrOpcode::kLoop: |
| 62 case IrOpcode::kMerge: |
| 63 ConnectMerge(node); |
| 64 break; |
| 65 case IrOpcode::kBranch: |
| 66 ConnectBranch(node); |
| 67 break; |
| 68 case IrOpcode::kDeoptimize: |
| 69 ConnectDeoptimize(node); |
| 70 case IrOpcode::kCall: |
| 71 if (OperatorProperties::CanLazilyDeoptimize(node->op())) { |
| 72 ConnectCall(node); |
| 73 } |
| 74 break; |
| 75 case IrOpcode::kReturn: |
| 76 ConnectReturn(node); |
| 77 break; |
| 78 default: |
| 79 break; |
| 80 } |
| 81 return GenericGraphVisit::CONTINUE; |
| 82 } |
| 83 |
| 84 void BuildBlockForNode(Node* node) { |
| 85 if (schedule_->block(node) == NULL) { |
| 86 BasicBlock* block = schedule_->NewBasicBlock(); |
| 87 Trace("Create block B%d for node %d (%s)\n", block->id(), node->id(), |
| 88 IrOpcode::Mnemonic(node->opcode())); |
| 89 schedule_->AddNode(block, node); |
| 90 } |
| 91 } |
| 92 |
| 93 void BuildBlocksForSuccessors(Node* node, IrOpcode::Value a, |
| 94 IrOpcode::Value b) { |
| 95 Node* successors[2]; |
| 96 CollectSuccessorProjections(node, successors, a, b); |
| 97 BuildBlockForNode(successors[0]); |
| 98 BuildBlockForNode(successors[1]); |
| 99 } |
| 100 |
| 101 // Collect the branch-related projections from a node, such as IfTrue, |
| 102 // IfFalse, Continuation, and LazyDeoptimization. |
| 103 // TODO(titzer): consider moving this to node.h |
| 104 void CollectSuccessorProjections(Node* node, Node** buffer, |
| 105 IrOpcode::Value true_opcode, |
| 106 IrOpcode::Value false_opcode) { |
| 107 buffer[0] = NULL; |
| 108 buffer[1] = NULL; |
| 109 for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) { |
| 110 if ((*i)->opcode() == true_opcode) { |
| 111 DCHECK_EQ(NULL, buffer[0]); |
| 112 buffer[0] = *i; |
| 113 } |
| 114 if ((*i)->opcode() == false_opcode) { |
| 115 DCHECK_EQ(NULL, buffer[1]); |
| 116 buffer[1] = *i; |
| 117 } |
| 118 } |
| 119 DCHECK_NE(NULL, buffer[0]); |
| 120 DCHECK_NE(NULL, buffer[1]); |
| 121 } |
| 122 |
| 123 void CollectSuccessorBlocks(Node* node, BasicBlock** buffer, |
| 124 IrOpcode::Value true_opcode, |
| 125 IrOpcode::Value false_opcode) { |
| 126 Node* successors[2]; |
| 127 CollectSuccessorProjections(node, successors, true_opcode, false_opcode); |
| 128 buffer[0] = schedule_->block(successors[0]); |
| 129 buffer[1] = schedule_->block(successors[1]); |
| 130 } |
| 131 |
| 132 void ConnectBranch(Node* branch) { |
| 133 Node* branch_block_node = NodeProperties::GetControlInput(branch); |
| 134 BasicBlock* branch_block = schedule_->block(branch_block_node); |
| 135 DCHECK(branch_block != NULL); |
| 136 |
| 137 BasicBlock* successor_blocks[2]; |
| 138 CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue, |
| 139 IrOpcode::kIfFalse); |
| 140 |
| 141 TraceConnect(branch, branch_block, successor_blocks[0]); |
| 142 TraceConnect(branch, branch_block, successor_blocks[1]); |
| 143 |
| 144 schedule_->AddBranch(branch_block, branch, successor_blocks[0], |
| 145 successor_blocks[1]); |
| 146 } |
| 147 |
| 148 void ConnectMerge(Node* merge) { |
| 149 BasicBlock* block = schedule_->block(merge); |
| 150 DCHECK(block != NULL); |
| 151 // For all of the merge's control inputs, add a goto at the end to the |
| 152 // merge's basic block. |
| 153 for (InputIter j = merge->inputs().begin(); j != merge->inputs().end(); |
| 154 ++j) { |
| 155 BasicBlock* predecessor_block = schedule_->block(*j); |
| 156 if ((*j)->opcode() != IrOpcode::kReturn && |
| 157 (*j)->opcode() != IrOpcode::kDeoptimize) { |
| 158 TraceConnect(merge, predecessor_block, block); |
| 159 schedule_->AddGoto(predecessor_block, block); |
| 160 } |
| 161 } |
| 162 } |
| 163 |
| 164 void ConnectDeoptimize(Node* deopt) { |
| 165 Node* deopt_block_node = NodeProperties::GetControlInput(deopt); |
| 166 BasicBlock* deopt_block = schedule_->block(deopt_block_node); |
| 167 TraceConnect(deopt, deopt_block, NULL); |
| 168 schedule_->AddDeoptimize(deopt_block, deopt); |
| 169 } |
| 170 |
| 171 void ConnectReturn(Node* ret) { |
| 172 Node* return_block_node = NodeProperties::GetControlInput(ret); |
| 173 BasicBlock* return_block = schedule_->block(return_block_node); |
| 174 TraceConnect(ret, return_block, NULL); |
| 175 schedule_->AddReturn(return_block, ret); |
| 176 } |
| 177 |
| 178 void ConnectCall(Node* call) { |
| 179 Node* call_block_node = NodeProperties::GetControlInput(call); |
| 180 BasicBlock* call_block = schedule_->block(call_block_node); |
| 181 |
| 182 BasicBlock* successor_blocks[2]; |
| 183 CollectSuccessorBlocks(call, successor_blocks, IrOpcode::kContinuation, |
| 184 IrOpcode::kLazyDeoptimization); |
| 185 |
| 186 TraceConnect(call, call_block, successor_blocks[0]); |
| 187 TraceConnect(call, call_block, successor_blocks[1]); |
| 188 |
| 189 schedule_->AddCall(call_block, call, successor_blocks[0], |
| 190 successor_blocks[1]); |
| 191 } |
| 192 |
| 193 void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) { |
| 194 DCHECK_NE(NULL, block); |
| 195 if (succ == NULL) { |
| 196 Trace("node %d (%s) in block %d -> end\n", node->id(), |
| 197 IrOpcode::Mnemonic(node->opcode()), block->id()); |
| 198 } else { |
| 199 Trace("node %d (%s) in block %d -> block %d\n", node->id(), |
| 200 IrOpcode::Mnemonic(node->opcode()), block->id(), succ->id()); |
| 201 } |
| 202 } |
| 203 }; |
| 204 |
| 205 |
| 18 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) | 206 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) |
| 19 : zone_(zone), | 207 : zone_(zone), |
| 20 graph_(graph), | 208 graph_(graph), |
| 21 schedule_(schedule), | 209 schedule_(schedule), |
| 22 branches_(NodeVector::allocator_type(zone)), | |
| 23 calls_(NodeVector::allocator_type(zone)), | |
| 24 deopts_(NodeVector::allocator_type(zone)), | |
| 25 returns_(NodeVector::allocator_type(zone)), | |
| 26 loops_and_merges_(NodeVector::allocator_type(zone)), | |
| 27 unscheduled_uses_(IntVector::allocator_type(zone)), | 210 unscheduled_uses_(IntVector::allocator_type(zone)), |
| 28 scheduled_nodes_(NodeVectorVector::allocator_type(zone)), | 211 scheduled_nodes_(NodeVectorVector::allocator_type(zone)), |
| 29 schedule_root_nodes_(NodeVector::allocator_type(zone)), | 212 schedule_root_nodes_(NodeVector::allocator_type(zone)), |
| 30 schedule_early_rpo_index_(IntVector::allocator_type(zone)) {} | 213 schedule_early_rpo_index_(IntVector::allocator_type(zone)) {} |
| 31 | 214 |
| 32 | 215 |
| 33 Schedule* Scheduler::ComputeSchedule(Graph* graph) { | 216 Schedule* Scheduler::ComputeSchedule(Graph* graph) { |
| 34 Zone tmp_zone(graph->zone()->isolate()); | 217 Zone tmp_zone(graph->zone()->isolate()); |
| 35 Schedule* schedule = new (graph->zone()) Schedule(graph->zone()); | 218 Schedule* schedule = new (graph->zone()) Schedule(graph->zone()); |
| 219 |
| 220 Scheduler::ComputeCFG(graph, schedule); |
| 221 |
| 36 Scheduler scheduler(&tmp_zone, graph, schedule); | 222 Scheduler scheduler(&tmp_zone, graph, schedule); |
| 37 | 223 |
| 38 schedule->AddNode(schedule->end(), graph->end()); | 224 scheduler.PrepareAuxiliaryNodeData(); |
| 39 | 225 |
| 40 scheduler.PrepareAuxiliaryNodeData(); | |
| 41 scheduler.CreateBlocks(); | |
| 42 scheduler.WireBlocks(); | |
| 43 scheduler.PrepareAuxiliaryBlockData(); | 226 scheduler.PrepareAuxiliaryBlockData(); |
| 44 | 227 |
| 45 Scheduler::ComputeSpecialRPO(schedule); | 228 Scheduler::ComputeSpecialRPO(schedule); |
| 46 scheduler.GenerateImmediateDominatorTree(); | 229 scheduler.GenerateImmediateDominatorTree(); |
| 47 | 230 |
| 48 scheduler.PrepareUses(); | 231 scheduler.PrepareUses(); |
| 49 scheduler.ScheduleEarly(); | 232 scheduler.ScheduleEarly(); |
| 50 scheduler.ScheduleLate(); | 233 scheduler.ScheduleLate(); |
| 51 | 234 |
| 52 return schedule; | 235 return schedule; |
| 53 } | 236 } |
| 54 | 237 |
| 55 | 238 |
| 56 bool Scheduler::IsBasicBlockBegin(Node* node) { | 239 bool Scheduler::IsBasicBlockBegin(Node* node) { |
| 57 return OperatorProperties::IsBasicBlockBegin(node->op()); | 240 return OperatorProperties::IsBasicBlockBegin(node->op()); |
| 58 } | 241 } |
| 59 | 242 |
| 60 | 243 |
| 61 bool Scheduler::CanBeScheduled(Node* node) { return true; } | |
| 62 | |
| 63 | |
| 64 bool Scheduler::HasFixedSchedulePosition(Node* node) { | 244 bool Scheduler::HasFixedSchedulePosition(Node* node) { |
| 65 IrOpcode::Value opcode = node->opcode(); | 245 IrOpcode::Value opcode = node->opcode(); |
| 66 return (IrOpcode::IsControlOpcode(opcode)) || | 246 return (IrOpcode::IsControlOpcode(opcode)) || |
| 67 opcode == IrOpcode::kParameter || opcode == IrOpcode::kEffectPhi || | 247 opcode == IrOpcode::kParameter || opcode == IrOpcode::kEffectPhi || |
| 68 opcode == IrOpcode::kPhi; | 248 opcode == IrOpcode::kPhi; |
| 69 } | 249 } |
| 70 | 250 |
| 71 | 251 |
| 72 bool Scheduler::IsScheduleRoot(Node* node) { | 252 bool Scheduler::IsScheduleRoot(Node* node) { |
| 73 IrOpcode::Value opcode = node->opcode(); | 253 IrOpcode::Value opcode = node->opcode(); |
| 74 return opcode == IrOpcode::kEnd || opcode == IrOpcode::kEffectPhi || | 254 return opcode == IrOpcode::kEnd || opcode == IrOpcode::kEffectPhi || |
| 75 opcode == IrOpcode::kPhi; | 255 opcode == IrOpcode::kPhi; |
| 76 } | 256 } |
| 77 | 257 |
| 78 | 258 |
| 79 class CreateBlockVisitor : public NullNodeVisitor { | 259 void Scheduler::ComputeCFG(Graph* graph, Schedule* schedule) { |
| 80 public: | 260 CFGBuilder cfg_builder(schedule); |
| 81 explicit CreateBlockVisitor(Scheduler* scheduler) : scheduler_(scheduler) {} | 261 Trace("---------------- CREATING CFG ------------------\n"); |
| 82 | 262 schedule->AddNode(schedule->start(), graph->start()); |
| 83 GenericGraphVisit::Control Post(Node* node) { | 263 graph->VisitNodeInputsFromEnd(&cfg_builder); |
| 84 Schedule* schedule = scheduler_->schedule_; | 264 schedule->AddNode(schedule->end(), graph->end()); |
| 85 switch (node->opcode()) { | |
| 86 case IrOpcode::kIfTrue: | |
| 87 case IrOpcode::kIfFalse: | |
| 88 case IrOpcode::kContinuation: | |
| 89 case IrOpcode::kLazyDeoptimization: { | |
| 90 BasicBlock* block = schedule->NewBasicBlock(); | |
| 91 schedule->AddNode(block, node); | |
| 92 break; | |
| 93 } | |
| 94 case IrOpcode::kLoop: | |
| 95 case IrOpcode::kMerge: { | |
| 96 BasicBlock* block = schedule->NewBasicBlock(); | |
| 97 schedule->AddNode(block, node); | |
| 98 scheduler_->loops_and_merges_.push_back(node); | |
| 99 break; | |
| 100 } | |
| 101 case IrOpcode::kBranch: { | |
| 102 scheduler_->branches_.push_back(node); | |
| 103 break; | |
| 104 } | |
| 105 case IrOpcode::kDeoptimize: { | |
| 106 scheduler_->deopts_.push_back(node); | |
| 107 break; | |
| 108 } | |
| 109 case IrOpcode::kCall: { | |
| 110 if (OperatorProperties::CanLazilyDeoptimize(node->op())) { | |
| 111 scheduler_->calls_.push_back(node); | |
| 112 } | |
| 113 break; | |
| 114 } | |
| 115 case IrOpcode::kReturn: | |
| 116 scheduler_->returns_.push_back(node); | |
| 117 break; | |
| 118 default: | |
| 119 break; | |
| 120 } | |
| 121 | |
| 122 return GenericGraphVisit::CONTINUE; | |
| 123 } | |
| 124 | |
| 125 private: | |
| 126 Scheduler* scheduler_; | |
| 127 }; | |
| 128 | |
| 129 | |
| 130 void Scheduler::CreateBlocks() { | |
| 131 CreateBlockVisitor create_blocks(this); | |
| 132 if (FLAG_trace_turbo_scheduler) { | |
| 133 PrintF("---------------- CREATING BLOCKS ------------------\n"); | |
| 134 } | |
| 135 schedule_->AddNode(schedule_->start(), graph_->start()); | |
| 136 graph_->VisitNodeInputsFromEnd(&create_blocks); | |
| 137 } | 265 } |
| 138 | 266 |
| 139 | 267 |
| 140 void Scheduler::WireBlocks() { | |
| 141 if (FLAG_trace_turbo_scheduler) { | |
| 142 PrintF("----------------- WIRING BLOCKS -------------------\n"); | |
| 143 } | |
| 144 AddSuccessorsForBranches(); | |
| 145 AddSuccessorsForReturns(); | |
| 146 AddSuccessorsForCalls(); | |
| 147 AddSuccessorsForDeopts(); | |
| 148 AddPredecessorsForLoopsAndMerges(); | |
| 149 // TODO(danno): Handle Throw, et al. | |
| 150 } | |
| 151 | |
| 152 | |
| 153 void Scheduler::PrepareAuxiliaryNodeData() { | 268 void Scheduler::PrepareAuxiliaryNodeData() { |
| 154 unscheduled_uses_.resize(graph_->NodeCount(), 0); | 269 unscheduled_uses_.resize(graph_->NodeCount(), 0); |
| 155 schedule_early_rpo_index_.resize(graph_->NodeCount(), 0); | 270 schedule_early_rpo_index_.resize(graph_->NodeCount(), 0); |
| 156 } | 271 } |
| 157 | 272 |
| 158 | 273 |
| 159 void Scheduler::PrepareAuxiliaryBlockData() { | 274 void Scheduler::PrepareAuxiliaryBlockData() { |
| 160 Zone* zone = schedule_->zone(); | 275 Zone* zone = schedule_->zone(); |
| 161 scheduled_nodes_.resize(schedule_->BasicBlockCount(), | 276 scheduled_nodes_.resize(schedule_->BasicBlockCount(), |
| 162 NodeVector(NodeVector::allocator_type(zone))); | 277 NodeVector(NodeVector::allocator_type(zone))); |
| 163 schedule_->immediate_dominator_.resize(schedule_->BasicBlockCount(), NULL); | 278 schedule_->immediate_dominator_.resize(schedule_->BasicBlockCount(), NULL); |
| 164 } | 279 } |
| 165 | 280 |
| 166 | 281 |
| 167 void Scheduler::AddPredecessorsForLoopsAndMerges() { | |
| 168 for (NodeVectorIter i = loops_and_merges_.begin(); | |
| 169 i != loops_and_merges_.end(); ++i) { | |
| 170 Node* merge_or_loop = *i; | |
| 171 BasicBlock* block = schedule_->block(merge_or_loop); | |
| 172 DCHECK(block != NULL); | |
| 173 // For all of the merge's control inputs, add a goto at the end to the | |
| 174 // merge's basic block. | |
| 175 for (InputIter j = (*i)->inputs().begin(); j != (*i)->inputs().end(); ++j) { | |
| 176 if (IsBasicBlockBegin((*i))) { | |
| 177 BasicBlock* predecessor_block = schedule_->block(*j); | |
| 178 if ((*j)->opcode() != IrOpcode::kReturn && | |
| 179 (*j)->opcode() != IrOpcode::kDeoptimize) { | |
| 180 DCHECK(predecessor_block != NULL); | |
| 181 if (FLAG_trace_turbo_scheduler) { | |
| 182 IrOpcode::Value opcode = (*i)->opcode(); | |
| 183 PrintF("node %d (%s) in block %d -> block %d\n", (*i)->id(), | |
| 184 IrOpcode::Mnemonic(opcode), predecessor_block->id(), | |
| 185 block->id()); | |
| 186 } | |
| 187 schedule_->AddGoto(predecessor_block, block); | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 | |
| 195 void Scheduler::AddSuccessorsForCalls() { | |
| 196 for (NodeVectorIter i = calls_.begin(); i != calls_.end(); ++i) { | |
| 197 Node* call = *i; | |
| 198 DCHECK(call->opcode() == IrOpcode::kCall); | |
| 199 DCHECK(OperatorProperties::CanLazilyDeoptimize(call->op())); | |
| 200 | |
| 201 Node* lazy_deopt_node = NULL; | |
| 202 Node* cont_node = NULL; | |
| 203 // Find the continuation and lazy-deopt nodes among the uses. | |
| 204 for (UseIter use_iter = call->uses().begin(); | |
| 205 use_iter != call->uses().end(); ++use_iter) { | |
| 206 switch ((*use_iter)->opcode()) { | |
| 207 case IrOpcode::kContinuation: { | |
| 208 DCHECK(cont_node == NULL); | |
| 209 cont_node = *use_iter; | |
| 210 break; | |
| 211 } | |
| 212 case IrOpcode::kLazyDeoptimization: { | |
| 213 DCHECK(lazy_deopt_node == NULL); | |
| 214 lazy_deopt_node = *use_iter; | |
| 215 break; | |
| 216 } | |
| 217 default: | |
| 218 break; | |
| 219 } | |
| 220 } | |
| 221 DCHECK(lazy_deopt_node != NULL); | |
| 222 DCHECK(cont_node != NULL); | |
| 223 BasicBlock* cont_successor_block = schedule_->block(cont_node); | |
| 224 BasicBlock* deopt_successor_block = schedule_->block(lazy_deopt_node); | |
| 225 Node* call_block_node = NodeProperties::GetControlInput(call); | |
| 226 BasicBlock* call_block = schedule_->block(call_block_node); | |
| 227 if (FLAG_trace_turbo_scheduler) { | |
| 228 IrOpcode::Value opcode = call->opcode(); | |
| 229 PrintF("node %d (%s) in block %d -> block %d\n", call->id(), | |
| 230 IrOpcode::Mnemonic(opcode), call_block->id(), | |
| 231 cont_successor_block->id()); | |
| 232 PrintF("node %d (%s) in block %d -> block %d\n", call->id(), | |
| 233 IrOpcode::Mnemonic(opcode), call_block->id(), | |
| 234 deopt_successor_block->id()); | |
| 235 } | |
| 236 schedule_->AddCall(call_block, call, cont_successor_block, | |
| 237 deopt_successor_block); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 | |
| 242 void Scheduler::AddSuccessorsForDeopts() { | |
| 243 for (NodeVectorIter i = deopts_.begin(); i != deopts_.end(); ++i) { | |
| 244 Node* deopt_block_node = NodeProperties::GetControlInput(*i); | |
| 245 BasicBlock* deopt_block = schedule_->block(deopt_block_node); | |
| 246 DCHECK(deopt_block != NULL); | |
| 247 if (FLAG_trace_turbo_scheduler) { | |
| 248 IrOpcode::Value opcode = (*i)->opcode(); | |
| 249 PrintF("node %d (%s) in block %d -> end\n", (*i)->id(), | |
| 250 IrOpcode::Mnemonic(opcode), deopt_block->id()); | |
| 251 } | |
| 252 schedule_->AddDeoptimize(deopt_block, *i); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 | |
| 257 void Scheduler::AddSuccessorsForBranches() { | |
| 258 for (NodeVectorIter i = branches_.begin(); i != branches_.end(); ++i) { | |
| 259 Node* branch = *i; | |
| 260 DCHECK(branch->opcode() == IrOpcode::kBranch); | |
| 261 Node* branch_block_node = NodeProperties::GetControlInput(branch); | |
| 262 BasicBlock* branch_block = schedule_->block(branch_block_node); | |
| 263 DCHECK(branch_block != NULL); | |
| 264 UseIter use_iter = branch->uses().begin(); | |
| 265 Node* first_successor = *use_iter; | |
| 266 ++use_iter; | |
| 267 DCHECK(use_iter != branch->uses().end()); | |
| 268 Node* second_successor = *use_iter; | |
| 269 DCHECK(++use_iter == branch->uses().end()); | |
| 270 Node* true_successor_node = first_successor->opcode() == IrOpcode::kIfTrue | |
| 271 ? first_successor | |
| 272 : second_successor; | |
| 273 Node* false_successor_node = first_successor->opcode() == IrOpcode::kIfTrue | |
| 274 ? second_successor | |
| 275 : first_successor; | |
| 276 DCHECK(true_successor_node->opcode() == IrOpcode::kIfTrue); | |
| 277 DCHECK(false_successor_node->opcode() == IrOpcode::kIfFalse); | |
| 278 BasicBlock* true_successor_block = schedule_->block(true_successor_node); | |
| 279 BasicBlock* false_successor_block = schedule_->block(false_successor_node); | |
| 280 DCHECK(true_successor_block != NULL); | |
| 281 DCHECK(false_successor_block != NULL); | |
| 282 if (FLAG_trace_turbo_scheduler) { | |
| 283 IrOpcode::Value opcode = branch->opcode(); | |
| 284 PrintF("node %d (%s) in block %d -> block %d\n", branch->id(), | |
| 285 IrOpcode::Mnemonic(opcode), branch_block->id(), | |
| 286 true_successor_block->id()); | |
| 287 PrintF("node %d (%s) in block %d -> block %d\n", branch->id(), | |
| 288 IrOpcode::Mnemonic(opcode), branch_block->id(), | |
| 289 false_successor_block->id()); | |
| 290 } | |
| 291 schedule_->AddBranch(branch_block, branch, true_successor_block, | |
| 292 false_successor_block); | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 | |
| 297 void Scheduler::AddSuccessorsForReturns() { | |
| 298 for (NodeVectorIter i = returns_.begin(); i != returns_.end(); ++i) { | |
| 299 Node* return_block_node = NodeProperties::GetControlInput(*i); | |
| 300 BasicBlock* return_block = schedule_->block(return_block_node); | |
| 301 DCHECK(return_block != NULL); | |
| 302 if (FLAG_trace_turbo_scheduler) { | |
| 303 IrOpcode::Value opcode = (*i)->opcode(); | |
| 304 PrintF("node %d (%s) in block %d -> end\n", (*i)->id(), | |
| 305 IrOpcode::Mnemonic(opcode), return_block->id()); | |
| 306 } | |
| 307 schedule_->AddReturn(return_block, *i); | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 | |
| 312 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { | 282 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { |
| 313 while (b1 != b2) { | 283 while (b1 != b2) { |
| 314 int b1_rpo = GetRPONumber(b1); | 284 int b1_rpo = GetRPONumber(b1); |
| 315 int b2_rpo = GetRPONumber(b2); | 285 int b2_rpo = GetRPONumber(b2); |
| 316 DCHECK(b1_rpo != b2_rpo); | 286 DCHECK(b1_rpo != b2_rpo); |
| 317 if (b1_rpo < b2_rpo) { | 287 if (b1_rpo < b2_rpo) { |
| 318 b2 = schedule_->immediate_dominator_[b2->id()]; | 288 b2 = schedule_->immediate_dominator_[b2->id()]; |
| 319 } else { | 289 } else { |
| 320 b1 = schedule_->immediate_dominator_[b1->id()]; | 290 b1 = schedule_->immediate_dominator_[b1->id()]; |
| 321 } | 291 } |
| 322 } | 292 } |
| 323 return b1; | 293 return b1; |
| 324 } | 294 } |
| 325 | 295 |
| 326 | 296 |
| 327 void Scheduler::GenerateImmediateDominatorTree() { | 297 void Scheduler::GenerateImmediateDominatorTree() { |
| 328 // Build the dominator graph. TODO(danno): consider using Lengauer & Tarjan's | 298 // Build the dominator graph. TODO(danno): consider using Lengauer & Tarjan's |
| 329 // if this becomes really slow. | 299 // if this becomes really slow. |
| 330 if (FLAG_trace_turbo_scheduler) { | 300 Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n"); |
| 331 PrintF("------------ IMMEDIATE BLOCK DOMINATORS -----------\n"); | |
| 332 } | |
| 333 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { | 301 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { |
| 334 BasicBlock* current_rpo = schedule_->rpo_order_[i]; | 302 BasicBlock* current_rpo = schedule_->rpo_order_[i]; |
| 335 if (current_rpo != schedule_->start()) { | 303 if (current_rpo != schedule_->start()) { |
| 336 BasicBlock::Predecessors::iterator current_pred = | 304 BasicBlock::Predecessors::iterator current_pred = |
| 337 current_rpo->predecessors().begin(); | 305 current_rpo->predecessors().begin(); |
| 338 BasicBlock::Predecessors::iterator end = | 306 BasicBlock::Predecessors::iterator end = |
| 339 current_rpo->predecessors().end(); | 307 current_rpo->predecessors().end(); |
| 340 DCHECK(current_pred != end); | 308 DCHECK(current_pred != end); |
| 341 BasicBlock* dominator = *current_pred; | 309 BasicBlock* dominator = *current_pred; |
| 342 ++current_pred; | 310 ++current_pred; |
| 343 // For multiple predecessors, walk up the rpo ordering until a common | 311 // For multiple predecessors, walk up the rpo ordering until a common |
| 344 // dominator is found. | 312 // dominator is found. |
| 345 int current_rpo_pos = GetRPONumber(current_rpo); | 313 int current_rpo_pos = GetRPONumber(current_rpo); |
| 346 while (current_pred != end) { | 314 while (current_pred != end) { |
| 347 // Don't examine backwards edges | 315 // Don't examine backwards edges |
| 348 BasicBlock* pred = *current_pred; | 316 BasicBlock* pred = *current_pred; |
| 349 if (GetRPONumber(pred) < current_rpo_pos) { | 317 if (GetRPONumber(pred) < current_rpo_pos) { |
| 350 dominator = GetCommonDominator(dominator, *current_pred); | 318 dominator = GetCommonDominator(dominator, *current_pred); |
| 351 } | 319 } |
| 352 ++current_pred; | 320 ++current_pred; |
| 353 } | 321 } |
| 354 schedule_->immediate_dominator_[current_rpo->id()] = dominator; | 322 schedule_->immediate_dominator_[current_rpo->id()] = dominator; |
| 355 if (FLAG_trace_turbo_scheduler) { | 323 Trace("Block %d's idom is %d\n", current_rpo->id(), dominator->id()); |
| 356 PrintF("Block %d's idom is %d\n", current_rpo->id(), dominator->id()); | |
| 357 } | |
| 358 } | 324 } |
| 359 } | 325 } |
| 360 } | 326 } |
| 361 | 327 |
| 362 | 328 |
| 363 class ScheduleEarlyNodeVisitor : public NullNodeVisitor { | 329 class ScheduleEarlyNodeVisitor : public NullNodeVisitor { |
| 364 public: | 330 public: |
| 365 explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler) | 331 explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler) |
| 366 : has_changed_rpo_constraints_(true), | 332 : has_changed_rpo_constraints_(true), |
| 367 scheduler_(scheduler), | 333 scheduler_(scheduler), |
| 368 schedule_(scheduler->schedule_) {} | 334 schedule_(scheduler->schedule_) {} |
| 369 | 335 |
| 370 GenericGraphVisit::Control Pre(Node* node) { | 336 GenericGraphVisit::Control Pre(Node* node) { |
| 371 int id = node->id(); | 337 int id = node->id(); |
| 372 int max_rpo = 0; | 338 int max_rpo = 0; |
| 373 // Fixed nodes already know their schedule early position. | 339 // Fixed nodes already know their schedule early position. |
| 374 if (IsFixedNode(node)) { | 340 if (scheduler_->HasFixedSchedulePosition(node)) { |
| 375 BasicBlock* block = schedule_->block(node); | 341 BasicBlock* block = schedule_->block(node); |
| 376 DCHECK(block != NULL); | 342 DCHECK(block != NULL); |
| 377 max_rpo = block->rpo_number_; | 343 max_rpo = block->rpo_number_; |
| 378 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { | 344 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { |
| 379 has_changed_rpo_constraints_ = true; | 345 has_changed_rpo_constraints_ = true; |
| 380 } | 346 } |
| 381 scheduler_->schedule_early_rpo_index_[id] = max_rpo; | 347 scheduler_->schedule_early_rpo_index_[id] = max_rpo; |
| 382 if (FLAG_trace_turbo_scheduler) { | 348 Trace("Node %d pre-scheduled early at rpo limit %d\n", id, max_rpo); |
| 383 PrintF("Node %d pre-scheduled early at rpo limit %d\n", id, max_rpo); | |
| 384 } | |
| 385 } | 349 } |
| 386 return GenericGraphVisit::CONTINUE; | 350 return GenericGraphVisit::CONTINUE; |
| 387 } | 351 } |
| 388 | 352 |
| 389 GenericGraphVisit::Control Post(Node* node) { | 353 GenericGraphVisit::Control Post(Node* node) { |
| 390 int id = node->id(); | 354 int id = node->id(); |
| 391 int max_rpo = 0; | 355 int max_rpo = 0; |
| 392 // Otherwise, the minimum rpo for the node is the max of all of the inputs. | 356 // Otherwise, the minimum rpo for the node is the max of all of the inputs. |
| 393 if (!IsFixedNode(node)) { | 357 if (!scheduler_->HasFixedSchedulePosition(node)) { |
| 394 DCHECK(!scheduler_->IsBasicBlockBegin(node)); | |
| 395 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); | 358 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); |
| 396 ++i) { | 359 ++i) { |
| 397 int control_rpo = scheduler_->schedule_early_rpo_index_[(*i)->id()]; | 360 int control_rpo = scheduler_->schedule_early_rpo_index_[(*i)->id()]; |
| 398 if (control_rpo > max_rpo) { | 361 if (control_rpo > max_rpo) { |
| 399 max_rpo = control_rpo; | 362 max_rpo = control_rpo; |
| 400 } | 363 } |
| 401 } | 364 } |
| 402 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { | 365 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { |
| 403 has_changed_rpo_constraints_ = true; | 366 has_changed_rpo_constraints_ = true; |
| 404 } | 367 } |
| 405 scheduler_->schedule_early_rpo_index_[id] = max_rpo; | 368 scheduler_->schedule_early_rpo_index_[id] = max_rpo; |
| 406 if (FLAG_trace_turbo_scheduler) { | 369 Trace("Node %d post-scheduled early at rpo limit %d\n", id, max_rpo); |
| 407 PrintF("Node %d post-scheduled early at rpo limit %d\n", id, max_rpo); | |
| 408 } | |
| 409 } | 370 } |
| 410 return GenericGraphVisit::CONTINUE; | 371 return GenericGraphVisit::CONTINUE; |
| 411 } | 372 } |
| 412 | 373 |
| 413 bool IsFixedNode(Node* node) { | |
| 414 return scheduler_->HasFixedSchedulePosition(node) || | |
| 415 !scheduler_->CanBeScheduled(node); | |
| 416 } | |
| 417 | |
| 418 // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be | 374 // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be |
| 419 // rewritten to use a pre-order traversal from the start instead. | 375 // rewritten to use a pre-order traversal from the start instead. |
| 420 bool has_changed_rpo_constraints_; | 376 bool has_changed_rpo_constraints_; |
| 421 | 377 |
| 422 private: | 378 private: |
| 423 Scheduler* scheduler_; | 379 Scheduler* scheduler_; |
| 424 Schedule* schedule_; | 380 Schedule* schedule_; |
| 425 }; | 381 }; |
| 426 | 382 |
| 427 | 383 |
| 428 void Scheduler::ScheduleEarly() { | 384 void Scheduler::ScheduleEarly() { |
| 429 if (FLAG_trace_turbo_scheduler) { | 385 Trace("------------------- SCHEDULE EARLY ----------------\n"); |
| 430 PrintF("------------------- SCHEDULE EARLY ----------------\n"); | |
| 431 } | |
| 432 | 386 |
| 433 int fixpoint_count = 0; | 387 int fixpoint_count = 0; |
| 434 ScheduleEarlyNodeVisitor visitor(this); | 388 ScheduleEarlyNodeVisitor visitor(this); |
| 435 while (visitor.has_changed_rpo_constraints_) { | 389 while (visitor.has_changed_rpo_constraints_) { |
| 436 visitor.has_changed_rpo_constraints_ = false; | 390 visitor.has_changed_rpo_constraints_ = false; |
| 437 graph_->VisitNodeInputsFromEnd(&visitor); | 391 graph_->VisitNodeInputsFromEnd(&visitor); |
| 438 fixpoint_count++; | 392 fixpoint_count++; |
| 439 } | 393 } |
| 440 | 394 |
| 441 if (FLAG_trace_turbo_scheduler) { | 395 Trace("It took %d iterations to determine fixpoint\n", fixpoint_count); |
| 442 PrintF("It took %d iterations to determine fixpoint\n", fixpoint_count); | |
| 443 } | |
| 444 } | 396 } |
| 445 | 397 |
| 446 | 398 |
| 447 class PrepareUsesVisitor : public NullNodeVisitor { | 399 class PrepareUsesVisitor : public NullNodeVisitor { |
| 448 public: | 400 public: |
| 449 explicit PrepareUsesVisitor(Scheduler* scheduler) | 401 explicit PrepareUsesVisitor(Scheduler* scheduler) |
| 450 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} | 402 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} |
| 451 | 403 |
| 452 GenericGraphVisit::Control Pre(Node* node) { | 404 GenericGraphVisit::Control Pre(Node* node) { |
| 453 // Some nodes must be scheduled explicitly to ensure they are in exactly the | 405 // Some nodes must be scheduled explicitly to ensure they are in exactly the |
| 454 // right place; it's a convenient place during the preparation of use counts | 406 // right place; it's a convenient place during the preparation of use counts |
| 455 // to schedule them. | 407 // to schedule them. |
| 456 if (!schedule_->IsScheduled(node) && | 408 if (!schedule_->IsScheduled(node) && |
| 457 scheduler_->HasFixedSchedulePosition(node)) { | 409 scheduler_->HasFixedSchedulePosition(node)) { |
| 458 if (FLAG_trace_turbo_scheduler) { | 410 Trace("Fixed position node %d is unscheduled, scheduling now\n", |
| 459 PrintF("Fixed position node %d is unscheduled, scheduling now\n", | 411 node->id()); |
| 460 node->id()); | |
| 461 } | |
| 462 IrOpcode::Value opcode = node->opcode(); | 412 IrOpcode::Value opcode = node->opcode(); |
| 463 BasicBlock* block = | 413 BasicBlock* block = |
| 464 opcode == IrOpcode::kParameter | 414 opcode == IrOpcode::kParameter |
| 465 ? schedule_->start() | 415 ? schedule_->start() |
| 466 : schedule_->block(NodeProperties::GetControlInput(node)); | 416 : schedule_->block(NodeProperties::GetControlInput(node)); |
| 467 DCHECK(block != NULL); | 417 DCHECK(block != NULL); |
| 468 schedule_->AddNode(block, node); | 418 schedule_->AddNode(block, node); |
| 469 } | 419 } |
| 470 | 420 |
| 471 if (scheduler_->IsScheduleRoot(node)) { | 421 if (scheduler_->IsScheduleRoot(node)) { |
| 472 scheduler_->schedule_root_nodes_.push_back(node); | 422 scheduler_->schedule_root_nodes_.push_back(node); |
| 473 } | 423 } |
| 474 | 424 |
| 475 return GenericGraphVisit::CONTINUE; | 425 return GenericGraphVisit::CONTINUE; |
| 476 } | 426 } |
| 477 | 427 |
| 478 void PostEdge(Node* from, int index, Node* to) { | 428 void PostEdge(Node* from, int index, Node* to) { |
| 479 // If the edge is from an unscheduled node, then tally it in the use count | 429 // If the edge is from an unscheduled node, then tally it in the use count |
| 480 // for all of its inputs. The same criterion will be used in ScheduleLate | 430 // for all of its inputs. The same criterion will be used in ScheduleLate |
| 481 // for decrementing use counts. | 431 // for decrementing use counts. |
| 482 if (!schedule_->IsScheduled(from) && scheduler_->CanBeScheduled(from)) { | 432 if (!schedule_->IsScheduled(from)) { |
| 483 DCHECK(!scheduler_->HasFixedSchedulePosition(from)); | 433 DCHECK(!scheduler_->HasFixedSchedulePosition(from)); |
| 484 ++scheduler_->unscheduled_uses_[to->id()]; | 434 ++scheduler_->unscheduled_uses_[to->id()]; |
| 485 if (FLAG_trace_turbo_scheduler) { | 435 Trace("Incrementing uses of node %d from %d to %d\n", to->id(), |
| 486 PrintF("Incrementing uses of node %d from %d to %d\n", to->id(), | 436 from->id(), scheduler_->unscheduled_uses_[to->id()]); |
| 487 from->id(), scheduler_->unscheduled_uses_[to->id()]); | |
| 488 } | |
| 489 } | 437 } |
| 490 } | 438 } |
| 491 | 439 |
| 492 private: | 440 private: |
| 493 Scheduler* scheduler_; | 441 Scheduler* scheduler_; |
| 494 Schedule* schedule_; | 442 Schedule* schedule_; |
| 495 }; | 443 }; |
| 496 | 444 |
| 497 | 445 |
| 498 void Scheduler::PrepareUses() { | 446 void Scheduler::PrepareUses() { |
| 499 if (FLAG_trace_turbo_scheduler) { | 447 Trace("------------------- PREPARE USES ------------------\n"); |
| 500 PrintF("------------------- PREPARE USES ------------------\n"); | |
| 501 } | |
| 502 // Count the uses of every node, it will be used to ensure that all of a | 448 // Count the uses of every node, it will be used to ensure that all of a |
| 503 // node's uses are scheduled before the node itself. | 449 // node's uses are scheduled before the node itself. |
| 504 PrepareUsesVisitor prepare_uses(this); | 450 PrepareUsesVisitor prepare_uses(this); |
| 505 graph_->VisitNodeInputsFromEnd(&prepare_uses); | 451 graph_->VisitNodeInputsFromEnd(&prepare_uses); |
| 506 } | 452 } |
| 507 | 453 |
| 508 | 454 |
| 509 class ScheduleLateNodeVisitor : public NullNodeVisitor { | 455 class ScheduleLateNodeVisitor : public NullNodeVisitor { |
| 510 public: | 456 public: |
| 511 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) | 457 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) |
| 512 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} | 458 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} |
| 513 | 459 |
| 514 GenericGraphVisit::Control Pre(Node* node) { | 460 GenericGraphVisit::Control Pre(Node* node) { |
| 515 // Don't schedule nodes that cannot be scheduled or are already scheduled. | 461 // Don't schedule nodes that are already scheduled. |
| 516 if (!scheduler_->CanBeScheduled(node) || schedule_->IsScheduled(node)) { | 462 if (schedule_->IsScheduled(node)) { |
| 517 return GenericGraphVisit::CONTINUE; | 463 return GenericGraphVisit::CONTINUE; |
| 518 } | 464 } |
| 519 DCHECK(!scheduler_->HasFixedSchedulePosition(node)); | 465 DCHECK(!scheduler_->HasFixedSchedulePosition(node)); |
| 520 | 466 |
| 521 // If all the uses of a node have been scheduled, then the node itself can | 467 // If all the uses of a node have been scheduled, then the node itself can |
| 522 // be scheduled. | 468 // be scheduled. |
| 523 bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0; | 469 bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0; |
| 524 if (FLAG_trace_turbo_scheduler) { | 470 Trace("Testing for schedule eligibility for node %d -> %s\n", node->id(), |
| 525 PrintF("Testing for schedule eligibility for node %d -> %s\n", node->id(), | 471 eligible ? "true" : "false"); |
| 526 eligible ? "true" : "false"); | |
| 527 } | |
| 528 if (!eligible) return GenericGraphVisit::DEFER; | 472 if (!eligible) return GenericGraphVisit::DEFER; |
| 529 | 473 |
| 530 // Determine the dominating block for all of the uses of this node. It is | 474 // Determine the dominating block for all of the uses of this node. It is |
| 531 // the latest block that this node can be scheduled in. | 475 // the latest block that this node can be scheduled in. |
| 532 BasicBlock* block = NULL; | 476 BasicBlock* block = NULL; |
| 533 for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end(); | 477 for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end(); |
| 534 ++i) { | 478 ++i) { |
| 535 BasicBlock* use_block = GetBlockForUse(i.edge()); | 479 BasicBlock* use_block = GetBlockForUse(i.edge()); |
| 536 block = block == NULL ? use_block : use_block == NULL | 480 block = block == NULL ? use_block : use_block == NULL |
| 537 ? block | 481 ? block |
| 538 : scheduler_->GetCommonDominator( | 482 : scheduler_->GetCommonDominator( |
| 539 block, use_block); | 483 block, use_block); |
| 540 } | 484 } |
| 541 DCHECK(block != NULL); | 485 DCHECK(block != NULL); |
| 542 | 486 |
| 543 int min_rpo = scheduler_->schedule_early_rpo_index_[node->id()]; | 487 int min_rpo = scheduler_->schedule_early_rpo_index_[node->id()]; |
| 544 if (FLAG_trace_turbo_scheduler) { | 488 Trace( |
| 545 PrintF( | 489 "Schedule late conservative for node %d is block %d at " |
| 546 "Schedule late conservative for node %d is block %d at " | 490 "loop depth %d, min rpo = %d\n", |
| 547 "loop depth %d, min rpo = %d\n", | 491 node->id(), block->id(), block->loop_depth_, min_rpo); |
| 548 node->id(), block->id(), block->loop_depth_, min_rpo); | |
| 549 } | |
| 550 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively | 492 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
| 551 // into enlcosing loop pre-headers until they would preceed their | 493 // into enlcosing loop pre-headers until they would preceed their |
| 552 // ScheduleEarly position. | 494 // ScheduleEarly position. |
| 553 BasicBlock* hoist_block = block; | 495 BasicBlock* hoist_block = block; |
| 554 while (hoist_block != NULL && hoist_block->rpo_number_ >= min_rpo) { | 496 while (hoist_block != NULL && hoist_block->rpo_number_ >= min_rpo) { |
| 555 if (hoist_block->loop_depth_ < block->loop_depth_) { | 497 if (hoist_block->loop_depth_ < block->loop_depth_) { |
| 556 block = hoist_block; | 498 block = hoist_block; |
| 557 if (FLAG_trace_turbo_scheduler) { | 499 Trace("Hoisting node %d to block %d\n", node->id(), block->id()); |
| 558 PrintF("Hoisting node %d to block %d\n", node->id(), block->id()); | |
| 559 } | |
| 560 } | 500 } |
| 561 // Try to hoist to the pre-header of the loop header. | 501 // Try to hoist to the pre-header of the loop header. |
| 562 hoist_block = hoist_block->loop_header(); | 502 hoist_block = hoist_block->loop_header(); |
| 563 if (hoist_block != NULL) { | 503 if (hoist_block != NULL) { |
| 564 BasicBlock* pre_header = schedule_->dominator(hoist_block); | 504 BasicBlock* pre_header = schedule_->dominator(hoist_block); |
| 565 DCHECK(pre_header == NULL || | 505 DCHECK(pre_header == NULL || |
| 566 *hoist_block->predecessors().begin() == pre_header); | 506 *hoist_block->predecessors().begin() == pre_header); |
| 567 if (FLAG_trace_turbo_scheduler) { | 507 Trace( |
| 568 PrintF( | 508 "Try hoist to pre-header block %d of loop header block %d," |
| 569 "Try hoist to pre-header block %d of loop header block %d," | 509 " depth would be %d\n", |
| 570 " depth would be %d\n", | 510 pre_header->id(), hoist_block->id(), pre_header->loop_depth_); |
| 571 pre_header->id(), hoist_block->id(), pre_header->loop_depth_); | |
| 572 } | |
| 573 hoist_block = pre_header; | 511 hoist_block = pre_header; |
| 574 } | 512 } |
| 575 } | 513 } |
| 576 | 514 |
| 577 ScheduleNode(block, node); | 515 ScheduleNode(block, node); |
| 578 | 516 |
| 579 return GenericGraphVisit::CONTINUE; | 517 return GenericGraphVisit::CONTINUE; |
| 580 } | 518 } |
| 581 | 519 |
| 582 private: | 520 private: |
| 583 BasicBlock* GetBlockForUse(Node::Edge edge) { | 521 BasicBlock* GetBlockForUse(Node::Edge edge) { |
| 584 Node* use = edge.from(); | 522 Node* use = edge.from(); |
| 585 IrOpcode::Value opcode = use->opcode(); | 523 IrOpcode::Value opcode = use->opcode(); |
| 586 // If the use is a phi, forward through the phi to the basic block | 524 // If the use is a phi, forward through the phi to the basic block |
| 587 // corresponding to the phi's input. | 525 // corresponding to the phi's input. |
| 588 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 526 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| 589 int index = edge.index(); | 527 int index = edge.index(); |
| 590 if (FLAG_trace_turbo_scheduler) { | 528 Trace("Use %d is input %d to a phi\n", use->id(), index); |
| 591 PrintF("Use %d is input %d to a phi\n", use->id(), index); | |
| 592 } | |
| 593 use = NodeProperties::GetControlInput(use, 0); | 529 use = NodeProperties::GetControlInput(use, 0); |
| 594 opcode = use->opcode(); | 530 opcode = use->opcode(); |
| 595 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); | 531 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); |
| 596 use = NodeProperties::GetControlInput(use, index); | 532 use = NodeProperties::GetControlInput(use, index); |
| 597 } | 533 } |
| 598 BasicBlock* result = schedule_->block(use); | 534 BasicBlock* result = schedule_->block(use); |
| 599 if (result == NULL) return NULL; | 535 if (result == NULL) return NULL; |
| 600 if (FLAG_trace_turbo_scheduler) { | 536 Trace("Must dominate use %d in block %d\n", use->id(), result->id()); |
| 601 PrintF("Must dominate use %d in block %d\n", use->id(), result->id()); | |
| 602 } | |
| 603 return result; | 537 return result; |
| 604 } | 538 } |
| 605 | 539 |
| 606 void ScheduleNode(BasicBlock* block, Node* node) { | 540 void ScheduleNode(BasicBlock* block, Node* node) { |
| 607 schedule_->PlanNode(block, node); | 541 schedule_->PlanNode(block, node); |
| 608 scheduler_->scheduled_nodes_[block->id()].push_back(node); | 542 scheduler_->scheduled_nodes_[block->id()].push_back(node); |
| 609 | 543 |
| 610 // Reduce the use count of the node's inputs to potentially make them | 544 // Reduce the use count of the node's inputs to potentially make them |
| 611 // scheduable. | 545 // scheduable. |
| 612 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { | 546 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { |
| 613 DCHECK(scheduler_->unscheduled_uses_[(*i)->id()] > 0); | 547 DCHECK(scheduler_->unscheduled_uses_[(*i)->id()] > 0); |
| 614 --scheduler_->unscheduled_uses_[(*i)->id()]; | 548 --scheduler_->unscheduled_uses_[(*i)->id()]; |
| 615 if (FLAG_trace_turbo_scheduler) { | 549 if (FLAG_trace_turbo_scheduler) { |
| 616 PrintF("Decrementing use count for node %d from node %d (now %d)\n", | 550 Trace("Decrementing use count for node %d from node %d (now %d)\n", |
| 617 (*i)->id(), i.edge().from()->id(), | 551 (*i)->id(), i.edge().from()->id(), |
| 618 scheduler_->unscheduled_uses_[(*i)->id()]); | 552 scheduler_->unscheduled_uses_[(*i)->id()]); |
| 619 if (scheduler_->unscheduled_uses_[(*i)->id()] == 0) { | 553 if (scheduler_->unscheduled_uses_[(*i)->id()] == 0) { |
| 620 PrintF("node %d is now eligible for scheduling\n", (*i)->id()); | 554 Trace("node %d is now eligible for scheduling\n", (*i)->id()); |
| 621 } | 555 } |
| 622 } | 556 } |
| 623 } | 557 } |
| 624 } | 558 } |
| 625 | 559 |
| 626 Scheduler* scheduler_; | 560 Scheduler* scheduler_; |
| 627 Schedule* schedule_; | 561 Schedule* schedule_; |
| 628 }; | 562 }; |
| 629 | 563 |
| 630 | 564 |
| 631 void Scheduler::ScheduleLate() { | 565 void Scheduler::ScheduleLate() { |
| 632 if (FLAG_trace_turbo_scheduler) { | 566 Trace("------------------- SCHEDULE LATE -----------------\n"); |
| 633 PrintF("------------------- SCHEDULE LATE -----------------\n"); | |
| 634 } | |
| 635 | 567 |
| 636 // Schedule: Places nodes in dominator block of all their uses. | 568 // Schedule: Places nodes in dominator block of all their uses. |
| 637 ScheduleLateNodeVisitor schedule_late_visitor(this); | 569 ScheduleLateNodeVisitor schedule_late_visitor(this); |
| 638 | 570 |
| 639 { | 571 { |
| 640 Zone zone(zone_->isolate()); | 572 Zone zone(zone_->isolate()); |
| 641 GenericGraphVisit::Visit<ScheduleLateNodeVisitor, | 573 GenericGraphVisit::Visit<ScheduleLateNodeVisitor, |
| 642 NodeInputIterationTraits<Node> >( | 574 NodeInputIterationTraits<Node> >( |
| 643 graph_, &zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(), | 575 graph_, &zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(), |
| 644 &schedule_late_visitor); | 576 &schedule_late_visitor); |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 // (i.e. A -> B is a backedge). | 790 // (i.e. A -> B is a backedge). |
| 859 // => If block A dominates block B, then A appears before B in the order. | 791 // => If block A dominates block B, then A appears before B in the order. |
| 860 // => If block A is a loop header, A appears before all blocks in the loop | 792 // => If block A is a loop header, A appears before all blocks in the loop |
| 861 // headed at A. | 793 // headed at A. |
| 862 // 2. All loops are contiguous in the order (i.e. no intervening blocks that | 794 // 2. All loops are contiguous in the order (i.e. no intervening blocks that |
| 863 // do not belong to the loop.) | 795 // do not belong to the loop.) |
| 864 // Note a simple RPO traversal satisfies (1) but not (3). | 796 // Note a simple RPO traversal satisfies (1) but not (3). |
| 865 BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) { | 797 BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) { |
| 866 Zone tmp_zone(schedule->zone()->isolate()); | 798 Zone tmp_zone(schedule->zone()->isolate()); |
| 867 Zone* zone = &tmp_zone; | 799 Zone* zone = &tmp_zone; |
| 868 if (FLAG_trace_turbo_scheduler) { | 800 Trace("------------- COMPUTING SPECIAL RPO ---------------\n"); |
| 869 PrintF("------------- COMPUTING SPECIAL RPO ---------------\n"); | |
| 870 } | |
| 871 // RPO should not have been computed for this schedule yet. | 801 // RPO should not have been computed for this schedule yet. |
| 872 CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number_); | 802 CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number_); |
| 873 CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size())); | 803 CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size())); |
| 874 | 804 |
| 875 // Perform an iterative RPO traversal using an explicit stack, | 805 // Perform an iterative RPO traversal using an explicit stack, |
| 876 // recording backedges that form cycles. O(|B|). | 806 // recording backedges that form cycles. O(|B|). |
| 877 ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone); | 807 ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone); |
| 878 SpecialRPOStackFrame* stack = | 808 SpecialRPOStackFrame* stack = |
| 879 zone->NewArray<SpecialRPOStackFrame>(schedule->BasicBlockCount()); | 809 zone->NewArray<SpecialRPOStackFrame>(schedule->BasicBlockCount()); |
| 880 BasicBlock* entry = schedule->start(); | 810 BasicBlock* entry = schedule->start(); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1020 ++i) { | 950 ++i) { |
| 1021 BasicBlock* current = *i; | 951 BasicBlock* current = *i; |
| 1022 current->loop_header_ = current_header; | 952 current->loop_header_ = current_header; |
| 1023 if (current->IsLoopHeader()) { | 953 if (current->IsLoopHeader()) { |
| 1024 loop_depth++; | 954 loop_depth++; |
| 1025 current_loop = &loops[current->loop_end_]; | 955 current_loop = &loops[current->loop_end_]; |
| 1026 BlockList* end = current_loop->end; | 956 BlockList* end = current_loop->end; |
| 1027 current->loop_end_ = end == NULL ? static_cast<int>(final_order->size()) | 957 current->loop_end_ = end == NULL ? static_cast<int>(final_order->size()) |
| 1028 : end->block->rpo_number_; | 958 : end->block->rpo_number_; |
| 1029 current_header = current_loop->header; | 959 current_header = current_loop->header; |
| 1030 if (FLAG_trace_turbo_scheduler) { | 960 Trace("Block %d is a loop header, increment loop depth to %d\n", |
| 1031 PrintF("Block %d is a loop header, increment loop depth to %d\n", | 961 current->id(), loop_depth); |
| 1032 current->id(), loop_depth); | |
| 1033 } | |
| 1034 } else { | 962 } else { |
| 1035 while (current_header != NULL && | 963 while (current_header != NULL && |
| 1036 current->rpo_number_ >= current_header->loop_end_) { | 964 current->rpo_number_ >= current_header->loop_end_) { |
| 1037 DCHECK(current_header->IsLoopHeader()); | 965 DCHECK(current_header->IsLoopHeader()); |
| 1038 DCHECK(current_loop != NULL); | 966 DCHECK(current_loop != NULL); |
| 1039 current_loop = current_loop->prev; | 967 current_loop = current_loop->prev; |
| 1040 current_header = current_loop == NULL ? NULL : current_loop->header; | 968 current_header = current_loop == NULL ? NULL : current_loop->header; |
| 1041 --loop_depth; | 969 --loop_depth; |
| 1042 } | 970 } |
| 1043 } | 971 } |
| 1044 current->loop_depth_ = loop_depth; | 972 current->loop_depth_ = loop_depth; |
| 1045 if (FLAG_trace_turbo_scheduler) { | 973 Trace("Block %d's loop header is block %d, loop depth %d\n", current->id(), |
| 1046 if (current->loop_header_ == NULL) { | 974 current->loop_header_ == NULL ? -1 : current->loop_header_->id(), |
| 1047 PrintF("Block %d's loop header is NULL, loop depth %d\n", current->id(), | 975 current->loop_depth_); |
| 1048 current->loop_depth_); | |
| 1049 } else { | |
| 1050 PrintF("Block %d's loop header is block %d, loop depth %d\n", | |
| 1051 current->id(), current->loop_header_->id(), | |
| 1052 current->loop_depth_); | |
| 1053 } | |
| 1054 } | |
| 1055 } | 976 } |
| 1056 | 977 |
| 1057 #if DEBUG | 978 #if DEBUG |
| 1058 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); | 979 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); |
| 1059 VerifySpecialRPO(num_loops, loops, final_order); | 980 VerifySpecialRPO(num_loops, loops, final_order); |
| 1060 #endif | 981 #endif |
| 1061 return final_order; | 982 return final_order; |
| 1062 } | 983 } |
| 1063 } | 984 } |
| 1064 } | 985 } |
| 1065 } // namespace v8::internal::compiler | 986 } // namespace v8::internal::compiler |
| OLD | NEW |