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

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

Issue 1613853003: dart2js cps: More rewritings for compound assignments. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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.statement_rewriter; 5 library tree_ir.optimization.statement_rewriter;
6 6
7 import 'optimization.dart' show Pass; 7 import 'optimization.dart' show Pass;
8 import '../tree_ir_nodes.dart'; 8 import '../tree_ir_nodes.dart';
9 import '../../io/source_information.dart'; 9 import '../../io/source_information.dart';
10 import '../../elements/elements.dart'; 10 import '../../elements/elements.dart';
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 } 745 }
746 return node; 746 return node;
747 } 747 }
748 748
749 Expression visitTypeOperator(TypeOperator node) { 749 Expression visitTypeOperator(TypeOperator node) {
750 _rewriteList(node.typeArguments); 750 _rewriteList(node.typeArguments);
751 node.value = visitExpression(node.value); 751 node.value = visitExpression(node.value);
752 return node; 752 return node;
753 } 753 }
754 754
755 bool sameVariable(Expression e1, Expression e2) {
756 return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
757 }
758
759 bool isCompoundableBuiltin(Expression e) { 755 bool isCompoundableBuiltin(Expression e) {
760 return e is ApplyBuiltinOperator && 756 return e is ApplyBuiltinOperator &&
761 e.arguments.length == 2 && 757 e.arguments.length >= 2 &&
762 isCompoundableOperator(e.operator); 758 isCompoundableOperator(e.operator);
763 } 759 }
764 760
761 /// Converts a compoundable operator application into the right-hand side for
762 /// use in a compound assignment, discarding the left-hand value.
763 ///
764 /// For example, for `x + y + z` it returns `y + z`.
765 Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
766 assert(isCompoundableBuiltin(e));
767 if (e.arguments.length > 2) {
768 assert(e.operator == BuiltinOperator.StringConcatenate);
769 return new ApplyBuiltinOperator(e.operator, e.arguments.skip(1).toList());
770 } else {
771 return e.arguments[1];
772 }
773 }
774
765 void destroyVariableUse(VariableUse node) { 775 void destroyVariableUse(VariableUse node) {
766 --node.variable.readCount; 776 --node.variable.readCount;
767 } 777 }
768 778
769 Expression visitSetField(SetField node) { 779 Expression visitSetField(SetField node) {
770 allowRhsPropagation.add(true); 780 allowRhsPropagation.add(true);
771 node.value = visitExpression(node.value); 781 node.value = visitExpression(node.value);
772 if (isCompoundableBuiltin(node.value)) { 782 if (isCompoundableBuiltin(node.value)) {
773 ApplyBuiltinOperator rhs = node.value; 783 ApplyBuiltinOperator rhs = node.value;
774 Expression left = rhs.arguments[0]; 784 Expression left = rhs.arguments[0];
775 Expression right = rhs.arguments[1];
776 if (left is GetField && 785 if (left is GetField &&
777 left.field == node.field && 786 left.field == node.field &&
778 sameVariable(left.object, node.object)) { 787 samePrimary(left.object, node.object)) {
779 destroyVariableUse(left.object); 788 destroyPrimaryExpression(left.object);
780 node.compound = rhs.operator; 789 node.compound = rhs.operator;
781 node.value = right; 790 node.value = contractCompoundableBuiltin(rhs);
782 } 791 }
783 } 792 }
784 node.object = visitExpression(node.object); 793 node.object = visitExpression(node.object);
785 allowRhsPropagation.removeLast(); 794 allowRhsPropagation.removeLast();
786 return node; 795 return node;
787 } 796 }
788 797
789 Expression visitGetField(GetField node) { 798 Expression visitGetField(GetField node) {
790 node.object = visitExpression(node.object); 799 node.object = visitExpression(node.object);
791 return node; 800 return node;
792 } 801 }
793 802
794 Expression visitGetStatic(GetStatic node) { 803 Expression visitGetStatic(GetStatic node) {
795 return node; 804 return node;
796 } 805 }
797 806
798 Expression visitSetStatic(SetStatic node) { 807 Expression visitSetStatic(SetStatic node) {
799 allowRhsPropagation.add(true); 808 allowRhsPropagation.add(true);
800 node.value = visitExpression(node.value); 809 node.value = visitExpression(node.value);
810 if (isCompoundableBuiltin(node.value)) {
811 ApplyBuiltinOperator rhs = node.value;
812 Expression left = rhs.arguments[0];
813 if (left is GetStatic &&
814 left.element == node.element &&
815 !left.useLazyGetter) {
816 node.compound = rhs.operator;
817 node.value = contractCompoundableBuiltin(rhs);
818 }
819 }
801 allowRhsPropagation.removeLast(); 820 allowRhsPropagation.removeLast();
802 return node; 821 return node;
803 } 822 }
804 823
805 Expression visitGetTypeTestProperty(GetTypeTestProperty node) { 824 Expression visitGetTypeTestProperty(GetTypeTestProperty node) {
806 node.object = visitExpression(node.object); 825 node.object = visitExpression(node.object);
807 return node; 826 return node;
808 } 827 }
809 828
810 Expression visitCreateBox(CreateBox node) { 829 Expression visitCreateBox(CreateBox node) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 node.index = visitExpression(node.index); 869 node.index = visitExpression(node.index);
851 node.object = visitExpression(node.object); 870 node.object = visitExpression(node.object);
852 return node; 871 return node;
853 } 872 }
854 873
855 Expression visitSetIndex(SetIndex node) { 874 Expression visitSetIndex(SetIndex node) {
856 node.value = visitExpression(node.value); 875 node.value = visitExpression(node.value);
857 if (isCompoundableBuiltin(node.value)) { 876 if (isCompoundableBuiltin(node.value)) {
858 ApplyBuiltinOperator rhs = node.value; 877 ApplyBuiltinOperator rhs = node.value;
859 Expression left = rhs.arguments[0]; 878 Expression left = rhs.arguments[0];
860 Expression right = rhs.arguments[1];
861 if (left is GetIndex && 879 if (left is GetIndex &&
862 sameVariable(left.object, node.object) && 880 samePrimary(left.object, node.object) &&
863 sameVariable(left.index, node.index)) { 881 samePrimary(left.index, node.index)) {
864 destroyVariableUse(left.object); 882 destroyPrimaryExpression(left.object);
865 destroyVariableUse(left.index); 883 destroyPrimaryExpression(left.index);
866 node.compound = rhs.operator; 884 node.compound = rhs.operator;
867 node.value = right; 885 node.value = contractCompoundableBuiltin(rhs);
868 } 886 }
869 } 887 }
870 node.index = visitExpression(node.index); 888 node.index = visitExpression(node.index);
871 node.object = visitExpression(node.object); 889 node.object = visitExpression(node.object);
872 return node; 890 return node;
873 } 891 }
874 892
875 /// True if [operator] is a binary operator that always has the same value 893 /// True if [operator] is a binary operator that always has the same value
876 /// if its arguments are swapped. 894 /// if its arguments are swapped.
877 bool isSymmetricOperator(BuiltinOperator operator) { 895 bool isSymmetricOperator(BuiltinOperator operator) {
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 /// 1047 ///
1030 /// C ? (v = E1) : (v = E2) 1048 /// C ? (v = E1) : (v = E2)
1031 /// ==> 1049 /// ==>
1032 /// v = C ? E1 : E2 1050 /// v = C ? E1 : E2
1033 /// 1051 ///
1034 /// The latter form is more compact and can also be inlined. 1052 /// The latter form is more compact and can also be inlined.
1035 CombinedExpressions combineAsConditional( 1053 CombinedExpressions combineAsConditional(
1036 Expression s, 1054 Expression s,
1037 Expression t, 1055 Expression t,
1038 Expression condition) { 1056 Expression condition) {
1039 if (s is Assign && t is Assign && s.variable == t.variable) { 1057 if (s is Assign && t is Assign &&
1040 Expression values = new Conditional(condition, s.value, t.value); 1058 s.variable == t.variable) {
1041 return new CombinedAssigns(s, t, new CombinedExpressions(values)); 1059 return new CombinedAssigns(s, t,
1060 combineAsConditional(s.value, t.value, condition));
1061 }
1062 if (s is SetStatic &&
1063 t is SetStatic &&
1064 s.element == t.element) {
1065 return new CombinedSetStatics(s, t,
1066 combineAsConditional(s.value, t.value, condition));
1067 }
1068 if (s is SetField &&
1069 t is SetField &&
1070 s.compound == null &&
1071 t.compound == null &&
1072 s.field == t.field &&
1073 samePrimary(s.object, t.object)) {
1074 return new CombinedSetFields(s, t,
1075 combineAsConditional(s.value, t.value, condition));
1076 }
1077 if (s is SetIndex &&
1078 t is SetIndex &&
1079 s.compound == null &&
1080 t.compound == null &&
1081 samePrimary(s.object, t.object) &&
1082 samePrimary(s.index, t.index)) {
1083 return new CombinedSetIndexes(s, t,
1084 combineAsConditional(s.value, t.value, condition));
1042 } 1085 }
1043 return new CombinedExpressions(new Conditional(condition, s, t)); 1086 return new CombinedExpressions(new Conditional(condition, s, t));
1044 } 1087 }
1045 1088
1046 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1089 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1047 /// [t] are incompatible. 1090 /// [t] are incompatible.
1048 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1091 /// If non-null is returned, the caller MUST discard [s] and [t] and use
1049 /// the returned statement instead. 1092 /// the returned statement instead.
1050 /// If two breaks are combined, the label's break counter will be decremented. 1093 /// If two breaks are combined, the label's break counter will be decremented.
1051 Statement combineStatements(Statement s, Statement t) { 1094 Statement combineStatements(Statement s, Statement t) {
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 /// 1317 ///
1275 /// Explicitly reverting a combination is necessary to maintain variable 1318 /// Explicitly reverting a combination is necessary to maintain variable
1276 /// reference counts. 1319 /// reference counts.
1277 abstract class CombinedExpressions { 1320 abstract class CombinedExpressions {
1278 Expression get combined; 1321 Expression get combined;
1279 void uncombine(); 1322 void uncombine();
1280 1323
1281 factory CombinedExpressions(Expression e) = GenericCombinedExpressions; 1324 factory CombinedExpressions(Expression e) = GenericCombinedExpressions;
1282 } 1325 }
1283 1326
1284 /// Combines assignments of form `[variable] := E1` and `[variable] := E2` into 1327 /// Combines assignments of form `v := E1` and `v := E2` into
1285 /// a single assignment of form `[variable] := combine(E1, E2)`. 1328 /// a single assignment of form `v := combine(E1, E2)`.
sra1 2016/01/22 03:22:04 We probably want to avoid this where one arm is a
asgerf 2016/01/22 18:54:47 Good point. I looked at the IR generated by V8 in
1286 class CombinedAssigns implements CombinedExpressions { 1329 class CombinedAssigns implements CombinedExpressions {
1287 Assign assign1, assign2; 1330 Assign assign1, assign2;
1288 CombinedExpressions value; 1331 CombinedExpressions value;
1289 Expression combined; 1332 Assign combined;
1290 1333
1291 CombinedAssigns(this.assign1, this.assign2, this.value) { 1334 CombinedAssigns(this.assign1, this.assign2, this.value) {
1292 assert(assign1.variable == assign2.variable); 1335 assert(assign1.variable == assign2.variable);
1293 assign1.variable.writeCount -= 2; // Destroy the two original assignemnts. 1336 assign1.variable.writeCount -= 2; // Destroy the two original assignemnts.
1294 combined = new Assign(assign1.variable, value.combined); 1337 combined = new Assign(assign1.variable, value.combined);
1295 } 1338 }
1296 1339
1297 void uncombine() { 1340 void uncombine() {
1298 value.uncombine(); 1341 value.uncombine();
1299 ++assign1.variable.writeCount; // Restore original reference count. 1342 ++assign1.variable.writeCount; // Restore original reference count.
1300 } 1343 }
1301 } 1344 }
1302 1345
1346 /// Combines `static = E1` and `static = E2` into `static = combine(E1, E2)`.
1347 class CombinedSetStatics implements CombinedExpressions {
1348 SetStatic assign1, assign2;
1349 CombinedExpressions value;
1350 SetStatic combined;
1351
1352 CombinedSetStatics(this.assign1, this.assign2, this.value) {
1353 assert(assign1.element == assign2.element);
1354 // TODO(asgerf): Can we combine source information from the two assignments?
1355 combined = new SetStatic(assign1.element, value.combined,
1356 assign1.sourceInformation);
1357 }
1358
1359 void uncombine() {
1360 value.uncombine();
1361 }
1362 }
1363
1364 /// Combines `v.field = E1` and `v.field = E2` into `v.field = combine(E1, E2)`.
1365 class CombinedSetFields implements CombinedExpressions {
1366 SetField assign1, assign2;
1367 CombinedExpressions value;
1368 SetField combined;
1369
1370 CombinedSetFields(this.assign1, this.assign2, this.value) {
1371 assert(samePrimary(assign1.object, assign2.object));
1372 assert(assign1.field == assign2.field);
1373 assert(assign1.compound == null);
1374 assert(assign2.compound == null);
1375 destroyPrimaryExpression(assign2.object);
1376 combined = new SetField(assign1.object, assign1.field, value.combined);
1377 }
1378
1379 void uncombine() {
1380 value.uncombine();
1381 restorePrimaryExpression(assign2.object);
1382 }
1383 }
1384
1385 /// Combines `v[index] = E1` and `v[index] = E2` into
1386 /// `v[index] = combine(E1, E2)`.
1387 class CombinedSetIndexes implements CombinedExpressions {
1388 SetIndex assign1, assign2;
1389 CombinedExpressions value;
1390 SetIndex combined;
1391
1392 CombinedSetIndexes(this.assign1, this.assign2, this.value) {
1393 assert(samePrimary(assign1.object, assign2.object));
1394 assert(samePrimary(assign1.index, assign2.index));
1395 assert(assign1.compound == null);
1396 assert(assign2.compound == null);
1397 destroyPrimaryExpression(assign2.object);
1398 destroyPrimaryExpression(assign2.index);
1399 combined = new SetIndex(assign1.object, assign1.index, value.combined,
1400 compound: assign1.compound);
1401 }
1402
1403 void uncombine() {
1404 value.uncombine();
1405 restorePrimaryExpression(assign2.object);
1406 restorePrimaryExpression(assign2.index);
1407 }
1408 }
1409
1303 /// Combines two variable uses into one. 1410 /// Combines two variable uses into one.
1304 class CombinedUses implements CombinedExpressions { 1411 class CombinedUses implements CombinedExpressions {
1305 VariableUse use1, use2; 1412 VariableUse use1, use2;
1306 Expression combined; 1413 VariableUse combined;
1307 1414
1308 CombinedUses(this.use1, this.use2) { 1415 CombinedUses(this.use1, this.use2) {
1309 assert(use1.variable == use2.variable); 1416 assert(use1.variable == use2.variable);
1310 use1.variable.readCount -= 2; // Destroy both the original uses. 1417 use1.variable.readCount -= 2; // Destroy both the original uses.
1311 combined = new VariableUse(use1.variable); 1418 combined = new VariableUse(use1.variable);
1312 } 1419 }
1313 1420
1314 void uncombine() { 1421 void uncombine() {
1315 ++use1.variable.readCount; // Restore original reference count. 1422 ++use1.variable.readCount; // Restore original reference count.
1316 } 1423 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 VariableUseCallback callback; 1456 VariableUseCallback callback;
1350 1457
1351 VariableUseVisitor(this.callback); 1458 VariableUseVisitor(this.callback);
1352 1459
1353 visitVariableUse(VariableUse use) => callback(use); 1460 visitVariableUse(VariableUse use) => callback(use);
1354 1461
1355 static void visit(Expression node, VariableUseCallback callback) { 1462 static void visit(Expression node, VariableUseCallback callback) {
1356 new VariableUseVisitor(callback).visitExpression(node); 1463 new VariableUseVisitor(callback).visitExpression(node);
1357 } 1464 }
1358 } 1465 }
1466
1467 bool sameVariable(Expression e1, Expression e2) {
1468 return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
1469 }
1470
1471 /// True if [e1] and [e2] are primary expressions (expressions without
1472 /// subexpressions) with the same value.
1473 bool samePrimary(Expression e1, Expression e2) {
1474 return sameVariable(e1, e2) || (e1 is This && e2 is This);
1475 }
1476
1477 /// Decrement the reference count for [e] if it is a variable use.
1478 void destroyPrimaryExpression(Expression e) {
1479 if (e is VariableUse) {
1480 --e.variable.readCount;
1481 } else {
1482 assert(e is This);
1483 }
1484 }
1485
1486 /// Increment the reference count for [e] if it is a variable use.
1487 void restorePrimaryExpression(Expression e) {
1488 if (e is VariableUse) {
1489 ++e.variable.readCount;
1490 } else {
1491 assert(e is This);
1492 }
1493 }
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