OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 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 #ifndef V8_COMPILER_INSTRUCTION_SCHEDULER_H_ | 5 #ifndef V8_COMPILER_INSTRUCTION_SCHEDULER_H_ |
6 #define V8_COMPILER_INSTRUCTION_SCHEDULER_H_ | 6 #define V8_COMPILER_INSTRUCTION_SCHEDULER_H_ |
7 | 7 |
8 #include "src/compiler/instruction.h" | 8 #include "src/compiler/instruction.h" |
9 #include "src/zone/zone-containers.h" | 9 #include "src/zone/zone-containers.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 namespace compiler { | 13 namespace compiler { |
14 | 14 |
15 // A set of flags describing properties of the instructions so that the | 15 // A set of flags describing properties of the instructions so that the |
16 // scheduler is aware of dependencies between instructions. | 16 // scheduler is aware of dependencies between instructions. |
17 enum ArchOpcodeFlags { | 17 enum ArchOpcodeFlags { |
18 kNoOpcodeFlags = 0, | 18 kNoOpcodeFlags = 0, |
19 kIsBlockTerminator = 1, // The instruction marks the end of a basic block | 19 kIsBlockTerminator = 1, // The instruction marks the end of a basic block |
20 // e.g.: jump and return instructions. | 20 // e.g.: jump and return instructions. |
21 kHasSideEffect = 2, // The instruction has some side effects (memory | 21 kHasSideEffect = 2, // The instruction has some side effects (memory |
22 // store, function call...) | 22 // store, function call...) |
23 kIsLoadOperation = 4, // The instruction is a memory load. | 23 kIsLoadOperation = 4, // The instruction is a memory load. |
24 kMayNeedDeoptCheck = 8, // The instruction might be associated with a deopt | 24 kMayNeedDeoptOrTrapCheck = 8, // The instruction may be associated with a |
25 // check. This is the case of instruction which can | 25 // deopt or trap check which must be run before |
26 // blow up with particular inputs (e.g.: division by | 26 // instruction e.g. div on Intel platform which |
27 // zero on Intel platforms). | 27 // will raise an exception when the divisor is |
| 28 // zero. |
28 }; | 29 }; |
29 | 30 |
30 class InstructionScheduler final : public ZoneObject { | 31 class InstructionScheduler final : public ZoneObject { |
31 public: | 32 public: |
32 InstructionScheduler(Zone* zone, InstructionSequence* sequence); | 33 InstructionScheduler(Zone* zone, InstructionSequence* sequence); |
33 | 34 |
34 void StartBlock(RpoNumber rpo); | 35 void StartBlock(RpoNumber rpo); |
35 void EndBlock(RpoNumber rpo); | 36 void EndBlock(RpoNumber rpo); |
36 | 37 |
37 void AddInstruction(Instruction* instr); | 38 void AddInstruction(Instruction* instr); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 // memory store). | 160 // memory store). |
160 bool HasSideEffect(const Instruction* instr) const { | 161 bool HasSideEffect(const Instruction* instr) const { |
161 return (GetInstructionFlags(instr) & kHasSideEffect) != 0; | 162 return (GetInstructionFlags(instr) & kHasSideEffect) != 0; |
162 } | 163 } |
163 | 164 |
164 // Return true if the instruction is a memory load. | 165 // Return true if the instruction is a memory load. |
165 bool IsLoadOperation(const Instruction* instr) const { | 166 bool IsLoadOperation(const Instruction* instr) const { |
166 return (GetInstructionFlags(instr) & kIsLoadOperation) != 0; | 167 return (GetInstructionFlags(instr) & kIsLoadOperation) != 0; |
167 } | 168 } |
168 | 169 |
169 // Return true if this instruction is usually associated with a deopt check | 170 // The scheduler will not move the following instructions before the last |
170 // to validate its input. | 171 // deopt/trap check: |
171 bool MayNeedDeoptCheck(const Instruction* instr) const { | 172 // * loads (this is conservative) |
172 return (GetInstructionFlags(instr) & kMayNeedDeoptCheck) != 0; | 173 // * instructions with side effect |
| 174 // * other deopts/traps |
| 175 // Any other instruction can be moved, apart from those that raise exceptions |
| 176 // on specific inputs - these are filtered out by the deopt/trap check. |
| 177 bool MayNeedDeoptOrTrapCheck(const Instruction* instr) const { |
| 178 return (GetInstructionFlags(instr) & kMayNeedDeoptOrTrapCheck) != 0; |
173 } | 179 } |
174 | 180 |
175 // Return true if the instruction cannot be moved before the last deopt | 181 // Return true if the instruction cannot be moved before the last deopt or |
176 // point we encountered. | 182 // trap point we encountered. |
177 bool DependsOnDeoptimization(const Instruction* instr) const { | 183 bool DependsOnDeoptOrTrap(const Instruction* instr) const { |
178 return MayNeedDeoptCheck(instr) || instr->IsDeoptimizeCall() || | 184 return MayNeedDeoptOrTrapCheck(instr) || instr->IsDeoptimizeCall() || |
179 HasSideEffect(instr) || IsLoadOperation(instr); | 185 instr->IsTrap() || HasSideEffect(instr) || IsLoadOperation(instr); |
180 } | 186 } |
181 | 187 |
182 // Identify nops used as a definition point for live-in registers at | 188 // Identify nops used as a definition point for live-in registers at |
183 // function entry. | 189 // function entry. |
184 bool IsFixedRegisterParameter(const Instruction* instr) const { | 190 bool IsFixedRegisterParameter(const Instruction* instr) const { |
185 return (instr->arch_opcode() == kArchNop) && (instr->OutputCount() == 1) && | 191 return (instr->arch_opcode() == kArchNop) && (instr->OutputCount() == 1) && |
186 (instr->OutputAt(0)->IsUnallocated()) && | 192 (instr->OutputAt(0)->IsUnallocated()) && |
187 (UnallocatedOperand::cast(instr->OutputAt(0)) | 193 (UnallocatedOperand::cast(instr->OutputAt(0)) |
188 ->HasFixedRegisterPolicy() || | 194 ->HasFixedRegisterPolicy() || |
189 UnallocatedOperand::cast(instr->OutputAt(0)) | 195 UnallocatedOperand::cast(instr->OutputAt(0)) |
(...skipping 20 matching lines...) Expand all Loading... |
210 // effects. | 216 // effects. |
211 ZoneVector<ScheduleGraphNode*> pending_loads_; | 217 ZoneVector<ScheduleGraphNode*> pending_loads_; |
212 | 218 |
213 // Live-in register markers are nop instructions which are emitted at the | 219 // Live-in register markers are nop instructions which are emitted at the |
214 // beginning of a basic block so that the register allocator will find a | 220 // beginning of a basic block so that the register allocator will find a |
215 // defining instruction for live-in values. They must not be moved. | 221 // defining instruction for live-in values. They must not be moved. |
216 // All these nops are chained together and added as a predecessor of every | 222 // All these nops are chained together and added as a predecessor of every |
217 // other instructions in the basic block. | 223 // other instructions in the basic block. |
218 ScheduleGraphNode* last_live_in_reg_marker_; | 224 ScheduleGraphNode* last_live_in_reg_marker_; |
219 | 225 |
220 // Last deoptimization instruction encountered while building the graph. | 226 // Last deoptimization or trap instruction encountered while building the |
221 ScheduleGraphNode* last_deopt_; | 227 // graph. |
| 228 ScheduleGraphNode* last_deopt_or_trap_; |
222 | 229 |
223 // Keep track of definition points for virtual registers. This is used to | 230 // Keep track of definition points for virtual registers. This is used to |
224 // record operand dependencies in the scheduling graph. | 231 // record operand dependencies in the scheduling graph. |
225 ZoneMap<int32_t, ScheduleGraphNode*> operands_map_; | 232 ZoneMap<int32_t, ScheduleGraphNode*> operands_map_; |
226 }; | 233 }; |
227 | 234 |
228 } // namespace compiler | 235 } // namespace compiler |
229 } // namespace internal | 236 } // namespace internal |
230 } // namespace v8 | 237 } // namespace v8 |
231 | 238 |
232 #endif // V8_COMPILER_INSTRUCTION_SCHEDULER_H_ | 239 #endif // V8_COMPILER_INSTRUCTION_SCHEDULER_H_ |
OLD | NEW |