| 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/bit-vector.h" | 7 #include "src/bit-vector.h" |
| 8 #include "src/compiler/common-operator.h" | 8 #include "src/compiler/common-operator.h" |
| 9 #include "src/compiler/control-equivalence.h" | 9 #include "src/compiler/control-equivalence.h" |
| 10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
| 11 #include "src/compiler/node.h" | 11 #include "src/compiler/node.h" |
| 12 #include "src/compiler/node-marker.h" | 12 #include "src/compiler/node-marker.h" |
| 13 #include "src/compiler/node-properties.h" | 13 #include "src/compiler/node-properties.h" |
| 14 #include "src/zone-containers.h" | 14 #include "src/zone-containers.h" |
| 15 | 15 |
| 16 namespace v8 { | 16 namespace v8 { |
| 17 namespace internal { | 17 namespace internal { |
| 18 namespace compiler { | 18 namespace compiler { |
| 19 | 19 |
| 20 static inline void Trace(const char* msg, ...) { | 20 static inline void Trace(const char* msg, ...) { |
| 21 if (FLAG_trace_turbo_scheduler) { | 21 if (FLAG_trace_turbo_scheduler) { |
| 22 va_list arguments; | 22 va_list arguments; |
| 23 va_start(arguments, msg); | 23 va_start(arguments, msg); |
| 24 base::OS::VPrint(msg, arguments); | 24 base::OS::VPrint(msg, arguments); |
| 25 va_end(arguments); | 25 va_end(arguments); |
| 26 } | 26 } |
| 27 } | 27 } |
| 28 | 28 |
| 29 | 29 |
| 30 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) | 30 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule, Flags flags) |
| 31 : zone_(zone), | 31 : zone_(zone), |
| 32 graph_(graph), | 32 graph_(graph), |
| 33 schedule_(schedule), | 33 schedule_(schedule), |
| 34 flags_(flags), |
| 34 scheduled_nodes_(zone), | 35 scheduled_nodes_(zone), |
| 35 schedule_root_nodes_(zone), | 36 schedule_root_nodes_(zone), |
| 36 schedule_queue_(zone), | 37 schedule_queue_(zone), |
| 37 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone) {} | 38 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone) {} |
| 38 | 39 |
| 39 | 40 |
| 40 Schedule* Scheduler::ComputeSchedule(Zone* zone, Graph* graph) { | 41 Schedule* Scheduler::ComputeSchedule(Zone* zone, Graph* graph, Flags flags) { |
| 41 Schedule* schedule = new (graph->zone()) | 42 Schedule* schedule = new (graph->zone()) |
| 42 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); | 43 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); |
| 43 Scheduler scheduler(zone, graph, schedule); | 44 Scheduler scheduler(zone, graph, schedule, flags); |
| 44 | 45 |
| 45 scheduler.BuildCFG(); | 46 scheduler.BuildCFG(); |
| 46 scheduler.ComputeSpecialRPONumbering(); | 47 scheduler.ComputeSpecialRPONumbering(); |
| 47 scheduler.GenerateImmediateDominatorTree(); | 48 scheduler.GenerateImmediateDominatorTree(); |
| 48 | 49 |
| 49 scheduler.PrepareUses(); | 50 scheduler.PrepareUses(); |
| 50 scheduler.ScheduleEarly(); | 51 scheduler.ScheduleEarly(); |
| 51 scheduler.ScheduleLate(); | 52 scheduler.ScheduleLate(); |
| 52 | 53 |
| 53 scheduler.SealFinalSchedule(); | 54 scheduler.SealFinalSchedule(); |
| (...skipping 1165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1219 } | 1220 } |
| 1220 | 1221 |
| 1221 | 1222 |
| 1222 // ----------------------------------------------------------------------------- | 1223 // ----------------------------------------------------------------------------- |
| 1223 // Phase 5: Schedule nodes late. | 1224 // Phase 5: Schedule nodes late. |
| 1224 | 1225 |
| 1225 | 1226 |
| 1226 class ScheduleLateNodeVisitor { | 1227 class ScheduleLateNodeVisitor { |
| 1227 public: | 1228 public: |
| 1228 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) | 1229 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) |
| 1229 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} | 1230 : scheduler_(scheduler), |
| 1231 schedule_(scheduler_->schedule_), |
| 1232 visited_(scheduler->zone_), |
| 1233 stack_(scheduler->zone_) {} |
| 1230 | 1234 |
| 1231 // Run the schedule late algorithm on a set of fixed root nodes. | 1235 // Run the schedule late algorithm on a set of fixed root nodes. |
| 1232 void Run(NodeVector* roots) { | 1236 void Run(NodeVector* roots) { |
| 1233 for (Node* const root : *roots) { | 1237 for (Node* const root : *roots) { |
| 1234 ProcessQueue(root); | 1238 ProcessQueue(root); |
| 1235 } | 1239 } |
| 1236 } | 1240 } |
| 1237 | 1241 |
| 1238 private: | 1242 private: |
| 1239 void ProcessQueue(Node* root) { | 1243 void ProcessQueue(Node* root) { |
| 1240 ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_); | 1244 ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_); |
| 1241 for (Node* node : root->inputs()) { | 1245 for (Node* node : root->inputs()) { |
| 1242 // Don't schedule coupled nodes on their own. | 1246 // Don't schedule coupled nodes on their own. |
| 1243 if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) { | 1247 if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) { |
| 1244 node = NodeProperties::GetControlInput(node); | 1248 node = NodeProperties::GetControlInput(node); |
| 1245 } | 1249 } |
| 1246 | 1250 |
| 1247 // Test schedulability condition by looking at unscheduled use count. | 1251 // Test schedulability condition by looking at unscheduled use count. |
| 1248 if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue; | 1252 if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue; |
| 1249 | 1253 |
| 1250 queue->push(node); | 1254 queue->push(node); |
| 1251 while (!queue->empty()) { | 1255 while (!queue->empty()) { |
| 1252 VisitNode(queue->front()); | 1256 Node* const node = queue->front(); |
| 1253 queue->pop(); | 1257 queue->pop(); |
| 1258 VisitNode(node); |
| 1254 } | 1259 } |
| 1255 } | 1260 } |
| 1256 } | 1261 } |
| 1257 | 1262 |
| 1258 // Visits one node from the queue of schedulable nodes and determines its | 1263 // Visits one node from the queue of schedulable nodes and determines its |
| 1259 // schedule late position. Also hoists nodes out of loops to find a more | 1264 // schedule late position. Also hoists nodes out of loops to find a more |
| 1260 // optimal scheduling position. | 1265 // optimal scheduling position. |
| 1261 void VisitNode(Node* node) { | 1266 void VisitNode(Node* node) { |
| 1262 DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_); | 1267 DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_); |
| 1263 | 1268 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1275 BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_; | 1280 BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_; |
| 1276 DCHECK_EQ(min_block, BasicBlock::GetCommonDominator(block, min_block)); | 1281 DCHECK_EQ(min_block, BasicBlock::GetCommonDominator(block, min_block)); |
| 1277 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum = B%d\n", | 1282 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum = B%d\n", |
| 1278 node->id(), node->op()->mnemonic(), block->id().ToInt(), | 1283 node->id(), node->op()->mnemonic(), block->id().ToInt(), |
| 1279 block->loop_depth(), min_block->id().ToInt()); | 1284 block->loop_depth(), min_block->id().ToInt()); |
| 1280 | 1285 |
| 1281 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively | 1286 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
| 1282 // into enclosing loop pre-headers until they would preceed their schedule | 1287 // into enclosing loop pre-headers until they would preceed their schedule |
| 1283 // early position. | 1288 // early position. |
| 1284 BasicBlock* hoist_block = GetPreHeader(block); | 1289 BasicBlock* hoist_block = GetPreHeader(block); |
| 1285 while (hoist_block != NULL && | 1290 if (hoist_block && |
| 1286 hoist_block->dominator_depth() >= min_block->dominator_depth()) { | 1291 hoist_block->dominator_depth() >= min_block->dominator_depth()) { |
| 1287 Trace(" hoisting #%d:%s to block B%d\n", node->id(), | 1292 do { |
| 1288 node->op()->mnemonic(), hoist_block->id().ToInt()); | 1293 Trace(" hoisting #%d:%s to block B%d\n", node->id(), |
| 1289 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); | 1294 node->op()->mnemonic(), hoist_block->id().ToInt()); |
| 1290 block = hoist_block; | 1295 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); |
| 1291 hoist_block = GetPreHeader(hoist_block); | 1296 block = hoist_block; |
| 1297 hoist_block = GetPreHeader(hoist_block); |
| 1298 } while (hoist_block && |
| 1299 hoist_block->dominator_depth() >= min_block->dominator_depth()); |
| 1300 } else if (scheduler_->flags_ & Scheduler::kSplitNodes && |
| 1301 block->SuccessorCount() >= 2 && |
| 1302 node->op()->HasProperty(Operator::kPure)) { |
| 1303 // Split the {node} if beneficial and return the new {block} for it. |
| 1304 if (SplitNode(block, node)) return; |
| 1292 } | 1305 } |
| 1293 | 1306 |
| 1294 // Schedule the node or a floating control structure. | 1307 // Schedule the node or a floating control structure. |
| 1295 if (NodeProperties::IsControl(node)) { | 1308 if (NodeProperties::IsControl(node)) { |
| 1296 ScheduleFloatingControl(block, node); | 1309 ScheduleFloatingControl(block, node); |
| 1297 } else { | 1310 } else { |
| 1298 ScheduleNode(block, node); | 1311 ScheduleNode(block, node); |
| 1299 } | 1312 } |
| 1300 } | 1313 } |
| 1301 | 1314 |
| 1315 bool SplitNode(BasicBlock* block, Node* node) { |
| 1316 std::fill(visited_.begin(), visited_.end(), false); |
| 1317 visited_.resize(schedule_->BasicBlockCount() + 1, false); |
| 1318 stack_.clear(); |
| 1319 |
| 1320 // Check if the {node} has uses in {block}. |
| 1321 for (Edge edge : node->use_edges()) { |
| 1322 BasicBlock* use_block = GetBlockForUse(edge); |
| 1323 if (use_block == block) { |
| 1324 Trace(" not splitting #%d:%s, it is used in B%d\n", node->id(), |
| 1325 node->op()->mnemonic(), block->id().ToInt()); |
| 1326 return false; |
| 1327 } |
| 1328 if (use_block) { |
| 1329 visited_[use_block->id().ToSize()] = true; |
| 1330 for (BasicBlock* predecessor : use_block->predecessors()) { |
| 1331 stack_.push_back(predecessor); |
| 1332 } |
| 1333 } |
| 1334 } |
| 1335 |
| 1336 while (!stack_.empty()) { |
| 1337 BasicBlock* block = stack_.back(); |
| 1338 stack_.pop_back(); |
| 1339 bool visited = visited_[block->id().ToSize()]; |
| 1340 if (visited) continue; |
| 1341 visited = true; |
| 1342 for (BasicBlock* successor : block->successors()) { |
| 1343 if (!visited_[successor->id().ToSize()]) { |
| 1344 visited = false; |
| 1345 break; |
| 1346 } |
| 1347 } |
| 1348 if (visited) { |
| 1349 visited_[block->id().ToSize()] = true; |
| 1350 for (BasicBlock* predecessor : block->predecessors()) { |
| 1351 stack_.push_back(predecessor); |
| 1352 } |
| 1353 } |
| 1354 } |
| 1355 |
| 1356 if (visited_[block->id().ToSize()]) { |
| 1357 return false; |
| 1358 } |
| 1359 |
| 1360 std::map<BasicBlock*, Node*> dominators; |
| 1361 for (Edge edge : node->use_edges()) { |
| 1362 BasicBlock* use_block = GetBlockForUse(edge); |
| 1363 if (!use_block) continue; |
| 1364 BasicBlock* dominator = use_block; |
| 1365 DCHECK(visited_[dominator->id().ToSize()]); |
| 1366 while (visited_[dominator->dominator()->id().ToSize()]) { |
| 1367 dominator = dominator->dominator(); |
| 1368 } |
| 1369 if (dominators.find(dominator) == dominators.end()) { |
| 1370 if (dominators.size() == 0) { |
| 1371 dominators.insert(std::make_pair(dominator, node)); |
| 1372 scheduler_->schedule_queue_.push(node); |
| 1373 } else { |
| 1374 Node* copy = CloneNode(node); |
| 1375 dominators.insert(std::make_pair(dominator, copy)); |
| 1376 scheduler_->schedule_queue_.push(copy); |
| 1377 } |
| 1378 } |
| 1379 } |
| 1380 |
| 1381 for (Edge edge : node->use_edges()) { |
| 1382 BasicBlock* use_block = GetBlockForUse(edge); |
| 1383 if (!use_block) continue; |
| 1384 for (;; use_block = use_block->dominator()) { |
| 1385 DCHECK(visited_[use_block->id().ToSize()]); |
| 1386 if (Node* node = dominators[use_block]) { |
| 1387 edge.UpdateTo(node); |
| 1388 break; |
| 1389 } |
| 1390 } |
| 1391 } |
| 1392 return true; |
| 1393 } |
| 1394 |
| 1302 BasicBlock* GetPreHeader(BasicBlock* block) { | 1395 BasicBlock* GetPreHeader(BasicBlock* block) { |
| 1303 if (block->IsLoopHeader()) { | 1396 if (block->IsLoopHeader()) { |
| 1304 return block->dominator(); | 1397 return block->dominator(); |
| 1305 } else if (block->loop_header() != NULL) { | 1398 } else if (block->loop_header() != NULL) { |
| 1306 return block->loop_header()->dominator(); | 1399 return block->loop_header()->dominator(); |
| 1307 } else { | 1400 } else { |
| 1308 return NULL; | 1401 return NULL; |
| 1309 } | 1402 } |
| 1310 } | 1403 } |
| 1311 | 1404 |
| 1312 BasicBlock* GetCommonDominatorOfUses(Node* node) { | 1405 BasicBlock* GetCommonDominatorOfUses(Node* node) { |
| 1313 BasicBlock* block = NULL; | 1406 BasicBlock* block = nullptr; |
| 1314 for (Edge edge : node->use_edges()) { | 1407 for (Edge edge : node->use_edges()) { |
| 1315 BasicBlock* use_block = GetBlockForUse(edge); | 1408 BasicBlock* use_block = GetBlockForUse(edge); |
| 1316 block = block == NULL ? use_block : use_block == NULL | 1409 block = block == NULL ? use_block : use_block == NULL |
| 1317 ? block | 1410 ? block |
| 1318 : BasicBlock::GetCommonDominator( | 1411 : BasicBlock::GetCommonDominator( |
| 1319 block, use_block); | 1412 block, use_block); |
| 1320 } | 1413 } |
| 1321 return block; | 1414 return block; |
| 1322 } | 1415 } |
| 1323 | 1416 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1354 void ScheduleFloatingControl(BasicBlock* block, Node* node) { | 1447 void ScheduleFloatingControl(BasicBlock* block, Node* node) { |
| 1355 scheduler_->FuseFloatingControl(block, node); | 1448 scheduler_->FuseFloatingControl(block, node); |
| 1356 } | 1449 } |
| 1357 | 1450 |
| 1358 void ScheduleNode(BasicBlock* block, Node* node) { | 1451 void ScheduleNode(BasicBlock* block, Node* node) { |
| 1359 schedule_->PlanNode(block, node); | 1452 schedule_->PlanNode(block, node); |
| 1360 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); | 1453 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); |
| 1361 scheduler_->UpdatePlacement(node, Scheduler::kScheduled); | 1454 scheduler_->UpdatePlacement(node, Scheduler::kScheduled); |
| 1362 } | 1455 } |
| 1363 | 1456 |
| 1457 Node* CloneNode(Node* node) { |
| 1458 int const input_count = node->InputCount(); |
| 1459 Node** const inputs = scheduler_->zone_->NewArray<Node*>(input_count); |
| 1460 for (int index = 0; index < input_count; ++index) { |
| 1461 Node* const input = node->InputAt(index); |
| 1462 scheduler_->IncrementUnscheduledUseCount(input, index, node); |
| 1463 inputs[index] = input; |
| 1464 } |
| 1465 Node* copy = scheduler_->graph_->NewNode(node->op(), input_count, inputs); |
| 1466 scheduler_->node_data_.resize(copy->id() + 1, |
| 1467 scheduler_->DefaultSchedulerData()); |
| 1468 scheduler_->node_data_[copy->id()] = scheduler_->node_data_[node->id()]; |
| 1469 return copy; |
| 1470 } |
| 1471 |
| 1364 Scheduler* scheduler_; | 1472 Scheduler* scheduler_; |
| 1365 Schedule* schedule_; | 1473 Schedule* schedule_; |
| 1474 BoolVector visited_; |
| 1475 BasicBlockVector stack_; |
| 1366 }; | 1476 }; |
| 1367 | 1477 |
| 1368 | 1478 |
| 1369 void Scheduler::ScheduleLate() { | 1479 void Scheduler::ScheduleLate() { |
| 1370 Trace("--- SCHEDULE LATE ------------------------------------------\n"); | 1480 Trace("--- SCHEDULE LATE ------------------------------------------\n"); |
| 1371 if (FLAG_trace_turbo_scheduler) { | 1481 if (FLAG_trace_turbo_scheduler) { |
| 1372 Trace("roots: "); | 1482 Trace("roots: "); |
| 1373 for (Node* node : schedule_root_nodes_) { | 1483 for (Node* node : schedule_root_nodes_) { |
| 1374 Trace("#%d:%s ", node->id(), node->op()->mnemonic()); | 1484 Trace("#%d:%s ", node->id(), node->op()->mnemonic()); |
| 1375 } | 1485 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 for (Node* const node : *nodes) { | 1576 for (Node* const node : *nodes) { |
| 1467 schedule_->SetBlockForNode(to, node); | 1577 schedule_->SetBlockForNode(to, node); |
| 1468 scheduled_nodes_[to->id().ToSize()].push_back(node); | 1578 scheduled_nodes_[to->id().ToSize()].push_back(node); |
| 1469 } | 1579 } |
| 1470 nodes->clear(); | 1580 nodes->clear(); |
| 1471 } | 1581 } |
| 1472 | 1582 |
| 1473 } // namespace compiler | 1583 } // namespace compiler |
| 1474 } // namespace internal | 1584 } // namespace internal |
| 1475 } // namespace v8 | 1585 } // namespace v8 |
| OLD | NEW |