Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Unified Diff: src/compiler/instruction-scheduler.cc

Issue 1375253002: [WIP][turbofan] Instruction scheduler for Turbofan. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase the patch Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/instruction-scheduler.h ('k') | src/compiler/instruction-selector.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/instruction-scheduler.cc
diff --git a/src/compiler/instruction-scheduler.cc b/src/compiler/instruction-scheduler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2f329ead41569959a6db4799f79b03a549d4f31a
--- /dev/null
+++ b/src/compiler/instruction-scheduler.cc
@@ -0,0 +1,280 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/instruction-scheduler.h"
+
+#include "src/base/adapters.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+InstructionScheduler::ScheduleGraphNode::ScheduleGraphNode(
+ Zone* zone,
+ Instruction* instr)
+ : instr_(instr),
+ successors_(zone),
+ unscheduled_predecessors_count_(0),
+ latency_(GetInstructionLatency(instr)),
+ total_latency_(-1),
+ start_cycle_(-1) {
+}
+
+
+void InstructionScheduler::ScheduleGraphNode::AddSuccessor(
+ ScheduleGraphNode* node) {
+ successors_.push_back(node);
+ node->unscheduled_predecessors_count_++;
+}
+
+
+InstructionScheduler::InstructionScheduler(Zone* zone,
+ InstructionSequence* sequence)
+ : zone_(zone),
+ sequence_(sequence),
+ graph_(zone),
+ last_side_effect_instr_(nullptr),
+ pending_loads_(zone),
+ last_live_in_reg_marker_(nullptr) {
+}
+
+
+void InstructionScheduler::StartBlock(RpoNumber rpo) {
+ DCHECK(graph_.empty());
+ DCHECK(last_side_effect_instr_ == nullptr);
+ DCHECK(pending_loads_.empty());
+ DCHECK(last_live_in_reg_marker_ == nullptr);
+ sequence()->StartBlock(rpo);
+}
+
+
+void InstructionScheduler::EndBlock(RpoNumber rpo) {
+ ScheduleBlock();
+ sequence()->EndBlock(rpo);
+ graph_.clear();
+ last_side_effect_instr_ = nullptr;
+ pending_loads_.clear();
+ last_live_in_reg_marker_ = nullptr;
+}
+
+
+void InstructionScheduler::AddInstruction(Instruction* instr) {
+ ScheduleGraphNode* new_node = new (zone()) ScheduleGraphNode(zone(), instr);
+
+ if (IsBlockTerminator(instr)) {
+ // Make sure that basic block terminators are not moved by adding them
+ // as successor of every instruction.
+ for (auto node : graph_) {
+ node->AddSuccessor(new_node);
+ }
+ } else if (IsFixedRegisterParameter(instr)) {
+ if (last_live_in_reg_marker_ != nullptr) {
+ last_live_in_reg_marker_->AddSuccessor(new_node);
+ }
+ last_live_in_reg_marker_ = new_node;
+ } else {
+ if (last_live_in_reg_marker_ != nullptr) {
+ last_live_in_reg_marker_->AddSuccessor(new_node);
+ }
+
+ // Instructions with side effects and memory operations can't be
+ // reordered with respect to each other.
+ if (HasSideEffect(instr)) {
+ if (last_side_effect_instr_ != nullptr) {
+ last_side_effect_instr_->AddSuccessor(new_node);
+ }
+ for (auto load : pending_loads_) {
+ load->AddSuccessor(new_node);
+ }
+ pending_loads_.clear();
+ last_side_effect_instr_ = new_node;
+ } else if (IsLoadOperation(instr)) {
+ // Load operations can't be reordered with side effects instructions but
+ // independent loads can be reordered with respect to each other.
+ if (last_side_effect_instr_ != nullptr) {
+ last_side_effect_instr_->AddSuccessor(new_node);
+ }
+ pending_loads_.push_back(new_node);
+ }
+
+ // Look for operand dependencies.
+ for (auto node : graph_) {
+ if (HasOperandDependency(node->instruction(), instr)) {
+ node->AddSuccessor(new_node);
+ }
+ }
+ }
+
+ graph_.push_back(new_node);
+}
+
+
+bool InstructionScheduler::CompareNodes(ScheduleGraphNode *node1,
+ ScheduleGraphNode *node2) const {
+ return node1->total_latency() > node2->total_latency();
+}
+
+
+void InstructionScheduler::ScheduleBlock() {
+ ZoneLinkedList<ScheduleGraphNode*> ready_list(zone());
+
+ // Compute total latencies so that we can schedule the critical path first.
+ ComputeTotalLatencies();
+
+ // Add nodes which don't have dependencies to the ready list.
+ for (auto node : graph_) {
+ if (!node->HasUnscheduledPredecessor()) {
+ ready_list.push_back(node);
+ }
+ }
+
+ // Go through the ready list and schedule the instructions.
+ int cycle = 0;
+ while (!ready_list.empty()) {
+ auto candidate = ready_list.end();
+ for (auto iterator = ready_list.begin(); iterator != ready_list.end();
+ ++iterator) {
+ // Look for the best candidate to schedule.
+ // We only consider instructions that have all their operands ready and
+ // we try to schedule the critical path first (we look for the instruction
+ // with the highest latency on the path to reach the end of the graph).
+ if (cycle >= (*iterator)->start_cycle()) {
+ if ((candidate == ready_list.end()) ||
+ CompareNodes(*iterator, *candidate)) {
+ candidate = iterator;
+ }
+ }
+ }
+
+ if (candidate != ready_list.end()) {
+ sequence()->AddInstruction((*candidate)->instruction());
+
+ for (auto successor : (*candidate)->successors()) {
+ successor->DropUnscheduledPredecessor();
+ successor->set_start_cycle(
+ std::max(successor->start_cycle(),
+ cycle + (*candidate)->latency()));
+
+ if (!successor->HasUnscheduledPredecessor()) {
+ ready_list.push_back(successor);
+ }
+ }
+
+ ready_list.erase(candidate);
+ }
+
+ cycle++;
+ }
+}
+
+
+int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
+ switch (instr->arch_opcode()) {
+ case kArchNop:
+ case kArchStackPointer:
+ case kArchFramePointer:
+ case kArchTruncateDoubleToI:
+ return kNoOpcodeFlags;
+
+ case kArchPrepareCallCFunction:
+ case kArchPrepareTailCall:
+ case kArchCallCFunction:
+ case kArchCallCodeObject:
+ case kArchCallJSFunction:
+ case kArchLazyBailout:
+ return kHasSideEffect;
+
+ case kArchTailCallCodeObject:
+ case kArchTailCallJSFunction:
+ return kHasSideEffect | kIsBlockTerminator;
+
+ case kArchDeoptimize:
+ case kArchJmp:
+ case kArchLookupSwitch:
+ case kArchTableSwitch:
+ case kArchRet:
+ case kArchThrowTerminator:
+ return kIsBlockTerminator;
+
+ case kCheckedLoadInt8:
+ case kCheckedLoadUint8:
+ case kCheckedLoadInt16:
+ case kCheckedLoadUint16:
+ case kCheckedLoadWord32:
+ case kCheckedLoadWord64:
+ case kCheckedLoadFloat32:
+ case kCheckedLoadFloat64:
+ return kIsLoadOperation;
+
+ case kCheckedStoreWord8:
+ case kCheckedStoreWord16:
+ case kCheckedStoreWord32:
+ case kCheckedStoreWord64:
+ case kCheckedStoreFloat32:
+ case kCheckedStoreFloat64:
+ case kArchStoreWithWriteBarrier:
+ return kHasSideEffect;
+
+#define CASE(Name) case k##Name:
+ TARGET_ARCH_OPCODE_LIST(CASE)
+#undef CASE
+ return GetTargetInstructionFlags(instr);
+ }
+
+ UNREACHABLE();
+ return kNoOpcodeFlags;
+}
+
+
+bool InstructionScheduler::HasOperandDependency(
+ const Instruction* instr1, const Instruction* instr2) const {
+ for (size_t i = 0; i < instr1->OutputCount(); ++i) {
+ for (size_t j = 0; j < instr2->InputCount(); ++j) {
+ const InstructionOperand* output = instr1->OutputAt(i);
+ const InstructionOperand* input = instr2->InputAt(j);
+
+ if (output->IsUnallocated() && input->IsUnallocated() &&
+ (UnallocatedOperand::cast(output)->virtual_register() ==
+ UnallocatedOperand::cast(input)->virtual_register())) {
+ return true;
+ }
+
+ if (output->IsConstant() && input->IsUnallocated() &&
+ (ConstantOperand::cast(output)->virtual_register() ==
+ UnallocatedOperand::cast(input)->virtual_register())) {
+ return true;
+ }
+ }
+ }
+
+ // TODO(bafsa): Do we need to look for anti-dependencies/output-dependencies?
+
+ return false;
+}
+
+
+bool InstructionScheduler::IsBlockTerminator(const Instruction* instr) const {
+ return ((GetInstructionFlags(instr) & kIsBlockTerminator) ||
+ (instr->flags_mode() == kFlags_branch));
+}
+
+
+void InstructionScheduler::ComputeTotalLatencies() {
+ for (auto node : base::Reversed(graph_)) {
+ int max_latency = 0;
+
+ for (auto successor : node->successors()) {
+ DCHECK(successor->total_latency() != -1);
+ if (successor->total_latency() > max_latency) {
+ max_latency = successor->total_latency();
+ }
+ }
+
+ node->set_total_latency(max_latency + node->latency());
+ }
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/compiler/instruction-scheduler.h ('k') | src/compiler/instruction-selector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698