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/control-flow-optimizer.h" | 5 #include "src/compiler/control-flow-optimizer.h" |
6 | 6 |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/graph.h" | 8 #include "src/compiler/graph.h" |
9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 if (NodeProperties::IsControlEdge(edge)) { | 56 if (NodeProperties::IsControlEdge(edge)) { |
57 Enqueue(edge.from()); | 57 Enqueue(edge.from()); |
58 } | 58 } |
59 } | 59 } |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 void ControlFlowOptimizer::VisitBranch(Node* node) { | 63 void ControlFlowOptimizer::VisitBranch(Node* node) { |
64 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 64 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
65 if (TryBuildSwitch(node)) return; | 65 if (TryBuildSwitch(node)) return; |
66 if (TryCloneBranch(node)) return; | |
67 VisitNode(node); | 66 VisitNode(node); |
68 } | 67 } |
69 | 68 |
70 | 69 |
71 bool ControlFlowOptimizer::TryCloneBranch(Node* node) { | |
72 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | |
73 | |
74 // This optimization is a special case of (super)block cloning. It takes an | |
75 // input graph as shown below and clones the Branch node for every predecessor | |
76 // to the Merge, essentially removing the Merge completely. This avoids | |
77 // materializing the bit for the Phi and may offer potential for further | |
78 // branch folding optimizations (i.e. because one or more inputs to the Phi is | |
79 // a constant). Note that there may be more Phi nodes hanging off the Merge, | |
80 // but we can only a certain subset of them currently (actually only Phi and | |
81 // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control | |
82 // input). | |
83 | |
84 // Control1 ... ControlN | |
85 // ^ ^ | |
86 // | | Cond1 ... CondN | |
87 // +----+ +----+ ^ ^ | |
88 // | | | | | |
89 // | | +----+ | | |
90 // Merge<--+ | +------------+ | |
91 // ^ \|/ | |
92 // | Phi | |
93 // | | | |
94 // Branch----+ | |
95 // ^ | |
96 // | | |
97 // +-----+-----+ | |
98 // | | | |
99 // IfTrue IfFalse | |
100 // ^ ^ | |
101 // | | | |
102 | |
103 // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: | |
104 | |
105 // Control1 Cond1 ... ControlN CondN | |
106 // ^ ^ ^ ^ | |
107 // \ / \ / | |
108 // Branch ... Branch | |
109 // ^ ^ | |
110 // | | | |
111 // +---+---+ +---+----+ | |
112 // | | | | | |
113 // IfTrue IfFalse ... IfTrue IfFalse | |
114 // ^ ^ ^ ^ | |
115 // | | | | | |
116 // +--+ +-------------+ | | |
117 // | | +--------------+ +--+ | |
118 // | | | | | |
119 // Merge Merge | |
120 // ^ ^ | |
121 // | | | |
122 | |
123 Node* branch = node; | |
124 Node* cond = NodeProperties::GetValueInput(branch, 0); | |
125 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false; | |
126 Node* merge = NodeProperties::GetControlInput(branch); | |
127 if (merge->opcode() != IrOpcode::kMerge || | |
128 NodeProperties::GetControlInput(cond) != merge) { | |
129 return false; | |
130 } | |
131 // Grab the IfTrue/IfFalse projections of the Branch. | |
132 BranchMatcher matcher(branch); | |
133 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. | |
134 NodeVector phis(zone()); | |
135 for (Node* const use : merge->uses()) { | |
136 if (use == branch || use == cond) continue; | |
137 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the | |
138 // Merge. Ideally, we would just clone the nodes (and everything that | |
139 // depends on it to some distant join point), but that requires knowledge | |
140 // about dominance/post-dominance. | |
141 if (!NodeProperties::IsPhi(use)) return false; | |
142 for (Edge edge : use->use_edges()) { | |
143 // Right now we can only handle Phi/EffectPhi nodes whose uses are | |
144 // directly control-dependend on either the IfTrue or the IfFalse | |
145 // successor, because we know exactly how to update those uses. | |
146 // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using | |
147 // dominance/post-dominance on the sea of nodes. | |
148 if (edge.from()->op()->ControlInputCount() != 1) return false; | |
149 Node* control = NodeProperties::GetControlInput(edge.from()); | |
150 if (NodeProperties::IsPhi(edge.from())) { | |
151 control = NodeProperties::GetControlInput(control, edge.index()); | |
152 } | |
153 if (control != matcher.IfTrue() && control != matcher.IfFalse()) | |
154 return false; | |
155 } | |
156 phis.push_back(use); | |
157 } | |
158 BranchHint const hint = BranchHintOf(branch->op()); | |
159 int const input_count = merge->op()->ControlInputCount(); | |
160 DCHECK_LE(1, input_count); | |
161 Node** const inputs = zone()->NewArray<Node*>(2 * input_count); | |
162 Node** const merge_true_inputs = &inputs[0]; | |
163 Node** const merge_false_inputs = &inputs[input_count]; | |
164 for (int index = 0; index < input_count; ++index) { | |
165 Node* cond1 = NodeProperties::GetValueInput(cond, index); | |
166 Node* control1 = NodeProperties::GetControlInput(merge, index); | |
167 Node* branch1 = graph()->NewNode(common()->Branch(hint), cond1, control1); | |
168 merge_true_inputs[index] = graph()->NewNode(common()->IfTrue(), branch1); | |
169 merge_false_inputs[index] = graph()->NewNode(common()->IfFalse(), branch1); | |
170 Enqueue(branch1); | |
171 } | |
172 Node* const merge_true = graph()->NewNode(common()->Merge(input_count), | |
173 input_count, merge_true_inputs); | |
174 Node* const merge_false = graph()->NewNode(common()->Merge(input_count), | |
175 input_count, merge_false_inputs); | |
176 for (Node* const phi : phis) { | |
177 for (int index = 0; index < input_count; ++index) { | |
178 inputs[index] = phi->InputAt(index); | |
179 } | |
180 inputs[input_count] = merge_true; | |
181 Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs); | |
182 inputs[input_count] = merge_false; | |
183 Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs); | |
184 for (Edge edge : phi->use_edges()) { | |
185 Node* control = NodeProperties::GetControlInput(edge.from()); | |
186 if (NodeProperties::IsPhi(edge.from())) { | |
187 control = NodeProperties::GetControlInput(control, edge.index()); | |
188 } | |
189 DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); | |
190 edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); | |
191 } | |
192 phi->Kill(); | |
193 } | |
194 // Fix up IfTrue and IfFalse and kill all dead nodes. | |
195 matcher.IfFalse()->ReplaceUses(merge_false); | |
196 matcher.IfTrue()->ReplaceUses(merge_true); | |
197 matcher.IfFalse()->Kill(); | |
198 matcher.IfTrue()->Kill(); | |
199 branch->Kill(); | |
200 cond->Kill(); | |
201 merge->Kill(); | |
202 return true; | |
203 } | |
204 | |
205 | |
206 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { | 70 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { |
207 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 71 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
208 | 72 |
209 Node* branch = node; | 73 Node* branch = node; |
210 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; | 74 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; |
211 Node* cond = NodeProperties::GetValueInput(branch, 0); | 75 Node* cond = NodeProperties::GetValueInput(branch, 0); |
212 if (cond->opcode() != IrOpcode::kWord32Equal) return false; | 76 if (cond->opcode() != IrOpcode::kWord32Equal) return false; |
213 Int32BinopMatcher m(cond); | 77 Int32BinopMatcher m(cond); |
214 Node* index = m.left().node(); | 78 Node* index = m.left().node(); |
215 if (!m.right().HasValue()) return false; | 79 if (!m.right().HasValue()) return false; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 if_false->ReplaceInput(0, node); | 133 if_false->ReplaceInput(0, node); |
270 NodeProperties::ChangeOp(if_false, common()->IfDefault()); | 134 NodeProperties::ChangeOp(if_false, common()->IfDefault()); |
271 Enqueue(if_false); | 135 Enqueue(if_false); |
272 branch->NullAllInputs(); | 136 branch->NullAllInputs(); |
273 return true; | 137 return true; |
274 } | 138 } |
275 | 139 |
276 } // namespace compiler | 140 } // namespace compiler |
277 } // namespace internal | 141 } // namespace internal |
278 } // namespace v8 | 142 } // namespace v8 |
OLD | NEW |