Index: src/compiler/effect-control-linearizer.cc |
diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc |
index ec21247bfc8c30d5b8a6efb5c794c5cd41e2c51f..1a484e0bbfb819b7d201db18c532a2b133b3b15e 100644 |
--- a/src/compiler/effect-control-linearizer.cc |
+++ b/src/compiler/effect-control-linearizer.cc |
@@ -34,8 +34,9 @@ MachineOperatorBuilder* EffectControlLinearizer::machine() const { |
namespace { |
-struct BlockEffectData { |
+struct BlockEffectControlData { |
Node* current_effect = nullptr; // New effect. |
+ Node* current_control = nullptr; // New control. |
}; |
// Effect phis that need to be updated after the first pass. |
@@ -48,7 +49,7 @@ struct PendingEffectPhi { |
}; |
void UpdateEffectPhi(Node* node, BasicBlock* block, |
- ZoneVector<BlockEffectData>* block_effects) { |
+ ZoneVector<BlockEffectControlData>* block_effects) { |
// Update all inputs to an effect phi with the effects from the given |
// block->effect map. |
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); |
@@ -64,6 +65,27 @@ void UpdateEffectPhi(Node* node, BasicBlock* block, |
} |
} |
+void UpdateBlockControl(BasicBlock* block, |
+ ZoneVector<BlockEffectControlData>* block_effects) { |
+ Node* control = block->NodeAt(0); |
+ DCHECK(NodeProperties::IsControl(control)); |
+ |
+ // Do not rewire the end node. |
+ if (control->opcode() == IrOpcode::kEnd) return; |
+ |
+ // Update all inputs to the given control node with the correct control. |
+ DCHECK_EQ(control->op()->ControlInputCount(), block->PredecessorCount()); |
+ for (int i = 0; i < control->op()->ControlInputCount(); i++) { |
+ Node* input = NodeProperties::GetControlInput(control, i); |
+ BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
+ Node* input_control = |
+ (*block_effects)[predecessor->rpo_number()].current_control; |
+ if (input != input_control) { |
+ NodeProperties::ReplaceControlInput(control, input_control, i); |
+ } |
+ } |
+} |
+ |
bool HasIncomingBackEdges(BasicBlock* block) { |
for (BasicBlock* pred : block->predecessors()) { |
if (pred->rpo_number() >= block->rpo_number()) { |
@@ -94,8 +116,9 @@ void RemoveRegionNode(Node* node) { |
} // namespace |
void EffectControlLinearizer::Run() { |
- ZoneVector<BlockEffectData> block_effects(temp_zone()); |
+ ZoneVector<BlockEffectControlData> block_effects(temp_zone()); |
ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); |
+ ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); |
block_effects.resize(schedule()->RpoBlockCount()); |
NodeVector inputs_buffer(temp_zone()); |
@@ -105,6 +128,16 @@ void EffectControlLinearizer::Run() { |
// The control node should be the first. |
Node* control = block->NodeAt(instr); |
DCHECK(NodeProperties::IsControl(control)); |
+ // Update the control inputs. |
+ if (HasIncomingBackEdges(block)) { |
+ // If there are back edges, we need to update later because we have not |
+ // computed the control yet. This should only happen for loops. |
+ DCHECK_EQ(IrOpcode::kLoop, control->opcode()); |
+ pending_block_controls.push_back(block); |
+ } else { |
+ // If there are no back edges, we can update now. |
+ UpdateBlockControl(block, &block_effects); |
+ } |
instr++; |
// Iterate over the phis and update the effect phis. |
@@ -177,8 +210,9 @@ void EffectControlLinearizer::Run() { |
pending_effect_phis.push_back(PendingEffectPhi(effect, block)); |
} else if (control->opcode() == IrOpcode::kIfException) { |
// The IfException is connected into the effect chain, so we need |
- // to process it here. |
- ProcessNode(control, &effect, &control); |
+ // to update the effect here. |
+ NodeProperties::ReplaceEffectInput(control, effect); |
+ effect = control; |
} |
} |
} |
@@ -212,6 +246,7 @@ void EffectControlLinearizer::Run() { |
// Store the effect for later use. |
block_effects[block->rpo_number()].current_effect = effect; |
+ block_effects[block->rpo_number()].current_control = control; |
} |
// Update the incoming edges of the effect phis that could not be processed |
@@ -220,8 +255,27 @@ void EffectControlLinearizer::Run() { |
UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, |
&block_effects); |
} |
+ for (BasicBlock* pending_block_control : pending_block_controls) { |
+ UpdateBlockControl(pending_block_control, &block_effects); |
+ } |
+} |
+ |
+namespace { |
+ |
+void TryScheduleCallIfSuccess(Node* node, Node** control) { |
+ // Schedule the call's IfSuccess node if there is no exception use. |
+ if (!NodeProperties::IsExceptionalCall(node)) { |
+ for (Edge edge : node->use_edges()) { |
+ if (NodeProperties::IsControlEdge(edge) && |
+ edge.from()->opcode() == IrOpcode::kIfSuccess) { |
+ *control = edge.from(); |
+ } |
+ } |
+ } |
} |
+} // namespace |
+ |
void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, |
Node** control) { |
// If the node needs to be wired into the effect/control chain, do this |
@@ -244,6 +298,16 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, |
} |
} |
+ if (node->opcode() == IrOpcode::kIfSuccess) { |
+ // We always schedule IfSuccess with its call, so skip it here. |
+ DCHECK_EQ(IrOpcode::kCall, node->InputAt(0)->opcode()); |
+ // The IfSuccess node should not belong to an exceptional call node |
+ // because such IfSuccess nodes should only start a basic block (and |
+ // basic block start nodes are not handled in the ProcessNode method). |
+ DCHECK(!NodeProperties::IsExceptionalCall(node->InputAt(0))); |
+ return; |
+ } |
+ |
// If the node takes an effect, replace with the current one. |
if (node->op()->EffectInputCount() > 0) { |
DCHECK_EQ(1, node->op()->EffectInputCount()); |
@@ -264,6 +328,18 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, |
DCHECK(node->op()->EffectOutputCount() == 0 || |
node->opcode() == IrOpcode::kStart); |
} |
+ // Rewire control inputs of control nodes, and update the current control |
+ // input. |
+ if (node->op()->ControlOutputCount() > 0) { |
+ DCHECK_EQ(1, node->op()->ControlInputCount()); |
+ NodeProperties::ReplaceControlInput(node, *control); |
+ *control = node; |
+ |
+ if (node->opcode() == IrOpcode::kCall) { |
+ // Schedule the call's IfSuccess node (if there is no exception use). |
+ TryScheduleCallIfSuccess(node, control); |
+ } |
+ } |
} |
bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect, |