| Index: src/compiler/instruction-scheduler.cc
|
| diff --git a/src/compiler/instruction-scheduler.cc b/src/compiler/instruction-scheduler.cc
|
| deleted file mode 100644
|
| index 2f329ead41569959a6db4799f79b03a549d4f31a..0000000000000000000000000000000000000000
|
| --- a/src/compiler/instruction-scheduler.cc
|
| +++ /dev/null
|
| @@ -1,280 +0,0 @@
|
| -// 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
|
|
|