| 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 |