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

Side by Side Diff: pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart

Issue 1203423003: dart2js cps: Better fallthrough analysis and eliminate "return null". (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update tests Created 5 years, 5 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library tree_ir.optimization.logical_rewriter; 5 library tree_ir.optimization.logical_rewriter;
6 6
7 import '../tree_ir_nodes.dart'; 7 import '../tree_ir_nodes.dart';
8 import 'optimization.dart' show Pass; 8 import 'optimization.dart' show Pass;
9 import '../../constants/values.dart' as values; 9 import '../../constants/values.dart' as values;
10 10
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 /// 54 ///
55 class LogicalRewriter extends RecursiveTransformer 55 class LogicalRewriter extends RecursiveTransformer
56 implements Pass { 56 implements Pass {
57 String get passName => 'Logical rewriter'; 57 String get passName => 'Logical rewriter';
58 58
59 @override 59 @override
60 void rewrite(FunctionDefinition node) { 60 void rewrite(FunctionDefinition node) {
61 node.body = visitStatement(node.body); 61 node.body = visitStatement(node.body);
62 } 62 }
63 63
64 /// Statement to be executed next by natural fallthrough. Although fallthrough 64 final FallthroughStack fallthrough = new FallthroughStack();
65 /// is not introduced in this phase, we need to reason about fallthrough when
66 /// evaluating the benefit of swapping the branches of an [If].
67 Statement fallthrough;
68 65
69 @override 66 @override
70 void visitInnerFunction(FunctionDefinition node) { 67 void visitInnerFunction(FunctionDefinition node) {
71 new LogicalRewriter().rewrite(node); 68 new LogicalRewriter().rewrite(node);
72 } 69 }
73 70
74 Statement visitLabeledStatement(LabeledStatement node) { 71 /// True if the given statement is equivalent to its fallthrough semantics.
75 Statement savedFallthrough = fallthrough; 72 ///
76 fallthrough = node.next; 73 /// This means it will ultimately translate to an empty statement.
77 node.body = visitStatement(node.body); 74 bool isFallthrough(Statement node) {
78 fallthrough = savedFallthrough; 75 return node is Break && isFallthroughBreak(node) ||
79 node.next = visitStatement(node.next); 76 node is Continue && isFallthroughContinue(node) ||
80 return node; 77 node is Return && isFallthroughReturn(node);
81 } 78 }
82 79
83 bool isFallthroughBreak(Statement node) { 80 bool isFallthroughBreak(Break node) {
84 return node is Break && node.target.binding.next == fallthrough; 81 Statement target = fallthrough.target;
82 return node.target.binding.next == target ||
83 target is Break && target.target == node.target;
84 }
85
86 bool isFallthroughContinue(Continue node) {
87 Statement target = fallthrough.target;
88 return node.target.binding == target ||
89 target is Continue && target.target == node.target;
90 }
91
92 bool isFallthroughReturn(Return node) {
93 return isNull(node.value) && fallthrough.target == null;
94 }
95
96 bool isTerminator(Statement node) {
97 return (node is Jump || node is Return) && !isFallthrough(node) ||
98 (node is ExpressionStatement && node.next is Unreachable);
85 } 99 }
86 100
87 Statement visitIf(If node) { 101 Statement visitIf(If node) {
88 // If one of the branches is empty (i.e. just a fallthrough), then that 102 // If one of the branches is empty (i.e. just a fallthrough), then that
89 // branch should preferably be the 'else' so we won't have to print it. 103 // branch should preferably be the 'else' so we won't have to print it.
90 // In other words, we wish to perform this rewrite: 104 // In other words, we wish to perform this rewrite:
91 // if (E) {} else {S} 105 // if (E) {} else {S}
92 // ==> 106 // ==>
93 // if (!E) {S} 107 // if (!E) {S}
94 // In the tree language, empty statements do not exist yet, so we must check 108 // In the tree language, empty statements do not exist yet, so we must check
95 // if one branch contains a break that can be eliminated by fallthrough. 109 // if one branch contains a break that can be eliminated by fallthrough.
96 110
97 // Swap branches if then is a fallthrough break. 111 // Rewrite each branch and keep track of which ones might fall through.
98 if (isFallthroughBreak(node.thenStatement)) { 112 int usesBefore = fallthrough.useCount;
113 node.thenStatement = visitStatement(node.thenStatement);
114 int usesAfterThen = fallthrough.useCount;
115 node.elseStatement = visitStatement(node.elseStatement);
116 bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
117 bool elseHasFallthrough = (fallthrough.useCount > usesAfterThen);
118
119 // Determine which branch is most beneficial as 'then' branch.
120 const int THEN = 1;
121 const int NEITHER = 0;
122 const int ELSE = -1;
123 int bestThenBranch = NEITHER;
124 if (isFallthrough(node.thenStatement) &&
125 !isFallthrough(node.elseStatement)) {
126 // Put the empty statement in the 'else' branch.
127 // if (E) {} else {S} ==> if (!E) {S}
128 bestThenBranch = ELSE;
129 } else if (isFallthrough(node.elseStatement) &&
130 !isFallthrough(node.thenStatement)) {
131 // Keep the empty statement in the 'else' branch.
132 // if (E) {S} else {}
133 bestThenBranch = THEN;
134 } else if (thenHasFallthrough && !elseHasFallthrough) {
135 // Put abrupt termination in the 'then' branch to omit 'else'.
136 // if (E) {S1} else {S2; return v} ==> if (!E) {S2; return v}; S1
137 bestThenBranch = ELSE;
138 } else if (!thenHasFallthrough && elseHasFallthrough) {
139 // Keep abrupt termination in the 'then' branch to omit 'else'.
140 // if (E) {S1; return v}; S2
141 bestThenBranch = THEN;
142 } else if (isTerminator(node.elseStatement) &&
143 !isTerminator(node.thenStatement)) {
144 // Put early termination in the 'then' branch to reduce nesting depth.
145 // if (E) {S}; return v ==> if (!E) return v; S
146 bestThenBranch = ELSE;
147 } else if (isTerminator(node.thenStatement) &&
148 !isTerminator(node.elseStatement)) {
149 // Keep early termination in the 'then' branch to reduce nesting depth.
150 // if (E) {return v;} S
151 bestThenBranch = THEN;
152 }
153
154 // Swap branches if 'else' is better as 'then'
155 if (bestThenBranch == ELSE) {
99 node.condition = new Not(node.condition); 156 node.condition = new Not(node.condition);
100 Statement tmp = node.thenStatement; 157 Statement tmp = node.thenStatement;
101 node.thenStatement = node.elseStatement; 158 node.thenStatement = node.elseStatement;
102 node.elseStatement = tmp; 159 node.elseStatement = tmp;
103 } 160 }
104 161
105 // Can the else part be eliminated? 162 // If neither branch is better, eliminate a negation in the condition
106 // (Either due to the above swap or if the break was already there).
107 bool emptyElse = isFallthroughBreak(node.elseStatement);
108
109 node.condition = makeCondition(node.condition, true, liftNots: !emptyElse);
110 node.thenStatement = visitStatement(node.thenStatement);
111 node.elseStatement = visitStatement(node.elseStatement);
112
113 // If neither branch is empty, eliminate a negation in the condition
114 // if (!E) S1 else S2 163 // if (!E) S1 else S2
115 // ==> 164 // ==>
116 // if (E) S2 else S1 165 // if (E) S2 else S1
117 if (!emptyElse && node.condition is Not) { 166 node.condition = makeCondition(node.condition, true,
167 liftNots: bestThenBranch == NEITHER);
168 if (bestThenBranch == NEITHER && node.condition is Not) {
118 node.condition = (node.condition as Not).operand; 169 node.condition = (node.condition as Not).operand;
119 Statement tmp = node.thenStatement; 170 Statement tmp = node.thenStatement;
120 node.thenStatement = node.elseStatement; 171 node.thenStatement = node.elseStatement;
121 node.elseStatement = tmp; 172 node.elseStatement = tmp;
122 } 173 }
123 174
124 return node; 175 return node;
125 } 176 }
126 177
178 Statement visitLabeledStatement(LabeledStatement node) {
179 fallthrough.push(node.next);
180 node.body = visitStatement(node.body);
181 fallthrough.pop();
182 node.next = visitStatement(node.next);
183 return node;
184 }
185
186 Statement visitWhileTrue(WhileTrue node) {
187 fallthrough.push(node);
188 node.body = visitStatement(node.body);
189 fallthrough.pop();
190 return node;
191 }
192
127 Statement visitWhileCondition(WhileCondition node) { 193 Statement visitWhileCondition(WhileCondition node) {
194 fallthrough.push(node);
128 node.condition = makeCondition(node.condition, true, liftNots: false); 195 node.condition = makeCondition(node.condition, true, liftNots: false);
129 node.body = visitStatement(node.body); 196 node.body = visitStatement(node.body);
197 fallthrough.pop();
130 node.next = visitStatement(node.next); 198 node.next = visitStatement(node.next);
131 return node; 199 return node;
132 } 200 }
133 201
202 Statement visitBreak(Break node) {
203 if (isFallthroughBreak(node)) {
204 fallthrough.use();
205 }
206 return node;
207 }
208
209 Statement visitContinue(Continue node) {
210 if (isFallthroughContinue(node)) {
211 fallthrough.use();
212 }
213 return node;
214 }
215
216 Statement visitReturn(Return node) {
217 node.value = visitExpression(node.value);
218 if (isFallthroughReturn(node)) {
219 fallthrough.use();
220 }
221 return node;
222 }
223
134 Expression visitNot(Not node) { 224 Expression visitNot(Not node) {
135 return toBoolean(makeCondition(node.operand, false, liftNots: false)); 225 return toBoolean(makeCondition(node.operand, false, liftNots: false));
136 } 226 }
137 227
138 /// True if the only possible falsy return value of [condition] is [value]. 228 /// True if the only possible falsy return value of [condition] is [value].
139 /// 229 ///
140 /// If [value] is `null` or a truthy value, false is returned. This is to make 230 /// If [value] is `null` or a truthy value, false is returned. This is to make
141 /// pattern matching more convenient. 231 /// pattern matching more convenient.
142 bool matchesFalsyValue(Expression condition, values.ConstantValue value) { 232 bool matchesFalsyValue(Expression condition, values.ConstantValue value) {
143 if (value == null) return false; 233 if (value == null) return false;
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 if (!polarity) { 474 if (!polarity) {
385 values.BoolConstantValue value = e.value; 475 values.BoolConstantValue value = e.value;
386 return new Constant.bool(value.negate()); 476 return new Constant.bool(value.negate());
387 } 477 }
388 return e; 478 return e;
389 } 479 }
390 e = visitExpression(e); 480 e = visitExpression(e);
391 return polarity ? e : new Not(e); 481 return polarity ? e : new Not(e);
392 } 482 }
393 483
484 bool isNull(Expression e) {
485 return e is Constant && e.value.isNull;
486 }
487
394 bool isTrue(Expression e) { 488 bool isTrue(Expression e) {
395 return e is Constant && e.value.isTrue; 489 return e is Constant && e.value.isTrue;
396 } 490 }
397 491
398 bool isFalse(Expression e) { 492 bool isFalse(Expression e) {
399 return e is Constant && e.value.isFalse; 493 return e is Constant && e.value.isFalse;
400 } 494 }
401 495
402 Expression makeAnd(Expression e1, Expression e2, {bool liftNots: true}) { 496 Expression makeAnd(Expression e1, Expression e2, {bool liftNots: true}) {
403 if (e1 is Not && e2 is Not && liftNots) { 497 if (e1 is Not && e2 is Not && liftNots) {
404 return new Not(new LogicalOperator.or(e1.operand, e2.operand)); 498 return new Not(new LogicalOperator.or(e1.operand, e2.operand));
405 } else { 499 } else {
406 return new LogicalOperator.and(e1, e2); 500 return new LogicalOperator.and(e1, e2);
407 } 501 }
408 } 502 }
409 503
410 Expression makeOr(Expression e1, Expression e2, {bool liftNots: true}) { 504 Expression makeOr(Expression e1, Expression e2, {bool liftNots: true}) {
411 if (e1 is Not && e2 is Not && liftNots) { 505 if (e1 is Not && e2 is Not && liftNots) {
412 return new Not(new LogicalOperator.and(e1.operand, e2.operand)); 506 return new Not(new LogicalOperator.and(e1.operand, e2.operand));
413 } else { 507 } else {
414 return new LogicalOperator.or(e1, e2); 508 return new LogicalOperator.or(e1, e2);
415 } 509 }
416 } 510 }
417 } 511 }
418 512
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/codegen/codegen.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698