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

Side by Side Diff: runtime/vm/branch_optimizer.cc

Issue 2481873005: clang-format runtime/vm (Closed)
Patch Set: Merge Created 4 years, 1 month 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 | « runtime/vm/branch_optimizer.h ('k') | runtime/vm/cha.h » ('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 (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/branch_optimizer.h" 5 #include "vm/branch_optimizer.h"
6 6
7 #include "vm/flow_graph.h" 7 #include "vm/flow_graph.h"
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 namespace dart { 10 namespace dart {
11 11
12 // Returns true if the given phi has a single input use and 12 // Returns true if the given phi has a single input use and
13 // is used in the environments either at the corresponding block entry or 13 // is used in the environments either at the corresponding block entry or
14 // at the same instruction where input use is. 14 // at the same instruction where input use is.
15 static bool PhiHasSingleUse(PhiInstr* phi, Value* use) { 15 static bool PhiHasSingleUse(PhiInstr* phi, Value* use) {
16 if ((use->next_use() != NULL) || (phi->input_use_list() != use)) { 16 if ((use->next_use() != NULL) || (phi->input_use_list() != use)) {
17 return false; 17 return false;
18 } 18 }
19 19
20 BlockEntryInstr* block = phi->block(); 20 BlockEntryInstr* block = phi->block();
21 for (Value* env_use = phi->env_use_list(); 21 for (Value* env_use = phi->env_use_list(); env_use != NULL;
22 env_use != NULL;
23 env_use = env_use->next_use()) { 22 env_use = env_use->next_use()) {
24 if ((env_use->instruction() != block) && 23 if ((env_use->instruction() != block) &&
25 (env_use->instruction() != use->instruction())) { 24 (env_use->instruction() != use->instruction())) {
26 return false; 25 return false;
27 } 26 }
28 } 27 }
29 28
30 return true; 29 return true;
31 } 30 }
32 31
(...skipping 15 matching lines...) Expand all
48 return false; 47 return false;
49 } 48 }
50 if (comparison->CanDeoptimize() || comparison->MayThrow()) { 49 if (comparison->CanDeoptimize() || comparison->MayThrow()) {
51 return false; 50 return false;
52 } 51 }
53 Value* left = comparison->left(); 52 Value* left = comparison->left();
54 PhiInstr* phi = left->definition()->AsPhi(); 53 PhiInstr* phi = left->definition()->AsPhi();
55 Value* right = comparison->right(); 54 Value* right = comparison->right();
56 ConstantInstr* constant = 55 ConstantInstr* constant =
57 (right == NULL) ? NULL : right->definition()->AsConstant(); 56 (right == NULL) ? NULL : right->definition()->AsConstant();
58 return (phi != NULL) && 57 return (phi != NULL) && (constant != NULL) && (phi->GetBlock() == block) &&
59 (constant != NULL) && 58 PhiHasSingleUse(phi, left) && (block->next() == branch) &&
60 (phi->GetBlock() == block) && 59 (block->phis()->length() == 1);
61 PhiHasSingleUse(phi, left) &&
62 (block->next() == branch) &&
63 (block->phis()->length() == 1);
64 } 60 }
65 61
66 62
67 JoinEntryInstr* BranchSimplifier::ToJoinEntry(Zone* zone, 63 JoinEntryInstr* BranchSimplifier::ToJoinEntry(Zone* zone,
68 TargetEntryInstr* target) { 64 TargetEntryInstr* target) {
69 // Convert a target block into a join block. Branches will be duplicated 65 // Convert a target block into a join block. Branches will be duplicated
70 // so the former true and false targets become joins of the control flows 66 // so the former true and false targets become joins of the control flows
71 // from all the duplicated branches. 67 // from all the duplicated branches.
72 JoinEntryInstr* join = 68 JoinEntryInstr* join =
73 new(zone) JoinEntryInstr(target->block_id(), target->try_index()); 69 new (zone) JoinEntryInstr(target->block_id(), target->try_index());
74 join->InheritDeoptTarget(zone, target); 70 join->InheritDeoptTarget(zone, target);
75 join->LinkTo(target->next()); 71 join->LinkTo(target->next());
76 join->set_last_instruction(target->last_instruction()); 72 join->set_last_instruction(target->last_instruction());
77 target->UnuseAllInputs(); 73 target->UnuseAllInputs();
78 return join; 74 return join;
79 } 75 }
80 76
81 77
82 BranchInstr* BranchSimplifier::CloneBranch(Zone* zone, 78 BranchInstr* BranchSimplifier::CloneBranch(Zone* zone,
83 BranchInstr* branch, 79 BranchInstr* branch,
84 Value* new_left, 80 Value* new_left,
85 Value* new_right) { 81 Value* new_right) {
86 ComparisonInstr* comparison = branch->comparison(); 82 ComparisonInstr* comparison = branch->comparison();
87 ComparisonInstr* new_comparison = 83 ComparisonInstr* new_comparison =
88 comparison->CopyWithNewOperands(new_left, new_right); 84 comparison->CopyWithNewOperands(new_left, new_right);
89 BranchInstr* new_branch = new(zone) BranchInstr(new_comparison); 85 BranchInstr* new_branch = new (zone) BranchInstr(new_comparison);
90 new_branch->set_is_checked(branch->is_checked()); 86 new_branch->set_is_checked(branch->is_checked());
91 return new_branch; 87 return new_branch;
92 } 88 }
93 89
94 90
95 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { 91 void BranchSimplifier::Simplify(FlowGraph* flow_graph) {
96 // Optimize some branches that test the value of a phi. When it is safe 92 // Optimize some branches that test the value of a phi. When it is safe
97 // to do so, push the branch to each of the predecessor blocks. This is 93 // to do so, push the branch to each of the predecessor blocks. This is
98 // an optimization when (a) it can avoid materializing a boolean object at 94 // an optimization when (a) it can avoid materializing a boolean object at
99 // the phi only to test its value, and (b) it can expose opportunities for 95 // the phi only to test its value, and (b) it can expose opportunities for
(...skipping 27 matching lines...) Expand all
127 // The branch will be copied and pushed to all the join's 123 // The branch will be copied and pushed to all the join's
128 // predecessors. Convert the true and false target blocks into join 124 // predecessors. Convert the true and false target blocks into join
129 // blocks to join the control flows from all of the true 125 // blocks to join the control flows from all of the true
130 // (respectively, false) targets of the copied branches. 126 // (respectively, false) targets of the copied branches.
131 // 127 //
132 // The converted join block will have no phis, so it cannot be another 128 // The converted join block will have no phis, so it cannot be another
133 // instance of the pattern. There is thus no need to add it to the 129 // instance of the pattern. There is thus no need to add it to the
134 // worklist. 130 // worklist.
135 BranchInstr* branch = block->last_instruction()->AsBranch(); 131 BranchInstr* branch = block->last_instruction()->AsBranch();
136 ASSERT(branch != NULL); 132 ASSERT(branch != NULL);
137 JoinEntryInstr* join_true = 133 JoinEntryInstr* join_true = ToJoinEntry(zone, branch->true_successor());
138 ToJoinEntry(zone, branch->true_successor()); 134 JoinEntryInstr* join_false = ToJoinEntry(zone, branch->false_successor());
139 JoinEntryInstr* join_false =
140 ToJoinEntry(zone, branch->false_successor());
141 135
142 ComparisonInstr* comparison = branch->comparison(); 136 ComparisonInstr* comparison = branch->comparison();
143 PhiInstr* phi = comparison->left()->definition()->AsPhi(); 137 PhiInstr* phi = comparison->left()->definition()->AsPhi();
144 ConstantInstr* constant = comparison->right()->definition()->AsConstant(); 138 ConstantInstr* constant = comparison->right()->definition()->AsConstant();
145 ASSERT(constant != NULL); 139 ASSERT(constant != NULL);
146 // Copy the constant and branch and push it to all the predecessors. 140 // Copy the constant and branch and push it to all the predecessors.
147 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { 141 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) {
148 GotoInstr* old_goto = 142 GotoInstr* old_goto =
149 block->PredecessorAt(i)->last_instruction()->AsGoto(); 143 block->PredecessorAt(i)->last_instruction()->AsGoto();
150 ASSERT(old_goto != NULL); 144 ASSERT(old_goto != NULL);
151 145
152 // Replace the goto in each predecessor with a rewritten branch, 146 // Replace the goto in each predecessor with a rewritten branch,
153 // rewritten to use the corresponding phi input instead of the phi. 147 // rewritten to use the corresponding phi input instead of the phi.
154 Value* new_left = phi->InputAt(i)->Copy(zone); 148 Value* new_left = phi->InputAt(i)->Copy(zone);
155 Value* new_right = new(zone) Value(constant); 149 Value* new_right = new (zone) Value(constant);
156 BranchInstr* new_branch = 150 BranchInstr* new_branch =
157 CloneBranch(zone, branch, new_left, new_right); 151 CloneBranch(zone, branch, new_left, new_right);
158 if (branch->env() == NULL) { 152 if (branch->env() == NULL) {
159 new_branch->InheritDeoptTarget(zone, old_goto); 153 new_branch->InheritDeoptTarget(zone, old_goto);
160 } else { 154 } else {
161 // Take the environment from the branch if it has one. 155 // Take the environment from the branch if it has one.
162 new_branch->InheritDeoptTarget(zone, branch); 156 new_branch->InheritDeoptTarget(zone, branch);
163 // InheritDeoptTarget gave the new branch's comparison the same 157 // InheritDeoptTarget gave the new branch's comparison the same
164 // deopt id that it gave the new branch. The id should be the 158 // deopt id that it gave the new branch. The id should be the
165 // deopt id of the original comparison. 159 // deopt id of the original comparison.
166 new_branch->comparison()->SetDeoptId(*comparison); 160 new_branch->comparison()->SetDeoptId(*comparison);
167 // The phi can be used in the branch's environment. Rename such 161 // The phi can be used in the branch's environment. Rename such
168 // uses. 162 // uses.
169 for (Environment::DeepIterator it(new_branch->env()); 163 for (Environment::DeepIterator it(new_branch->env()); !it.Done();
170 !it.Done();
171 it.Advance()) { 164 it.Advance()) {
172 Value* use = it.CurrentValue(); 165 Value* use = it.CurrentValue();
173 if (use->definition() == phi) { 166 if (use->definition() == phi) {
174 Definition* replacement = phi->InputAt(i)->definition(); 167 Definition* replacement = phi->InputAt(i)->definition();
175 use->RemoveFromUseList(); 168 use->RemoveFromUseList();
176 use->set_definition(replacement); 169 use->set_definition(replacement);
177 replacement->AddEnvUse(use); 170 replacement->AddEnvUse(use);
178 } 171 }
179 } 172 }
180 } 173 }
181 174
182 new_branch->InsertBefore(old_goto); 175 new_branch->InsertBefore(old_goto);
183 new_branch->set_next(NULL); // Detaching the goto from the graph. 176 new_branch->set_next(NULL); // Detaching the goto from the graph.
184 old_goto->UnuseAllInputs(); 177 old_goto->UnuseAllInputs();
185 178
186 // Update the predecessor block. We may have created another 179 // Update the predecessor block. We may have created another
187 // instance of the pattern so add it to the worklist if necessary. 180 // instance of the pattern so add it to the worklist if necessary.
188 BlockEntryInstr* branch_block = new_branch->GetBlock(); 181 BlockEntryInstr* branch_block = new_branch->GetBlock();
189 branch_block->set_last_instruction(new_branch); 182 branch_block->set_last_instruction(new_branch);
190 if (branch_block->IsJoinEntry()) worklist.Add(branch_block); 183 if (branch_block->IsJoinEntry()) worklist.Add(branch_block);
191 184
192 // Connect the branch to the true and false joins, via empty target 185 // Connect the branch to the true and false joins, via empty target
193 // blocks. 186 // blocks.
194 TargetEntryInstr* true_target = 187 TargetEntryInstr* true_target = new (zone) TargetEntryInstr(
195 new(zone) TargetEntryInstr(flow_graph->max_block_id() + 1, 188 flow_graph->max_block_id() + 1, block->try_index());
196 block->try_index());
197 true_target->InheritDeoptTarget(zone, join_true); 189 true_target->InheritDeoptTarget(zone, join_true);
198 TargetEntryInstr* false_target = 190 TargetEntryInstr* false_target = new (zone) TargetEntryInstr(
199 new(zone) TargetEntryInstr(flow_graph->max_block_id() + 2, 191 flow_graph->max_block_id() + 2, block->try_index());
200 block->try_index());
201 false_target->InheritDeoptTarget(zone, join_false); 192 false_target->InheritDeoptTarget(zone, join_false);
202 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2); 193 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2);
203 *new_branch->true_successor_address() = true_target; 194 *new_branch->true_successor_address() = true_target;
204 *new_branch->false_successor_address() = false_target; 195 *new_branch->false_successor_address() = false_target;
205 GotoInstr* goto_true = new(zone) GotoInstr(join_true); 196 GotoInstr* goto_true = new (zone) GotoInstr(join_true);
206 goto_true->InheritDeoptTarget(zone, join_true); 197 goto_true->InheritDeoptTarget(zone, join_true);
207 true_target->LinkTo(goto_true); 198 true_target->LinkTo(goto_true);
208 true_target->set_last_instruction(goto_true); 199 true_target->set_last_instruction(goto_true);
209 GotoInstr* goto_false = new(zone) GotoInstr(join_false); 200 GotoInstr* goto_false = new (zone) GotoInstr(join_false);
210 goto_false->InheritDeoptTarget(zone, join_false); 201 goto_false->InheritDeoptTarget(zone, join_false);
211 false_target->LinkTo(goto_false); 202 false_target->LinkTo(goto_false);
212 false_target->set_last_instruction(goto_false); 203 false_target->set_last_instruction(goto_false);
213 } 204 }
214 // When all predecessors have been rewritten, the original block is 205 // When all predecessors have been rewritten, the original block is
215 // unreachable from the graph. 206 // unreachable from the graph.
216 phi->UnuseAllInputs(); 207 phi->UnuseAllInputs();
217 branch->UnuseAllInputs(); 208 branch->UnuseAllInputs();
218 block->UnuseAllInputs(); 209 block->UnuseAllInputs();
219 ASSERT(!phi->HasUses()); 210 ASSERT(!phi->HasUses());
220 } 211 }
221 } 212 }
222 213
223 if (changed) { 214 if (changed) {
224 // We may have changed the block order and the dominator tree. 215 // We may have changed the block order and the dominator tree.
225 flow_graph->DiscoverBlocks(); 216 flow_graph->DiscoverBlocks();
226 GrowableArray<BitVector*> dominance_frontier; 217 GrowableArray<BitVector*> dominance_frontier;
227 flow_graph->ComputeDominators(&dominance_frontier); 218 flow_graph->ComputeDominators(&dominance_frontier);
228 } 219 }
229 } 220 }
230 221
231 222
232 static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) { 223 static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) {
233 return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) && 224 return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) &&
234 ((block->next() == block->last_instruction()) || 225 ((block->next() == block->last_instruction()) ||
235 ((block->next() == defn) && (defn->next() == block->last_instruction()))); 226 ((block->next() == defn) &&
227 (defn->next() == block->last_instruction())));
236 } 228 }
237 229
238 230
239 static void EliminateTrivialBlock(BlockEntryInstr* block, 231 static void EliminateTrivialBlock(BlockEntryInstr* block,
240 Definition* instr, 232 Definition* instr,
241 IfThenElseInstr* before) { 233 IfThenElseInstr* before) {
242 block->UnuseAllInputs(); 234 block->UnuseAllInputs();
243 block->last_instruction()->UnuseAllInputs(); 235 block->last_instruction()->UnuseAllInputs();
244 236
245 if ((block->next() == instr) && 237 if ((block->next() == instr) &&
(...skipping 26 matching lines...) Expand all
272 // v2 = Constant(...) 264 // v2 = Constant(...)
273 // goto B_block 265 // goto B_block
274 // B_block: 266 // B_block:
275 // v3 = phi(v1, v2) -- single phi 267 // v3 = phi(v1, v2) -- single phi
276 // 268 //
277 // and replace it with 269 // and replace it with
278 // 270 //
279 // Ba: 271 // Ba:
280 // v3 = IfThenElse(COMP ? v1 : v2) 272 // v3 = IfThenElse(COMP ? v1 : v2)
281 // 273 //
282 if ((join != NULL) && 274 if ((join != NULL) && (join->phis() != NULL) &&
283 (join->phis() != NULL) && 275 (join->phis()->length() == 1) && (block->PredecessorCount() == 2)) {
284 (join->phis()->length() == 1) &&
285 (block->PredecessorCount() == 2)) {
286 BlockEntryInstr* pred1 = block->PredecessorAt(0); 276 BlockEntryInstr* pred1 = block->PredecessorAt(0);
287 BlockEntryInstr* pred2 = block->PredecessorAt(1); 277 BlockEntryInstr* pred2 = block->PredecessorAt(1);
288 278
289 PhiInstr* phi = (*join->phis())[0]; 279 PhiInstr* phi = (*join->phis())[0];
290 Value* v1 = phi->InputAt(0); 280 Value* v1 = phi->InputAt(0);
291 Value* v2 = phi->InputAt(1); 281 Value* v2 = phi->InputAt(1);
292 282
293 if (IsTrivialBlock(pred1, v1->definition()) && 283 if (IsTrivialBlock(pred1, v1->definition()) &&
294 IsTrivialBlock(pred2, v2->definition()) && 284 IsTrivialBlock(pred2, v2->definition()) &&
295 (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) { 285 (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) {
296 BlockEntryInstr* pred = pred1->PredecessorAt(0); 286 BlockEntryInstr* pred = pred1->PredecessorAt(0);
297 BranchInstr* branch = pred->last_instruction()->AsBranch(); 287 BranchInstr* branch = pred->last_instruction()->AsBranch();
298 ComparisonInstr* comparison = branch->comparison(); 288 ComparisonInstr* comparison = branch->comparison();
299 289
300 // Check if the platform supports efficient branchless IfThenElseInstr 290 // Check if the platform supports efficient branchless IfThenElseInstr
301 // for the given combination of comparison and values flowing from 291 // for the given combination of comparison and values flowing from
302 // false and true paths. 292 // false and true paths.
303 if (IfThenElseInstr::Supports(comparison, v1, v2)) { 293 if (IfThenElseInstr::Supports(comparison, v1, v2)) {
304 Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2; 294 Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2;
305 Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2; 295 Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2;
306 296
307 ComparisonInstr* new_comparison = 297 ComparisonInstr* new_comparison = comparison->CopyWithNewOperands(
308 comparison->CopyWithNewOperands( 298 comparison->left()->Copy(zone), comparison->right()->Copy(zone));
309 comparison->left()->Copy(zone), 299 IfThenElseInstr* if_then_else = new (zone) IfThenElseInstr(
310 comparison->right()->Copy(zone)); 300 new_comparison, if_true->Copy(zone), if_false->Copy(zone));
311 IfThenElseInstr* if_then_else = new(zone) IfThenElseInstr( 301 flow_graph->InsertBefore(branch, if_then_else, NULL,
312 new_comparison,
313 if_true->Copy(zone),
314 if_false->Copy(zone));
315 flow_graph->InsertBefore(branch,
316 if_then_else,
317 NULL,
318 FlowGraph::kValue); 302 FlowGraph::kValue);
319 303
320 phi->ReplaceUsesWith(if_then_else); 304 phi->ReplaceUsesWith(if_then_else);
321 305
322 // Connect IfThenElseInstr to the first instruction in the merge block 306 // Connect IfThenElseInstr to the first instruction in the merge block
323 // effectively eliminating diamond control flow. 307 // effectively eliminating diamond control flow.
324 // Current block as well as pred1 and pred2 blocks are no longer in 308 // Current block as well as pred1 and pred2 blocks are no longer in
325 // the graph at this point. 309 // the graph at this point.
326 if_then_else->LinkTo(join->next()); 310 if_then_else->LinkTo(join->next());
327 pred->set_last_instruction(join->last_instruction()); 311 pred->set_last_instruction(join->last_instruction());
(...skipping 24 matching lines...) Expand all
352 if (changed) { 336 if (changed) {
353 // We may have changed the block order and the dominator tree. 337 // We may have changed the block order and the dominator tree.
354 flow_graph->DiscoverBlocks(); 338 flow_graph->DiscoverBlocks();
355 GrowableArray<BitVector*> dominance_frontier; 339 GrowableArray<BitVector*> dominance_frontier;
356 flow_graph->ComputeDominators(&dominance_frontier); 340 flow_graph->ComputeDominators(&dominance_frontier);
357 } 341 }
358 } 342 }
359 343
360 344
361 } // namespace dart 345 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/branch_optimizer.h ('k') | runtime/vm/cha.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698