Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: src/compiler/control-flow-optimizer.cc

Issue 947963002: [turbofan] Initial version of branch cloning. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Tests and documentation. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/control-flow-optimizer.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/js-graph.h" 7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/node-matchers.h" 8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/node-properties.h" 9 #include "src/compiler/node-properties.h"
10 10
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 47
48 void ControlFlowOptimizer::VisitNode(Node* node) { 48 void ControlFlowOptimizer::VisitNode(Node* node) {
49 for (Node* use : node->uses()) { 49 for (Node* use : node->uses()) {
50 if (NodeProperties::IsControl(use)) Enqueue(use); 50 if (NodeProperties::IsControl(use)) Enqueue(use);
51 } 51 }
52 } 52 }
53 53
54 54
55 void ControlFlowOptimizer::VisitBranch(Node* node) { 55 void ControlFlowOptimizer::VisitBranch(Node* node) {
56 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 56 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
57 if (TryBuildSwitch(node)) return;
58 if (TryCloneBranch(node)) return;
59 VisitNode(node);
60 }
61
62
63 bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
64 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
65
66 // This optimization is a special case of (super)block cloning. It takes an
67 // input graph as shown below and clones the Branch node for every predecessor
68 // to the Merge, essentially removing the Merge completely. This avoids
69 // materializing the bit for the Phi and may offer potential for further
70 // branch folding optimizations (i.e. because one or more inputs to the Phi is
71 // a constant). Note that there may be more Phi nodes hanging off the Merge,
72 // but we can only a certain subset of them currently (actually only Phi and
73 // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control
74 // input).
75
76 // Control1 ... ControlN
77 // ^ ^
78 // | | Cond1 ... CondN
79 // +----+ +----+ ^ ^
80 // | | | |
81 // | | +----+ |
82 // Merge<--+ | +------------+
83 // ^ \|/
84 // | Phi
85 // | |
86 // Branch----+
87 // ^
88 // |
89 // +-----+-----+
90 // | |
91 // IfTrue IfFalse
92 // ^ ^
93 // | |
94
95 // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this:
96
97 // Control1 Cond1 ... ControlN CondN
98 // ^ ^ ^ ^
99 // \ / \ /
100 // Branch ... Branch
101 // ^ ^
102 // | |
103 // +---+---+ +---+----+
104 // | | | |
105 // IfTrue IfFalse ... IfTrue IfFalse
106 // ^ ^ ^ ^
107 // | | | |
108 // +--+ +-------------+ |
109 // | | +--------------+ +--+
110 // | | | |
111 // Merge Merge
112 // ^ ^
113 // | |
114
115 Node* branch = node;
116 Node* cond = NodeProperties::GetValueInput(branch, 0);
117 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false;
118 Node* merge = NodeProperties::GetControlInput(branch);
119 if (merge->opcode() != IrOpcode::kMerge ||
120 NodeProperties::GetControlInput(cond) != merge) {
121 return false;
122 }
123 // Grab the IfTrue/IfFalse projections of the Branch.
124 Node* control_projections[2];
125 NodeProperties::CollectControlProjections(branch, control_projections,
126 arraysize(control_projections));
127 Node* if_true = control_projections[0];
128 Node* if_false = control_projections[1];
129 DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
130 DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
131 // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
132 NodeVector phis(zone());
133 for (Node* const use : merge->uses()) {
134 if (use == branch || use == cond) continue;
135 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the
136 // Merge. Ideally, we would just clone the nodes (and everything that
137 // depends on it to some distant join point), but that requires knowledge
138 // about dominance/post-dominance.
139 if (!NodeProperties::IsPhi(use)) return false;
140 for (Edge edge : use->use_edges()) {
141 // Right now we can only handle Phi/EffectPhi nodes whose uses are
142 // directly control-dependend on either the IfTrue or the IfFalse
143 // successor, because we know exactly how to update those uses.
144 // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using
145 // dominance/post-dominance on the sea of nodes.
146 if (edge.from()->op()->ControlInputCount() != 1) return false;
147 Node* control = NodeProperties::GetControlInput(edge.from());
148 if (NodeProperties::IsPhi(edge.from())) {
149 control = NodeProperties::GetControlInput(control, edge.index());
150 }
151 if (control != if_true && control != if_false) return false;
152 }
153 phis.push_back(use);
154 }
155 BranchHint const hint = BranchHintOf(branch->op());
156 int const input_count = merge->op()->ControlInputCount();
157 DCHECK_LE(1, input_count);
158 Node** const inputs = zone()->NewArray<Node*>(2 * input_count);
159 Node** const merge_true_inputs = &inputs[0];
160 Node** const merge_false_inputs = &inputs[input_count];
161 for (int index = 0; index < input_count; ++index) {
162 Node* cond1 = NodeProperties::GetValueInput(cond, index);
163 Node* control1 = NodeProperties::GetControlInput(merge, index);
164 Node* branch1 = graph()->NewNode(common()->Branch(hint), cond1, control1);
165 merge_true_inputs[index] = graph()->NewNode(common()->IfTrue(), branch1);
166 merge_false_inputs[index] = graph()->NewNode(common()->IfFalse(), branch1);
167 Enqueue(branch1);
168 }
169 Node* const merge_true = graph()->NewNode(common()->Merge(input_count),
170 input_count, merge_true_inputs);
171 Node* const merge_false = graph()->NewNode(common()->Merge(input_count),
172 input_count, merge_false_inputs);
173 for (Node* const phi : phis) {
174 for (int index = 0; index < input_count; ++index) {
175 inputs[index] = phi->InputAt(index);
176 }
177 inputs[input_count] = merge_true;
178 Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs);
179 inputs[input_count] = merge_false;
180 Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs);
181 for (Edge edge : phi->use_edges()) {
182 Node* control = NodeProperties::GetControlInput(edge.from());
183 if (NodeProperties::IsPhi(edge.from())) {
184 control = NodeProperties::GetControlInput(control, edge.index());
185 }
186 DCHECK(control == if_true || control == if_false);
187 edge.UpdateTo((control == if_true) ? phi_true : phi_false);
188 }
189 phi->Kill();
190 }
191 // Fix up IfTrue and IfFalse and kill all dead nodes.
192 if_false->ReplaceUses(merge_false);
193 if_true->ReplaceUses(merge_true);
194 if_false->Kill();
195 if_true->Kill();
196 branch->Kill();
197 cond->Kill();
198 merge->Kill();
199 return true;
200 }
201
202
203 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
204 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
57 205
58 Node* branch = node; 206 Node* branch = node;
59 Node* cond = NodeProperties::GetValueInput(branch, 0); 207 Node* cond = NodeProperties::GetValueInput(branch, 0);
60 if (cond->opcode() != IrOpcode::kWord32Equal) return VisitNode(node); 208 if (cond->opcode() != IrOpcode::kWord32Equal) return false;
61 Int32BinopMatcher m(cond); 209 Int32BinopMatcher m(cond);
62 Node* index = m.left().node(); 210 Node* index = m.left().node();
63 if (!m.right().HasValue()) return VisitNode(node); 211 if (!m.right().HasValue()) return false;
64 int32_t value = m.right().Value(); 212 int32_t value = m.right().Value();
65 ZoneSet<int32_t> values(zone()); 213 ZoneSet<int32_t> values(zone());
66 values.insert(value); 214 values.insert(value);
67 215
68 Node* if_false; 216 Node* if_false;
69 Node* if_true; 217 Node* if_true;
70 while (true) { 218 while (true) {
71 Node* control_projections[2]; 219 Node* control_projections[2];
72 NodeProperties::CollectControlProjections(branch, control_projections, 2); 220 NodeProperties::CollectControlProjections(branch, control_projections, 2);
73 if_true = control_projections[0]; 221 if_true = control_projections[0];
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 node->set_op(common()->Switch(values.size() + 1)); 263 node->set_op(common()->Switch(values.size() + 1));
116 node->ReplaceInput(0, index); 264 node->ReplaceInput(0, index);
117 if_true->set_op(common()->IfValue(value)); 265 if_true->set_op(common()->IfValue(value));
118 if_true->ReplaceInput(0, node); 266 if_true->ReplaceInput(0, node);
119 Enqueue(if_true); 267 Enqueue(if_true);
120 if_false->set_op(common()->IfDefault()); 268 if_false->set_op(common()->IfDefault());
121 if_false->ReplaceInput(0, node); 269 if_false->ReplaceInput(0, node);
122 Enqueue(if_false); 270 Enqueue(if_false);
123 branch->RemoveAllInputs(); 271 branch->RemoveAllInputs();
124 } 272 }
273 return true;
125 } 274 }
126 275
127 276
128 CommonOperatorBuilder* ControlFlowOptimizer::common() const { 277 CommonOperatorBuilder* ControlFlowOptimizer::common() const {
129 return jsgraph()->common(); 278 return jsgraph()->common();
130 } 279 }
131 280
132 281
133 Graph* ControlFlowOptimizer::graph() const { return jsgraph()->graph(); } 282 Graph* ControlFlowOptimizer::graph() const { return jsgraph()->graph(); }
134 283
135 284
136 MachineOperatorBuilder* ControlFlowOptimizer::machine() const { 285 MachineOperatorBuilder* ControlFlowOptimizer::machine() const {
137 return jsgraph()->machine(); 286 return jsgraph()->machine();
138 } 287 }
139 288
140 } // namespace compiler 289 } // namespace compiler
141 } // namespace internal 290 } // namespace internal
142 } // namespace v8 291 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/control-flow-optimizer.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698