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 #include "src/compiler/effect-control-linearizer.h" | 5 #include "src/compiler/effect-control-linearizer.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/compiler/access-builder.h" | 8 #include "src/compiler/access-builder.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/linkage.h" | 10 #include "src/compiler/linkage.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 } | 27 } |
28 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { | 28 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { |
29 return js_graph_->simplified(); | 29 return js_graph_->simplified(); |
30 } | 30 } |
31 MachineOperatorBuilder* EffectControlLinearizer::machine() const { | 31 MachineOperatorBuilder* EffectControlLinearizer::machine() const { |
32 return js_graph_->machine(); | 32 return js_graph_->machine(); |
33 } | 33 } |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 struct BlockEffectData { | 37 struct BlockEffectControlData { |
38 Node* current_effect = nullptr; // New effect. | 38 Node* current_effect = nullptr; // New effect. |
| 39 Node* current_control = nullptr; // New control. |
39 }; | 40 }; |
40 | 41 |
41 // Effect phis that need to be updated after the first pass. | 42 // Effect phis that need to be updated after the first pass. |
42 struct PendingEffectPhi { | 43 struct PendingEffectPhi { |
43 Node* effect_phi; | 44 Node* effect_phi; |
44 BasicBlock* block; | 45 BasicBlock* block; |
45 | 46 |
46 PendingEffectPhi(Node* effect_phi, BasicBlock* block) | 47 PendingEffectPhi(Node* effect_phi, BasicBlock* block) |
47 : effect_phi(effect_phi), block(block) {} | 48 : effect_phi(effect_phi), block(block) {} |
48 }; | 49 }; |
49 | 50 |
50 void UpdateEffectPhi(Node* node, BasicBlock* block, | 51 void UpdateEffectPhi(Node* node, BasicBlock* block, |
51 ZoneVector<BlockEffectData>* block_effects) { | 52 ZoneVector<BlockEffectControlData>* block_effects) { |
52 // Update all inputs to an effect phi with the effects from the given | 53 // Update all inputs to an effect phi with the effects from the given |
53 // block->effect map. | 54 // block->effect map. |
54 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); | 55 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); |
55 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount()); | 56 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount()); |
56 for (int i = 0; i < node->op()->EffectInputCount(); i++) { | 57 for (int i = 0; i < node->op()->EffectInputCount(); i++) { |
57 Node* input = node->InputAt(i); | 58 Node* input = node->InputAt(i); |
58 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); | 59 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
59 Node* input_effect = | 60 Node* input_effect = |
60 (*block_effects)[predecessor->rpo_number()].current_effect; | 61 (*block_effects)[predecessor->rpo_number()].current_effect; |
61 if (input != input_effect) { | 62 if (input != input_effect) { |
62 node->ReplaceInput(i, input_effect); | 63 node->ReplaceInput(i, input_effect); |
63 } | 64 } |
64 } | 65 } |
65 } | 66 } |
66 | 67 |
| 68 void UpdateBlockControl(BasicBlock* block, |
| 69 ZoneVector<BlockEffectControlData>* block_effects) { |
| 70 Node* control = block->NodeAt(0); |
| 71 DCHECK(NodeProperties::IsControl(control)); |
| 72 |
| 73 // Do not rewire the end node. |
| 74 if (control->opcode() == IrOpcode::kEnd) return; |
| 75 |
| 76 // Update all inputs to the given control node with the correct control. |
| 77 DCHECK_EQ(control->op()->ControlInputCount(), block->PredecessorCount()); |
| 78 for (int i = 0; i < control->op()->ControlInputCount(); i++) { |
| 79 Node* input = NodeProperties::GetControlInput(control, i); |
| 80 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
| 81 Node* input_control = |
| 82 (*block_effects)[predecessor->rpo_number()].current_control; |
| 83 if (input != input_control) { |
| 84 NodeProperties::ReplaceControlInput(control, input_control, i); |
| 85 } |
| 86 } |
| 87 } |
| 88 |
67 bool HasIncomingBackEdges(BasicBlock* block) { | 89 bool HasIncomingBackEdges(BasicBlock* block) { |
68 for (BasicBlock* pred : block->predecessors()) { | 90 for (BasicBlock* pred : block->predecessors()) { |
69 if (pred->rpo_number() >= block->rpo_number()) { | 91 if (pred->rpo_number() >= block->rpo_number()) { |
70 return true; | 92 return true; |
71 } | 93 } |
72 } | 94 } |
73 return false; | 95 return false; |
74 } | 96 } |
75 | 97 |
76 void RemoveRegionNode(Node* node) { | 98 void RemoveRegionNode(Node* node) { |
(...skipping 10 matching lines...) Expand all Loading... |
87 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); | 109 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); |
88 edge.UpdateTo(node->InputAt(0)); | 110 edge.UpdateTo(node->InputAt(0)); |
89 } | 111 } |
90 } | 112 } |
91 node->Kill(); | 113 node->Kill(); |
92 } | 114 } |
93 | 115 |
94 } // namespace | 116 } // namespace |
95 | 117 |
96 void EffectControlLinearizer::Run() { | 118 void EffectControlLinearizer::Run() { |
97 ZoneVector<BlockEffectData> block_effects(temp_zone()); | 119 ZoneVector<BlockEffectControlData> block_effects(temp_zone()); |
98 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); | 120 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); |
| 121 ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); |
99 block_effects.resize(schedule()->RpoBlockCount()); | 122 block_effects.resize(schedule()->RpoBlockCount()); |
100 NodeVector inputs_buffer(temp_zone()); | 123 NodeVector inputs_buffer(temp_zone()); |
101 | 124 |
102 for (BasicBlock* block : *(schedule()->rpo_order())) { | 125 for (BasicBlock* block : *(schedule()->rpo_order())) { |
103 size_t instr = 0; | 126 size_t instr = 0; |
104 | 127 |
105 // The control node should be the first. | 128 // The control node should be the first. |
106 Node* control = block->NodeAt(instr); | 129 Node* control = block->NodeAt(instr); |
107 DCHECK(NodeProperties::IsControl(control)); | 130 DCHECK(NodeProperties::IsControl(control)); |
| 131 // Update the control inputs. |
| 132 if (HasIncomingBackEdges(block)) { |
| 133 // If there are back edges, we need to update later because we have not |
| 134 // computed the control yet. This should only happen for loops. |
| 135 DCHECK_EQ(IrOpcode::kLoop, control->opcode()); |
| 136 pending_block_controls.push_back(block); |
| 137 } else { |
| 138 // If there are no back edges, we can update now. |
| 139 UpdateBlockControl(block, &block_effects); |
| 140 } |
108 instr++; | 141 instr++; |
109 | 142 |
110 // Iterate over the phis and update the effect phis. | 143 // Iterate over the phis and update the effect phis. |
111 Node* effect = nullptr; | 144 Node* effect = nullptr; |
112 Node* terminate = nullptr; | 145 Node* terminate = nullptr; |
113 for (; instr < block->NodeCount(); instr++) { | 146 for (; instr < block->NodeCount(); instr++) { |
114 Node* node = block->NodeAt(instr); | 147 Node* node = block->NodeAt(instr); |
115 // Only go through the phis and effect phis. | 148 // Only go through the phis and effect phis. |
116 if (node->opcode() == IrOpcode::kEffectPhi) { | 149 if (node->opcode() == IrOpcode::kEffectPhi) { |
117 // There should be at most one effect phi in a block. | 150 // There should be at most one effect phi in a block. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 inputs_buffer.clear(); | 203 inputs_buffer.clear(); |
171 inputs_buffer.resize(block->PredecessorCount(), graph()->start()); | 204 inputs_buffer.resize(block->PredecessorCount(), graph()->start()); |
172 inputs_buffer.push_back(control); | 205 inputs_buffer.push_back(control); |
173 effect = graph()->NewNode( | 206 effect = graph()->NewNode( |
174 common()->EffectPhi(static_cast<int>(block->PredecessorCount())), | 207 common()->EffectPhi(static_cast<int>(block->PredecessorCount())), |
175 static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front())); | 208 static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front())); |
176 // Let us update the effect phi node later. | 209 // Let us update the effect phi node later. |
177 pending_effect_phis.push_back(PendingEffectPhi(effect, block)); | 210 pending_effect_phis.push_back(PendingEffectPhi(effect, block)); |
178 } else if (control->opcode() == IrOpcode::kIfException) { | 211 } else if (control->opcode() == IrOpcode::kIfException) { |
179 // The IfException is connected into the effect chain, so we need | 212 // The IfException is connected into the effect chain, so we need |
180 // to process it here. | 213 // to update the effect here. |
181 ProcessNode(control, &effect, &control); | 214 NodeProperties::ReplaceEffectInput(control, effect); |
| 215 effect = control; |
182 } | 216 } |
183 } | 217 } |
184 } | 218 } |
185 | 219 |
186 // Fixup the Terminate node. | 220 // Fixup the Terminate node. |
187 if (terminate != nullptr) { | 221 if (terminate != nullptr) { |
188 NodeProperties::ReplaceEffectInput(terminate, effect); | 222 NodeProperties::ReplaceEffectInput(terminate, effect); |
189 } | 223 } |
190 | 224 |
191 // Process the ordinary instructions. | 225 // Process the ordinary instructions. |
(...skipping 13 matching lines...) Expand all Loading... |
205 case BasicBlock::kSwitch: | 239 case BasicBlock::kSwitch: |
206 case BasicBlock::kReturn: | 240 case BasicBlock::kReturn: |
207 case BasicBlock::kDeoptimize: | 241 case BasicBlock::kDeoptimize: |
208 case BasicBlock::kThrow: | 242 case BasicBlock::kThrow: |
209 ProcessNode(block->control_input(), &effect, &control); | 243 ProcessNode(block->control_input(), &effect, &control); |
210 break; | 244 break; |
211 } | 245 } |
212 | 246 |
213 // Store the effect for later use. | 247 // Store the effect for later use. |
214 block_effects[block->rpo_number()].current_effect = effect; | 248 block_effects[block->rpo_number()].current_effect = effect; |
| 249 block_effects[block->rpo_number()].current_control = control; |
215 } | 250 } |
216 | 251 |
217 // Update the incoming edges of the effect phis that could not be processed | 252 // Update the incoming edges of the effect phis that could not be processed |
218 // during the first pass (because they could have incoming back edges). | 253 // during the first pass (because they could have incoming back edges). |
219 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { | 254 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { |
220 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, | 255 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, |
221 &block_effects); | 256 &block_effects); |
222 } | 257 } |
| 258 for (BasicBlock* pending_block_control : pending_block_controls) { |
| 259 UpdateBlockControl(pending_block_control, &block_effects); |
| 260 } |
223 } | 261 } |
224 | 262 |
| 263 namespace { |
| 264 |
| 265 void TryScheduleCallIfSuccess(Node* node, Node** control) { |
| 266 // Schedule the call's IfSuccess node if there is no exception use. |
| 267 if (!NodeProperties::IsExceptionalCall(node)) { |
| 268 for (Edge edge : node->use_edges()) { |
| 269 if (NodeProperties::IsControlEdge(edge) && |
| 270 edge.from()->opcode() == IrOpcode::kIfSuccess) { |
| 271 *control = edge.from(); |
| 272 } |
| 273 } |
| 274 } |
| 275 } |
| 276 |
| 277 } // namespace |
| 278 |
225 void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, | 279 void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, |
226 Node** control) { | 280 Node** control) { |
227 // If the node needs to be wired into the effect/control chain, do this | 281 // If the node needs to be wired into the effect/control chain, do this |
228 // here. | 282 // here. |
229 if (TryWireInStateEffect(node, effect, control)) { | 283 if (TryWireInStateEffect(node, effect, control)) { |
230 return; | 284 return; |
231 } | 285 } |
232 | 286 |
233 // Remove the end markers of 'atomic' allocation region because the | 287 // Remove the end markers of 'atomic' allocation region because the |
234 // region should be wired-in now. | 288 // region should be wired-in now. |
235 if (node->opcode() == IrOpcode::kFinishRegion || | 289 if (node->opcode() == IrOpcode::kFinishRegion || |
236 node->opcode() == IrOpcode::kBeginRegion) { | 290 node->opcode() == IrOpcode::kBeginRegion) { |
237 // Update the value uses to the value input of the finish node and | 291 // Update the value uses to the value input of the finish node and |
238 // the effect uses to the effect input. | 292 // the effect uses to the effect input. |
239 | 293 |
240 // TODO(jarin) Enable this once we make sure everything with side effects | 294 // TODO(jarin) Enable this once we make sure everything with side effects |
241 // is marked as effectful. | 295 // is marked as effectful. |
242 if (false) { | 296 if (false) { |
243 return RemoveRegionNode(node); | 297 return RemoveRegionNode(node); |
244 } | 298 } |
245 } | 299 } |
246 | 300 |
| 301 if (node->opcode() == IrOpcode::kIfSuccess) { |
| 302 // We always schedule IfSuccess with its call, so skip it here. |
| 303 DCHECK_EQ(IrOpcode::kCall, node->InputAt(0)->opcode()); |
| 304 // The IfSuccess node should not belong to an exceptional call node |
| 305 // because such IfSuccess nodes should only start a basic block (and |
| 306 // basic block start nodes are not handled in the ProcessNode method). |
| 307 DCHECK(!NodeProperties::IsExceptionalCall(node->InputAt(0))); |
| 308 return; |
| 309 } |
| 310 |
247 // If the node takes an effect, replace with the current one. | 311 // If the node takes an effect, replace with the current one. |
248 if (node->op()->EffectInputCount() > 0) { | 312 if (node->op()->EffectInputCount() > 0) { |
249 DCHECK_EQ(1, node->op()->EffectInputCount()); | 313 DCHECK_EQ(1, node->op()->EffectInputCount()); |
250 Node* input_effect = NodeProperties::GetEffectInput(node); | 314 Node* input_effect = NodeProperties::GetEffectInput(node); |
251 | 315 |
252 if (input_effect != *effect) { | 316 if (input_effect != *effect) { |
253 NodeProperties::ReplaceEffectInput(node, *effect); | 317 NodeProperties::ReplaceEffectInput(node, *effect); |
254 } | 318 } |
255 | 319 |
256 // If the node produces an effect, update our current effect. (However, | 320 // If the node produces an effect, update our current effect. (However, |
257 // ignore new effect chains started with ValueEffect.) | 321 // ignore new effect chains started with ValueEffect.) |
258 if (node->op()->EffectOutputCount() > 0) { | 322 if (node->op()->EffectOutputCount() > 0) { |
259 DCHECK_EQ(1, node->op()->EffectOutputCount()); | 323 DCHECK_EQ(1, node->op()->EffectOutputCount()); |
260 *effect = node; | 324 *effect = node; |
261 } | 325 } |
262 } else { | 326 } else { |
263 // New effect chain is only started with a Start or ValueEffect node. | 327 // New effect chain is only started with a Start or ValueEffect node. |
264 DCHECK(node->op()->EffectOutputCount() == 0 || | 328 DCHECK(node->op()->EffectOutputCount() == 0 || |
265 node->opcode() == IrOpcode::kStart); | 329 node->opcode() == IrOpcode::kStart); |
266 } | 330 } |
| 331 // Rewire control inputs of control nodes, and update the current control |
| 332 // input. |
| 333 if (node->op()->ControlOutputCount() > 0) { |
| 334 DCHECK_EQ(1, node->op()->ControlInputCount()); |
| 335 NodeProperties::ReplaceControlInput(node, *control); |
| 336 *control = node; |
| 337 |
| 338 if (node->opcode() == IrOpcode::kCall) { |
| 339 // Schedule the call's IfSuccess node (if there is no exception use). |
| 340 TryScheduleCallIfSuccess(node, control); |
| 341 } |
| 342 } |
267 } | 343 } |
268 | 344 |
269 bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect, | 345 bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect, |
270 Node** control) { | 346 Node** control) { |
271 ValueEffectControl state(nullptr, nullptr, nullptr); | 347 ValueEffectControl state(nullptr, nullptr, nullptr); |
272 switch (node->opcode()) { | 348 switch (node->opcode()) { |
273 case IrOpcode::kChangeInt32ToTagged: | 349 case IrOpcode::kChangeInt32ToTagged: |
274 state = LowerChangeInt32ToTagged(node, *effect, *control); | 350 state = LowerChangeInt32ToTagged(node, *effect, *control); |
275 break; | 351 break; |
276 case IrOpcode::kChangeUint32ToTagged: | 352 case IrOpcode::kChangeUint32ToTagged: |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 return jsgraph()->Int32Constant(Smi::kMaxValue); | 533 return jsgraph()->Int32Constant(Smi::kMaxValue); |
458 } | 534 } |
459 | 535 |
460 Node* EffectControlLinearizer::SmiShiftBitsConstant() { | 536 Node* EffectControlLinearizer::SmiShiftBitsConstant() { |
461 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); | 537 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); |
462 } | 538 } |
463 | 539 |
464 } // namespace compiler | 540 } // namespace compiler |
465 } // namespace internal | 541 } // namespace internal |
466 } // namespace v8 | 542 } // namespace v8 |
OLD | NEW |