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

Side by Side 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: Created 5 years, 2 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/instruction-scheduler.h"
6
7 namespace v8 {
8 namespace internal {
9 namespace compiler {
10
11 const int InstructionScheduler::instruction_flags_[] = {
Jarin 2015/10/26 15:12:35 I think Chrome cannot have static variables. How a
baptiste.afsa1 2015/10/27 16:00:23 Done.
12 #define ARCH_OPCODE_FLAGS(Name, Flags) Flags,
13 ARCH_OPCODE_LIST(ARCH_OPCODE_FLAGS)
14 #undef ARCH_OPCODE_FLAGS
15 };
16
17
18 InstructionScheduler::ScheduleGraphNode::ScheduleGraphNode(
19 Zone* zone,
20 Instruction* instr)
21 : instr_(instr),
22 successors_(zone),
23 dependency_count_(0),
24 latency_(GetInstructionLatency(instr)),
25 total_latency_(-1),
26 start_cycle_(-1) {
27 }
28
29
30 void InstructionScheduler::ScheduleGraphNode::AddSuccessor(
31 ScheduleGraphNode* node) {
32 successors_.push_back(node);
33 node->dependency_count_++;
34 }
35
36
37 InstructionScheduler::InstructionScheduler(Zone* zone,
38 InstructionSequence* sequence)
39 : zone_(zone),
40 sequence_(sequence),
41 graph_(zone) {
42 }
43
44
45 void InstructionScheduler::StartBlock(RpoNumber rpo) {
46 DCHECK(graph_.empty());
47 sequence()->StartBlock(rpo);
48 }
49
50
51 void InstructionScheduler::EndBlock(RpoNumber rpo) {
52 ScheduleBlock();
53 sequence()->EndBlock(rpo);
54 graph_.clear();
55 }
56
57
58 void InstructionScheduler::AddInstruction(Instruction* instr) {
59 ScheduleGraphNode* new_node = new (zone()) ScheduleGraphNode(zone(), instr);
60
61 for (auto node : graph_) {
62 if (HasOperandDependency(node->instruction(), instr) ||
63 // Make sure that basic block terminators are not moved by adding them
64 // as successor of every instruction.
65 IsBlockTerminator(instr) ||
66
67 // Instructions with side effects and memory operations can't be
68 // reordered.
69 (HasSideEffect(node->instruction()) && HasSideEffect(instr)) ||
70 (IsLoadOperation(node->instruction()) && HasSideEffect(instr)) ||
71 (HasSideEffect(node->instruction()) && IsLoadOperation(instr)) ||
72
73 // These nops are used to mark a defining instruction for some live
74 // ranges in the register allocator. They must not be moved.
75 ((node->instruction()->arch_opcode() == kArchNop) &&
76 (node->instruction()->OutputAt(0)->IsUnallocated()) &&
77 UnallocatedOperand::cast(
78 node->instruction()->OutputAt(0))->HasFixedRegisterPolicy())) {
79 node->AddSuccessor(new_node);
80 }
Jarin 2015/10/27 09:02:31 This loop is worrisome: for a basic block with n i
baptiste.afsa1 2015/10/27 16:00:24 Yes, good idea. I'll fix this.
81 }
82
83 graph_.push_back(new_node);
84 }
85
86
87 bool InstructionScheduler::CompareNodes(ScheduleGraphNode *node1,
88 ScheduleGraphNode *node2) const {
89 return node1->total_latency() > node2->total_latency();
90 }
91
92
93 void InstructionScheduler::ScheduleBlock() {
94 ZoneLinkedList<ScheduleGraphNode*> ready_list(zone());
95
96 // Compute total latency so that we can schedule the critical path first and
97 // add nodes which don't have dependencies to the ready list.
98 for (auto node : graph_) {
Jarin 2015/10/26 15:12:35 nit: If you went from the end of the graph, then y
baptiste.afsa1 2015/10/27 16:00:24 I would also need to be able to go from a node to
99 if (!node->HasDependency()) {
100 ComputeTotalLatency(node);
101 ready_list.push_back(node);
102 }
103 }
104
105 // Go through the ready list and schedule the instructions.
106 int cycle = 0;
107 while (!ready_list.empty()) {
108 auto candidate = ready_list.end();
109 for (auto iterator = ready_list.begin(); iterator != ready_list.end();
110 ++iterator) {
111 if (cycle >= (*iterator)->start_cycle()) {
Jarin 2015/10/26 15:12:35 Could you add a comment here explaining that you o
baptiste.afsa1 2015/10/27 16:00:24 Done.
112 if ((candidate == ready_list.end()) ||
113 CompareNodes(*iterator, *candidate)) {
114 candidate = iterator;
115 }
116 }
117 }
118
119 if (candidate != ready_list.end()) {
120 sequence()->AddInstruction((*candidate)->instruction());
121
122 for (auto successor : (*candidate)->successors()) {
123 successor->DropDependency();
124 successor->set_start_cycle(
125 std::max(successor->start_cycle(),
126 cycle + (*candidate)->latency()));
127
128 if (!successor->HasDependency()) {
129 ready_list.push_back(successor);
130 }
131 }
132
133 ready_list.erase(candidate);
134 }
135
136 cycle++;
137 }
138 }
139
140
141 bool InstructionScheduler::HasOperandDependency(
142 const Instruction* instr1, const Instruction* instr2) const {
143 for (int i = 0; i < instr1->OutputCount(); ++i) {
144 for (int j = 0; j < instr2->InputCount(); ++j) {
145 const InstructionOperand* output = instr1->OutputAt(i);
146 const InstructionOperand* input = instr2->InputAt(j);
147
148 if (output->IsUnallocated() && input->IsUnallocated() &&
149 (UnallocatedOperand::cast(output)->virtual_register() ==
150 UnallocatedOperand::cast(input)->virtual_register())) {
151 return true;
152 }
153
154 if (output->IsConstant() && input->IsUnallocated() &&
155 (ConstantOperand::cast(output)->virtual_register() ==
156 UnallocatedOperand::cast(input)->virtual_register())) {
157 return true;
158 }
159 }
160 }
161
162 // TODO(bafsa): Do we need to look for anti-dependencies/output-dependencies?
Jarin 2015/10/26 15:12:35 I think we don't because SSA (although I am not en
baptiste.afsa1 2015/10/27 16:00:23 It was my initial thought but I wasn't too sure.
163
164 return false;
165 }
166
167
168 bool InstructionScheduler::IsBlockTerminator(const Instruction* instr) const {
169 return ((instruction_flags_[instr->arch_opcode()] & kIsBlockTerminator) ||
170 (instr->flags_mode() == kFlags_branch) ||
171 // TODO(all): TurboFan throw nodes are currently turned into nops.
172 // These nops must not be reordered when they occur at the end of a
173 // basic block. We need to find a more reliable way to catch those.
Jarin 2015/10/26 15:12:35 Why can't they be reordered? These should be unrea
baptiste.afsa1 2015/10/27 16:00:23 It triggers an assertion in the register allocator
174 ((instr->arch_opcode() == kArchNop) && (instr->OutputCount() == 0) &&
175 (instr->InputCount() == 0)));
176 }
177
178
179 void InstructionScheduler::ComputeTotalLatency(ScheduleGraphNode* node) {
180 int max_latency = 0;
181
182 for (auto successor : node->successors()) {
183 if (successor->total_latency() == -1) {
184 ComputeTotalLatency(successor);
185 }
186
187 if (successor->total_latency() > max_latency) {
188 max_latency = successor->total_latency();
189 }
190 }
191
192 node->set_total_latency(max_latency + node->latency());
193 }
194
195 } // namespace compiler
196 } // namespace internal
197 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698