Chromium Code Reviews| 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" |
| 11 #include "src/compiler/node-matchers.h" | |
| 11 #include "src/compiler/node-properties.h" | 12 #include "src/compiler/node-properties.h" |
| 12 #include "src/compiler/node.h" | 13 #include "src/compiler/node.h" |
| 13 #include "src/compiler/schedule.h" | 14 #include "src/compiler/schedule.h" |
| 14 | 15 |
| 15 namespace v8 { | 16 namespace v8 { |
| 16 namespace internal { | 17 namespace internal { |
| 17 namespace compiler { | 18 namespace compiler { |
| 18 | 19 |
| 19 EffectControlLinearizer::EffectControlLinearizer(JSGraph* js_graph, | 20 EffectControlLinearizer::EffectControlLinearizer(JSGraph* js_graph, |
| 20 Schedule* schedule, | 21 Schedule* schedule, |
| 21 Zone* temp_zone) | 22 Zone* temp_zone) |
| 22 : js_graph_(js_graph), schedule_(schedule), temp_zone_(temp_zone) {} | 23 : js_graph_(js_graph), schedule_(schedule), temp_zone_(temp_zone) {} |
| 23 | 24 |
| 24 Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); } | 25 Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); } |
| 25 CommonOperatorBuilder* EffectControlLinearizer::common() const { | 26 CommonOperatorBuilder* EffectControlLinearizer::common() const { |
| 26 return js_graph_->common(); | 27 return js_graph_->common(); |
| 27 } | 28 } |
| 28 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { | 29 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { |
| 29 return js_graph_->simplified(); | 30 return js_graph_->simplified(); |
| 30 } | 31 } |
| 31 MachineOperatorBuilder* EffectControlLinearizer::machine() const { | 32 MachineOperatorBuilder* EffectControlLinearizer::machine() const { |
| 32 return js_graph_->machine(); | 33 return js_graph_->machine(); |
| 33 } | 34 } |
| 34 | 35 |
| 35 namespace { | 36 namespace { |
| 36 | 37 |
| 37 struct BlockEffectControlData { | 38 struct BlockEffectControlData { |
| 38 Node* current_effect = nullptr; // New effect. | 39 Node* current_effect = nullptr; // New effect. |
| 39 Node* current_control = nullptr; // New control. | 40 Node* current_control = nullptr; // New control. |
| 40 Node* current_frame_state = nullptr; // New frame state. | 41 Node* current_frame_state = nullptr; // New frame state. |
| 41 }; | 42 }; |
| 42 | 43 |
| 44 struct BlockDataKey { | |
| 45 BasicBlock* from; | |
|
Benedikt Meurer
2016/07/12 03:16:14
How about using the rpo numbers as keys instead of
epertoso
2016/07/12 10:14:44
Done.
| |
| 46 BasicBlock* to; | |
| 47 | |
| 48 BlockDataKey(BasicBlock* from, BasicBlock* to) : from(from), to(to) {} | |
| 49 }; | |
| 50 | |
| 51 struct BlockDataKeyComparator { | |
| 52 bool operator()(const BlockDataKey& lhs, const BlockDataKey& rhs) const { | |
| 53 return lhs.from == rhs.from ? lhs.to < rhs.to : lhs.from < rhs.from; | |
| 54 } | |
| 55 }; | |
| 56 | |
| 57 using BlockEffectControlMap = | |
| 58 ZoneMap<BlockDataKey, BlockEffectControlData, BlockDataKeyComparator>; | |
| 59 | |
| 43 // Effect phis that need to be updated after the first pass. | 60 // Effect phis that need to be updated after the first pass. |
| 44 struct PendingEffectPhi { | 61 struct PendingEffectPhi { |
| 45 Node* effect_phi; | 62 Node* effect_phi; |
| 46 BasicBlock* block; | 63 BasicBlock* block; |
| 47 | 64 |
| 48 PendingEffectPhi(Node* effect_phi, BasicBlock* block) | 65 PendingEffectPhi(Node* effect_phi, BasicBlock* block) |
| 49 : effect_phi(effect_phi), block(block) {} | 66 : effect_phi(effect_phi), block(block) {} |
| 50 }; | 67 }; |
| 51 | 68 |
| 52 void UpdateEffectPhi(Node* node, BasicBlock* block, | 69 void UpdateEffectPhi(Node* node, BasicBlock* block, |
| 53 ZoneVector<BlockEffectControlData>* block_effects) { | 70 BlockEffectControlMap* block_effects) { |
| 54 // Update all inputs to an effect phi with the effects from the given | 71 // Update all inputs to an effect phi with the effects from the given |
| 55 // block->effect map. | 72 // block->effect map. |
| 56 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); | 73 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); |
| 57 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount()); | 74 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount()); |
| 58 for (int i = 0; i < node->op()->EffectInputCount(); i++) { | 75 for (int i = 0; i < node->op()->EffectInputCount(); i++) { |
| 59 Node* input = node->InputAt(i); | 76 Node* input = node->InputAt(i); |
| 60 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); | 77 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
| 61 Node* input_effect = | 78 BlockEffectControlMap::iterator it = |
| 62 (*block_effects)[predecessor->rpo_number()].current_effect; | 79 block_effects->find({predecessor, block}); |
|
Benedikt Meurer
2016/07/12 03:16:14
This kind of uniform initialization is not support
epertoso
2016/07/12 10:14:44
Explicitly using the constructor now.
| |
| 80 Node* input_effect = it->second.current_effect; | |
| 63 if (input != input_effect) { | 81 if (input != input_effect) { |
| 64 node->ReplaceInput(i, input_effect); | 82 node->ReplaceInput(i, input_effect); |
| 65 } | 83 } |
| 66 } | 84 } |
| 67 } | 85 } |
| 68 | 86 |
| 69 void UpdateBlockControl(BasicBlock* block, | 87 void UpdateBlockControl(BasicBlock* block, |
| 70 ZoneVector<BlockEffectControlData>* block_effects) { | 88 BlockEffectControlMap* block_effects) { |
| 71 Node* control = block->NodeAt(0); | 89 Node* control = block->NodeAt(0); |
| 72 DCHECK(NodeProperties::IsControl(control)); | 90 DCHECK(NodeProperties::IsControl(control)); |
| 73 | 91 |
| 74 // Do not rewire the end node. | 92 // Do not rewire the end node. |
| 75 if (control->opcode() == IrOpcode::kEnd) return; | 93 if (control->opcode() == IrOpcode::kEnd) return; |
| 76 | 94 |
| 77 // Update all inputs to the given control node with the correct control. | 95 // Update all inputs to the given control node with the correct control. |
| 78 DCHECK_EQ(control->op()->ControlInputCount(), block->PredecessorCount()); | 96 DCHECK(control->opcode() == IrOpcode::kMerge || |
| 97 control->op()->ControlInputCount() == block->PredecessorCount()); | |
| 98 if (control->op()->ControlInputCount() != block->PredecessorCount()) | |
| 99 return; // We already wired stuff. | |
|
Benedikt Meurer
2016/07/12 03:16:15
Nit: Add { } around the return
epertoso
2016/07/12 10:14:44
Done.
| |
| 79 for (int i = 0; i < control->op()->ControlInputCount(); i++) { | 100 for (int i = 0; i < control->op()->ControlInputCount(); i++) { |
| 80 Node* input = NodeProperties::GetControlInput(control, i); | 101 Node* input = NodeProperties::GetControlInput(control, i); |
| 81 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); | 102 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
| 82 Node* input_control = | 103 BlockEffectControlMap::iterator it = |
| 83 (*block_effects)[predecessor->rpo_number()].current_control; | 104 block_effects->find({predecessor, block}); |
| 105 Node* input_control = it->second.current_control; | |
| 84 if (input != input_control) { | 106 if (input != input_control) { |
| 85 NodeProperties::ReplaceControlInput(control, input_control, i); | 107 NodeProperties::ReplaceControlInput(control, input_control, i); |
| 86 } | 108 } |
| 87 } | 109 } |
| 88 } | 110 } |
| 89 | 111 |
| 90 bool HasIncomingBackEdges(BasicBlock* block) { | 112 bool HasIncomingBackEdges(BasicBlock* block) { |
| 91 for (BasicBlock* pred : block->predecessors()) { | 113 for (BasicBlock* pred : block->predecessors()) { |
| 92 if (pred->rpo_number() >= block->rpo_number()) { | 114 if (pred->rpo_number() >= block->rpo_number()) { |
| 93 return true; | 115 return true; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 107 edge.UpdateTo(NodeProperties::GetEffectInput(node)); | 129 edge.UpdateTo(NodeProperties::GetEffectInput(node)); |
| 108 } else { | 130 } else { |
| 109 DCHECK(!NodeProperties::IsControlEdge(edge)); | 131 DCHECK(!NodeProperties::IsControlEdge(edge)); |
| 110 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); | 132 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); |
| 111 edge.UpdateTo(node->InputAt(0)); | 133 edge.UpdateTo(node->InputAt(0)); |
| 112 } | 134 } |
| 113 } | 135 } |
| 114 node->Kill(); | 136 node->Kill(); |
| 115 } | 137 } |
| 116 | 138 |
| 139 void TryCloneBranch(Node* node, BasicBlock* block, Graph* graph, | |
| 140 CommonOperatorBuilder* common, | |
| 141 BlockEffectControlMap* block_effects) { | |
| 142 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | |
| 143 | |
| 144 // This optimization is a special case of (super)block cloning. It takes an | |
| 145 // input graph as shown below and clones the Branch node for every predecessor | |
| 146 // to the Merge, essentially removing the Merge completely. This avoids | |
| 147 // materializing the bit for the Phi and may offer potential for further | |
| 148 // branch folding optimizations (i.e. because one or more inputs to the Phi is | |
| 149 // a constant). Note that there may be more Phi nodes hanging off the Merge, | |
| 150 // but we can only a certain subset of them currently (actually only Phi and | |
| 151 // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control | |
| 152 // input). | |
| 153 | |
| 154 // Control1 ... ControlN | |
| 155 // ^ ^ | |
| 156 // | | Cond1 ... CondN | |
| 157 // +----+ +----+ ^ ^ | |
| 158 // | | | | | |
| 159 // | | +----+ | | |
| 160 // Merge<--+ | +------------+ | |
| 161 // ^ \|/ | |
| 162 // | Phi | |
| 163 // | | | |
| 164 // Branch----+ | |
| 165 // ^ | |
| 166 // | | |
| 167 // +-----+-----+ | |
| 168 // | | | |
| 169 // IfTrue IfFalse | |
| 170 // ^ ^ | |
| 171 // | | | |
| 172 | |
| 173 // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: | |
| 174 | |
| 175 // Control1 Cond1 ... ControlN CondN | |
| 176 // ^ ^ ^ ^ | |
| 177 // \ / \ / | |
| 178 // Branch ... Branch | |
| 179 // ^ ^ | |
| 180 // | | | |
| 181 // +---+---+ +---+----+ | |
| 182 // | | | | | |
| 183 // IfTrue IfFalse ... IfTrue IfFalse | |
| 184 // ^ ^ ^ ^ | |
| 185 // | | | | | |
| 186 // +--+ +-------------+ | | |
| 187 // | | +--------------+ +--+ | |
| 188 // | | | | | |
| 189 // Merge Merge | |
| 190 // ^ ^ | |
| 191 // | | | |
| 192 | |
| 193 Node* branch = node; | |
| 194 Node* cond = NodeProperties::GetValueInput(branch, 0); | |
| 195 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return; | |
| 196 Node* merge = NodeProperties::GetControlInput(branch); | |
| 197 if (merge->opcode() != IrOpcode::kMerge || | |
| 198 NodeProperties::GetControlInput(cond) != merge) { | |
| 199 return; | |
| 200 } | |
| 201 // Grab the IfTrue/IfFalse projections of the Branch. | |
| 202 BranchMatcher matcher(branch); | |
| 203 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. | |
| 204 NodeVector phis(graph->zone()); | |
| 205 for (Node* const use : merge->uses()) { | |
| 206 if (use == branch || use == cond) continue; | |
| 207 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the | |
| 208 // Merge. Ideally, we would just clone the nodes (and everything that | |
| 209 // depends on it to some distant join point), but that requires knowledge | |
| 210 // about dominance/post-dominance. | |
| 211 if (!NodeProperties::IsPhi(use)) return; | |
| 212 for (Edge edge : use->use_edges()) { | |
| 213 // Right now we can only handle Phi/EffectPhi nodes whose uses are | |
| 214 // directly control-dependend on either the IfTrue or the IfFalse | |
| 215 // successor, because we know exactly how to update those uses. | |
| 216 if (edge.from()->op()->ControlInputCount() != 1) return; | |
| 217 Node* control = NodeProperties::GetControlInput(edge.from()); | |
| 218 if (NodeProperties::IsPhi(edge.from())) { | |
| 219 control = NodeProperties::GetControlInput(control, edge.index()); | |
| 220 } | |
| 221 if (control != matcher.IfTrue() && control != matcher.IfFalse()) return; | |
| 222 } | |
| 223 phis.push_back(use); | |
| 224 } | |
| 225 BranchHint const hint = BranchHintOf(branch->op()); | |
| 226 int const input_count = merge->op()->ControlInputCount(); | |
| 227 DCHECK_LE(1, input_count); | |
| 228 Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count); | |
| 229 Node** const merge_true_inputs = &inputs[0]; | |
| 230 Node** const merge_false_inputs = &inputs[input_count]; | |
| 231 for (int index = 0; index < input_count; ++index) { | |
| 232 Node* cond1 = NodeProperties::GetValueInput(cond, index); | |
| 233 Node* control1 = NodeProperties::GetControlInput(merge, index); | |
| 234 Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1); | |
| 235 merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1); | |
| 236 merge_false_inputs[index] = graph->NewNode(common->IfFalse(), branch1); | |
| 237 } | |
| 238 Node* const merge_true = matcher.IfTrue(); | |
| 239 Node* const merge_false = matcher.IfFalse(); | |
| 240 merge_true->TrimInputCount(0); | |
| 241 merge_false->TrimInputCount(0); | |
| 242 for (int i = 0; i < input_count; ++i) { | |
| 243 merge_true->AppendInput(graph->zone(), merge_true_inputs[i]); | |
| 244 merge_false->AppendInput(graph->zone(), merge_false_inputs[i]); | |
| 245 } | |
| 246 DCHECK_EQ(2, block->SuccessorCount()); | |
| 247 NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count)); | |
| 248 NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count)); | |
| 249 int const true_index = | |
| 250 block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1; | |
| 251 BlockEffectControlData* true_block_data = | |
| 252 &(*block_effects)[{block, block->SuccessorAt(true_index)}]; | |
| 253 BlockEffectControlData* false_block_data = | |
| 254 &(*block_effects)[{block, block->SuccessorAt(true_index ^ 1)}]; | |
| 255 for (Node* const phi : phis) { | |
| 256 for (int index = 0; index < input_count; ++index) { | |
| 257 inputs[index] = phi->InputAt(index); | |
| 258 } | |
| 259 inputs[input_count] = merge_true; | |
| 260 Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs); | |
| 261 inputs[input_count] = merge_false; | |
| 262 Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs); | |
| 263 if (phi->UseCount() == 0) { | |
| 264 DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi); | |
| 265 DCHECK_EQ(input_count, block->SuccessorCount()); | |
| 266 } else { | |
| 267 for (Edge edge : phi->use_edges()) { | |
| 268 Node* control = NodeProperties::GetControlInput(edge.from()); | |
| 269 if (NodeProperties::IsPhi(edge.from())) { | |
| 270 control = NodeProperties::GetControlInput(control, edge.index()); | |
| 271 } | |
| 272 DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); | |
| 273 edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); | |
| 274 } | |
| 275 } | |
| 276 true_block_data->current_effect = phi_true; | |
| 277 false_block_data->current_effect = phi_false; | |
| 278 phi->Kill(); | |
| 279 } | |
| 280 // Fix up IfTrue and IfFalse and kill all dead nodes. | |
| 281 if (branch == block->control_input()) { | |
| 282 true_block_data->current_control = merge_true; | |
| 283 false_block_data->current_control = merge_false; | |
| 284 } | |
| 285 branch->Kill(); | |
| 286 cond->Kill(); | |
| 287 merge->Kill(); | |
| 288 } | |
| 117 } // namespace | 289 } // namespace |
| 118 | 290 |
| 119 void EffectControlLinearizer::Run() { | 291 void EffectControlLinearizer::Run() { |
| 120 ZoneVector<BlockEffectControlData> block_effects(temp_zone()); | 292 BlockEffectControlMap block_effects(temp_zone()); |
| 121 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); | 293 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); |
| 122 ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); | 294 ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); |
| 123 block_effects.resize(schedule()->RpoBlockCount()); | |
| 124 NodeVector inputs_buffer(temp_zone()); | 295 NodeVector inputs_buffer(temp_zone()); |
| 125 | 296 |
| 126 for (BasicBlock* block : *(schedule()->rpo_order())) { | 297 for (BasicBlock* block : *(schedule()->rpo_order())) { |
| 298 for (BasicBlock* successor : block->successors()) { | |
| 299 block_effects[{block, successor}] = BlockEffectControlData(); | |
| 300 } | |
| 127 size_t instr = 0; | 301 size_t instr = 0; |
| 128 | 302 |
| 129 // The control node should be the first. | 303 // The control node should be the first. |
| 130 Node* control = block->NodeAt(instr); | 304 Node* control = block->NodeAt(instr); |
| 131 DCHECK(NodeProperties::IsControl(control)); | 305 DCHECK(NodeProperties::IsControl(control)); |
| 132 // Update the control inputs. | 306 // Update the control inputs. |
| 133 if (HasIncomingBackEdges(block)) { | 307 if (HasIncomingBackEdges(block)) { |
| 134 // If there are back edges, we need to update later because we have not | 308 // If there are back edges, we need to update later because we have not |
| 135 // computed the control yet. This should only happen for loops. | 309 // computed the control yet. This should only happen for loops. |
| 136 DCHECK_EQ(IrOpcode::kLoop, control->opcode()); | 310 DCHECK_EQ(IrOpcode::kLoop, control->opcode()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 if (block == schedule()->start()) { | 353 if (block == schedule()->start()) { |
| 180 // Start block => effect is start. | 354 // Start block => effect is start. |
| 181 DCHECK_EQ(graph()->start(), control); | 355 DCHECK_EQ(graph()->start(), control); |
| 182 effect = graph()->start(); | 356 effect = graph()->start(); |
| 183 } else if (control->opcode() == IrOpcode::kEnd) { | 357 } else if (control->opcode() == IrOpcode::kEnd) { |
| 184 // End block is just a dummy, no effect needed. | 358 // End block is just a dummy, no effect needed. |
| 185 DCHECK_EQ(BasicBlock::kNone, block->control()); | 359 DCHECK_EQ(BasicBlock::kNone, block->control()); |
| 186 DCHECK_EQ(1u, block->size()); | 360 DCHECK_EQ(1u, block->size()); |
| 187 effect = nullptr; | 361 effect = nullptr; |
| 188 } else { | 362 } else { |
| 189 // If all the predecessors have the same effect, we can use it | 363 // If all the predecessors have the same effect, we can use it as our |
| 190 // as our current effect. | 364 // current effect. |
| 191 int rpo_number = block->PredecessorAt(0)->rpo_number(); | 365 effect = block_effects[{block->PredecessorAt(0), block}].current_effect; |
| 192 effect = block_effects[rpo_number].current_effect; | 366 for (size_t i = 1; i < block->PredecessorCount(); ++i) { |
| 193 for (size_t i = 1; i < block->PredecessorCount(); i++) { | 367 if (block_effects[{block->PredecessorAt(i), block}].current_effect != |
| 194 int rpo_number = block->PredecessorAt(i)->rpo_number(); | 368 effect) { |
| 195 if (block_effects[rpo_number].current_effect != effect) { | |
| 196 effect = nullptr; | 369 effect = nullptr; |
| 197 break; | 370 break; |
| 198 } | 371 } |
| 199 } | 372 } |
| 200 if (effect == nullptr) { | 373 if (effect == nullptr) { |
| 201 DCHECK_NE(IrOpcode::kIfException, control->opcode()); | 374 DCHECK_NE(IrOpcode::kIfException, control->opcode()); |
| 202 // The input blocks do not have the same effect. We have | 375 // The input blocks do not have the same effect. We have |
| 203 // to create an effect phi node. | 376 // to create an effect phi node. |
| 204 inputs_buffer.clear(); | 377 inputs_buffer.clear(); |
| 205 inputs_buffer.resize(block->PredecessorCount(), graph()->start()); | 378 inputs_buffer.resize(block->PredecessorCount(), graph()->start()); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 225 | 398 |
| 226 // The frame state at block entry is determined by the frame states leaving | 399 // The frame state at block entry is determined by the frame states leaving |
| 227 // all predecessors. In case there is no frame state dominating this block, | 400 // all predecessors. In case there is no frame state dominating this block, |
| 228 // we can rely on a checkpoint being present before the next deoptimization. | 401 // we can rely on a checkpoint being present before the next deoptimization. |
| 229 // TODO(mstarzinger): Eventually we will need to go hunt for a frame state | 402 // TODO(mstarzinger): Eventually we will need to go hunt for a frame state |
| 230 // once deoptimizing nodes roam freely through the schedule. | 403 // once deoptimizing nodes roam freely through the schedule. |
| 231 Node* frame_state = nullptr; | 404 Node* frame_state = nullptr; |
| 232 if (block != schedule()->start()) { | 405 if (block != schedule()->start()) { |
| 233 // If all the predecessors have the same effect, we can use it | 406 // If all the predecessors have the same effect, we can use it |
| 234 // as our current effect. | 407 // as our current effect. |
| 235 int rpo_number = block->PredecessorAt(0)->rpo_number(); | 408 frame_state = |
| 236 frame_state = block_effects[rpo_number].current_frame_state; | 409 block_effects[{block->PredecessorAt(0), block}].current_frame_state; |
| 237 for (size_t i = 1; i < block->PredecessorCount(); i++) { | 410 for (size_t i = 1; i < block->PredecessorCount(); i++) { |
| 238 int rpo_number = block->PredecessorAt(i)->rpo_number(); | 411 if (block_effects[{block->PredecessorAt(i), block}] |
| 239 if (block_effects[rpo_number].current_frame_state != frame_state) { | 412 .current_frame_state != frame_state) { |
| 240 frame_state = nullptr; | 413 frame_state = nullptr; |
| 241 break; | 414 break; |
| 242 } | 415 } |
| 243 } | 416 } |
| 244 } | 417 } |
| 245 | 418 |
| 246 // Process the ordinary instructions. | 419 // Process the ordinary instructions. |
| 247 for (; instr < block->NodeCount(); instr++) { | 420 for (; instr < block->NodeCount(); instr++) { |
| 248 Node* node = block->NodeAt(instr); | 421 Node* node = block->NodeAt(instr); |
| 249 ProcessNode(node, &frame_state, &effect, &control); | 422 ProcessNode(node, &frame_state, &effect, &control); |
| 250 } | 423 } |
| 251 | 424 |
| 252 switch (block->control()) { | 425 switch (block->control()) { |
| 253 case BasicBlock::kGoto: | 426 case BasicBlock::kGoto: |
| 254 case BasicBlock::kNone: | 427 case BasicBlock::kNone: |
| 255 break; | 428 break; |
| 256 | 429 |
| 257 case BasicBlock::kCall: | 430 case BasicBlock::kCall: |
| 258 case BasicBlock::kTailCall: | 431 case BasicBlock::kTailCall: |
| 259 case BasicBlock::kBranch: | 432 case BasicBlock::kBranch: |
| 260 case BasicBlock::kSwitch: | 433 case BasicBlock::kSwitch: |
| 261 case BasicBlock::kReturn: | 434 case BasicBlock::kReturn: |
| 262 case BasicBlock::kDeoptimize: | 435 case BasicBlock::kDeoptimize: |
| 263 case BasicBlock::kThrow: | 436 case BasicBlock::kThrow: { |
| 264 ProcessNode(block->control_input(), &frame_state, &effect, &control); | 437 ProcessNode(block->control_input(), &frame_state, &effect, &control); |
| 265 break; | 438 if (block->control() == BasicBlock::kBranch) { |
| 439 TryCloneBranch(block->control_input(), block, graph(), common(), | |
| 440 &block_effects); | |
| 441 } | |
| 442 } break; | |
| 266 } | 443 } |
| 267 | 444 |
| 268 // Store the effect for later use. | 445 // Store the effect, control and frame state for later use. |
| 269 block_effects[block->rpo_number()].current_effect = effect; | 446 for (BasicBlock* successor : block->successors()) { |
| 270 block_effects[block->rpo_number()].current_control = control; | 447 BlockEffectControlData& data = block_effects[{block, successor}]; |
| 271 block_effects[block->rpo_number()].current_frame_state = frame_state; | 448 if (data.current_effect == nullptr) { |
| 449 data.current_effect = effect; | |
| 450 } | |
| 451 if (data.current_control == nullptr) { | |
| 452 data.current_control = control; | |
| 453 } | |
| 454 data.current_frame_state = frame_state; | |
| 455 } | |
| 272 } | 456 } |
| 273 | 457 |
| 274 // Update the incoming edges of the effect phis that could not be processed | 458 // Update the incoming edges of the effect phis that could not be processed |
| 275 // during the first pass (because they could have incoming back edges). | 459 // during the first pass (because they could have incoming back edges). |
| 276 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { | 460 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { |
| 277 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, | 461 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, |
| 278 &block_effects); | 462 &block_effects); |
| 279 } | 463 } |
| 280 for (BasicBlock* pending_block_control : pending_block_controls) { | 464 for (BasicBlock* pending_block_control : pending_block_controls) { |
| 281 UpdateBlockControl(pending_block_control, &block_effects); | 465 UpdateBlockControl(pending_block_control, &block_effects); |
| (...skipping 1586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1868 isolate(), graph()->zone(), callable.descriptor(), 0, flags, | 2052 isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
| 1869 Operator::kNoThrow); | 2053 Operator::kNoThrow); |
| 1870 to_number_operator_.set(common()->Call(desc)); | 2054 to_number_operator_.set(common()->Call(desc)); |
| 1871 } | 2055 } |
| 1872 return to_number_operator_.get(); | 2056 return to_number_operator_.get(); |
| 1873 } | 2057 } |
| 1874 | 2058 |
| 1875 } // namespace compiler | 2059 } // namespace compiler |
| 1876 } // namespace internal | 2060 } // namespace internal |
| 1877 } // namespace v8 | 2061 } // namespace v8 |
| OLD | NEW |