Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |