5 #include "src/compiler/backend/instruction-scheduler.h" 7 #include "src/base/adapters.h" 8 #include "src/base/utils/random-number-generator.h" 9 #include "src/isolate.h" 15 void InstructionScheduler::SchedulingQueueBase::AddNode(
16 ScheduleGraphNode* node) {
19 auto it = nodes_.begin();
20 while ((it != nodes_.end()) &&
21 ((*it)->total_latency() >= node->total_latency())) {
24 nodes_.insert(it, node);
27 InstructionScheduler::ScheduleGraphNode*
28 InstructionScheduler::CriticalPathFirstQueue::PopBestCandidate(
int cycle) {
30 auto candidate = nodes_.end();
31 for (
auto iterator = nodes_.begin(); iterator != nodes_.end(); ++iterator) {
33 if (cycle >= (*iterator)->start_cycle()) {
39 if (candidate != nodes_.end()) {
40 ScheduleGraphNode* result = *candidate;
41 nodes_.erase(candidate);
48 InstructionScheduler::ScheduleGraphNode*
49 InstructionScheduler::StressSchedulerQueue::PopBestCandidate(
int cycle) {
52 auto candidate = nodes_.begin();
53 std::advance(candidate, isolate()->random_number_generator()->NextInt(
54 static_cast<int>(nodes_.size())));
55 ScheduleGraphNode* result = *candidate;
56 nodes_.erase(candidate);
60 InstructionScheduler::ScheduleGraphNode::ScheduleGraphNode(Zone* zone,
64 unscheduled_predecessors_count_(0),
65 latency_(GetInstructionLatency(instr)),
69 void InstructionScheduler::ScheduleGraphNode::AddSuccessor(
70 ScheduleGraphNode* node) {
71 successors_.push_back(node);
72 node->unscheduled_predecessors_count_++;
75 InstructionScheduler::InstructionScheduler(Zone* zone,
76 InstructionSequence* sequence)
80 last_side_effect_instr_(nullptr),
82 last_live_in_reg_marker_(nullptr),
83 last_deopt_or_trap_(nullptr),
84 operands_map_(zone) {}
86 void InstructionScheduler::StartBlock(RpoNumber rpo) {
87 DCHECK(graph_.empty());
88 DCHECK_NULL(last_side_effect_instr_);
89 DCHECK(pending_loads_.empty());
90 DCHECK_NULL(last_live_in_reg_marker_);
91 DCHECK_NULL(last_deopt_or_trap_);
92 DCHECK(operands_map_.empty());
93 sequence()->StartBlock(rpo);
96 void InstructionScheduler::EndBlock(RpoNumber rpo) {
97 if (FLAG_turbo_stress_instruction_scheduling) {
98 ScheduleBlock<StressSchedulerQueue>();
100 ScheduleBlock<CriticalPathFirstQueue>();
102 sequence()->EndBlock(rpo);
104 last_side_effect_instr_ =
nullptr;
105 pending_loads_.clear();
106 last_live_in_reg_marker_ =
nullptr;
107 last_deopt_or_trap_ =
nullptr;
108 operands_map_.clear();
111 void InstructionScheduler::AddTerminator(Instruction* instr) {
112 ScheduleGraphNode* new_node =
new (zone()) ScheduleGraphNode(zone(), instr);
115 for (ScheduleGraphNode* node : graph_) {
116 node->AddSuccessor(new_node);
118 graph_.push_back(new_node);
121 void InstructionScheduler::AddInstruction(Instruction* instr) {
122 ScheduleGraphNode* new_node =
new (zone()) ScheduleGraphNode(zone(), instr);
125 DCHECK_NE(instr->flags_mode(), kFlags_branch);
126 DCHECK_NE(instr->flags_mode(), kFlags_branch_and_poison);
128 if (IsFixedRegisterParameter(instr)) {
129 if (last_live_in_reg_marker_ !=
nullptr) {
130 last_live_in_reg_marker_->AddSuccessor(new_node);
132 last_live_in_reg_marker_ = new_node;
134 if (last_live_in_reg_marker_ !=
nullptr) {
135 last_live_in_reg_marker_->AddSuccessor(new_node);
140 if ((last_deopt_or_trap_ !=
nullptr) && DependsOnDeoptOrTrap(instr)) {
141 last_deopt_or_trap_->AddSuccessor(new_node);
146 if (HasSideEffect(instr)) {
147 if (last_side_effect_instr_ !=
nullptr) {
148 last_side_effect_instr_->AddSuccessor(new_node);
150 for (ScheduleGraphNode* load : pending_loads_) {
151 load->AddSuccessor(new_node);
153 pending_loads_.clear();
154 last_side_effect_instr_ = new_node;
155 }
else if (IsLoadOperation(instr)) {
158 if (last_side_effect_instr_ !=
nullptr) {
159 last_side_effect_instr_->AddSuccessor(new_node);
161 pending_loads_.push_back(new_node);
162 }
else if (instr->IsDeoptimizeCall() || instr->IsTrap()) {
165 if (last_side_effect_instr_ !=
nullptr) {
166 last_side_effect_instr_->AddSuccessor(new_node);
168 last_deopt_or_trap_ = new_node;
172 for (
size_t i = 0;
i < instr->InputCount(); ++
i) {
173 const InstructionOperand* input = instr->InputAt(
i);
174 if (input->IsUnallocated()) {
175 int32_t vreg = UnallocatedOperand::cast(input)->virtual_register();
176 auto it = operands_map_.find(vreg);
177 if (it != operands_map_.end()) {
178 it->second->AddSuccessor(new_node);
184 for (
size_t i = 0;
i < instr->OutputCount(); ++
i) {
185 const InstructionOperand* output = instr->OutputAt(
i);
186 if (output->IsUnallocated()) {
187 operands_map_[UnallocatedOperand::cast(output)->virtual_register()] =
189 }
else if (output->IsConstant()) {
190 operands_map_[ConstantOperand::cast(output)->virtual_register()] =
196 graph_.push_back(new_node);
199 template <
typename QueueType>
200 void InstructionScheduler::ScheduleBlock() {
201 QueueType ready_list(
this);
204 ComputeTotalLatencies();
207 for (ScheduleGraphNode* node : graph_) {
208 if (!node->HasUnscheduledPredecessor()) {
209 ready_list.AddNode(node);
215 while (!ready_list.IsEmpty()) {
216 ScheduleGraphNode* candidate = ready_list.PopBestCandidate(cycle);
218 if (candidate !=
nullptr) {
219 sequence()->AddInstruction(candidate->instruction());
221 for (ScheduleGraphNode* successor : candidate->successors()) {
222 successor->DropUnscheduledPredecessor();
223 successor->set_start_cycle(
224 std::max(successor->start_cycle(), cycle + candidate->latency()));
226 if (!successor->HasUnscheduledPredecessor()) {
227 ready_list.AddNode(successor);
236 int InstructionScheduler::GetInstructionFlags(
const Instruction* instr)
const {
237 switch (instr->arch_opcode()) {
239 case kArchFramePointer:
240 case kArchParentFramePointer:
245 case kArchDeoptimize:
247 case kArchBinarySearchSwitch:
248 case kArchLookupSwitch:
250 case kArchTableSwitch:
251 case kArchThrowTerminator:
252 return kNoOpcodeFlags;
254 case kArchTruncateDoubleToI:
255 case kIeee754Float64Acos:
256 case kIeee754Float64Acosh:
257 case kIeee754Float64Asin:
258 case kIeee754Float64Asinh:
259 case kIeee754Float64Atan:
260 case kIeee754Float64Atanh:
261 case kIeee754Float64Atan2:
262 case kIeee754Float64Cbrt:
263 case kIeee754Float64Cos:
264 case kIeee754Float64Cosh:
265 case kIeee754Float64Exp:
266 case kIeee754Float64Expm1:
267 case kIeee754Float64Log:
268 case kIeee754Float64Log1p:
269 case kIeee754Float64Log10:
270 case kIeee754Float64Log2:
271 case kIeee754Float64Pow:
272 case kIeee754Float64Sin:
273 case kIeee754Float64Sinh:
274 case kIeee754Float64Tan:
275 case kIeee754Float64Tanh:
276 return kNoOpcodeFlags;
278 case kArchStackPointer:
281 return kIsLoadOperation;
283 case kArchWordPoisonOnSpeculation:
286 return kHasSideEffect;
288 case kArchPrepareCallCFunction:
289 case kArchSaveCallerRegisters:
290 case kArchRestoreCallerRegisters:
291 case kArchPrepareTailCall:
292 case kArchCallCFunction:
293 case kArchCallCodeObject:
294 case kArchCallJSFunction:
295 case kArchCallWasmFunction:
296 case kArchTailCallCodeObjectFromJSFunction:
297 case kArchTailCallCodeObject:
298 case kArchTailCallAddress:
299 case kArchTailCallWasm:
300 case kArchDebugAbort:
301 case kArchDebugBreak:
302 return kHasSideEffect;
304 case kArchStoreWithWriteBarrier:
305 return kHasSideEffect;
307 case kWord32AtomicLoadInt8:
308 case kWord32AtomicLoadUint8:
309 case kWord32AtomicLoadInt16:
310 case kWord32AtomicLoadUint16:
311 case kWord32AtomicLoadWord32:
312 return kIsLoadOperation;
314 case kWord32AtomicStoreWord8:
315 case kWord32AtomicStoreWord16:
316 case kWord32AtomicStoreWord32:
317 return kHasSideEffect;
319 case kWord32AtomicExchangeInt8:
320 case kWord32AtomicExchangeUint8:
321 case kWord32AtomicExchangeInt16:
322 case kWord32AtomicExchangeUint16:
323 case kWord32AtomicExchangeWord32:
324 case kWord32AtomicCompareExchangeInt8:
325 case kWord32AtomicCompareExchangeUint8:
326 case kWord32AtomicCompareExchangeInt16:
327 case kWord32AtomicCompareExchangeUint16:
328 case kWord32AtomicCompareExchangeWord32:
329 case kWord32AtomicAddInt8:
330 case kWord32AtomicAddUint8:
331 case kWord32AtomicAddInt16:
332 case kWord32AtomicAddUint16:
333 case kWord32AtomicAddWord32:
334 case kWord32AtomicSubInt8:
335 case kWord32AtomicSubUint8:
336 case kWord32AtomicSubInt16:
337 case kWord32AtomicSubUint16:
338 case kWord32AtomicSubWord32:
339 case kWord32AtomicAndInt8:
340 case kWord32AtomicAndUint8:
341 case kWord32AtomicAndInt16:
342 case kWord32AtomicAndUint16:
343 case kWord32AtomicAndWord32:
344 case kWord32AtomicOrInt8:
345 case kWord32AtomicOrUint8:
346 case kWord32AtomicOrInt16:
347 case kWord32AtomicOrUint16:
348 case kWord32AtomicOrWord32:
349 case kWord32AtomicXorInt8:
350 case kWord32AtomicXorUint8:
351 case kWord32AtomicXorInt16:
352 case kWord32AtomicXorUint16:
353 case kWord32AtomicXorWord32:
354 return kHasSideEffect;
356 #define CASE(Name) case k##Name: 357 TARGET_ARCH_OPCODE_LIST(CASE)
359 return GetTargetInstructionFlags(instr);
365 void InstructionScheduler::ComputeTotalLatencies() {
366 for (ScheduleGraphNode* node : base::Reversed(graph_)) {
369 for (ScheduleGraphNode* successor : node->successors()) {
370 DCHECK_NE(-1, successor->total_latency());
371 if (successor->total_latency() > max_latency) {
372 max_latency = successor->total_latency();
376 node->set_total_latency(max_latency + node->latency());