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

Side by Side Diff: lib/compiler/implementation/ssa/codegen.dart

Issue 10495013: Recognize logical operations before code generation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 class SsaCodeGeneratorTask extends CompilerTask { 5 class SsaCodeGeneratorTask extends CompilerTask {
6 final JavaScriptBackend backend; 6 final JavaScriptBackend backend;
7 SsaCodeGeneratorTask(JavaScriptBackend backend) 7 SsaCodeGeneratorTask(JavaScriptBackend backend)
8 : this.backend = backend, 8 : this.backend = backend,
9 super(backend.compiler); 9 super(backend.compiler);
10 String get name() => 'SSA code generator'; 10 String get name() => 'SSA code generator';
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 static final int TYPE_STATEMENT = 0; 140 static final int TYPE_STATEMENT = 0;
141 static final int TYPE_EXPRESSION = 1; 141 static final int TYPE_EXPRESSION = 1;
142 static final int TYPE_DECLARATION = 2; 142 static final int TYPE_DECLARATION = 2;
143 143
144 final JavaScriptBackend backend; 144 final JavaScriptBackend backend;
145 final WorkItem work; 145 final WorkItem work;
146 final StringBuffer buffer; 146 final StringBuffer buffer;
147 final String parameters; 147 final String parameters;
148 148
149 final Set<HInstruction> generateAtUseSite; 149 final Set<HInstruction> generateAtUseSite;
150 final Map<HPhi, String> logicalOperations; 150 final Set<HInstruction> logicalOperations;
151 final Map<Element, ElementAction> breakAction; 151 final Map<Element, ElementAction> breakAction;
152 final Map<Element, ElementAction> continueAction; 152 final Map<Element, ElementAction> continueAction;
153 final Map<Element, String> parameterNames; 153 final Map<Element, String> parameterNames;
154 154
155 /** 155 /**
156 * Contains the names of the instructions, as well as the parallel 156 * Contains the names of the instructions, as well as the parallel
157 * copies to perform on block transitioning. 157 * copies to perform on block transitioning.
158 */ 158 */
159 VariableNames variableNames; 159 VariableNames variableNames;
160 160
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 } 199 }
200 200
201 SsaCodeGenerator(this.backend, 201 SsaCodeGenerator(this.backend,
202 this.work, 202 this.work,
203 this.parameters, 203 this.parameters,
204 this.parameterNames) 204 this.parameterNames)
205 : declaredVariables = new Set<String>(), 205 : declaredVariables = new Set<String>(),
206 delayedVariablesDeclaration = new List<String>(), 206 delayedVariablesDeclaration = new List<String>(),
207 buffer = new StringBuffer(), 207 buffer = new StringBuffer(),
208 generateAtUseSite = new Set<HInstruction>(), 208 generateAtUseSite = new Set<HInstruction>(),
209 logicalOperations = new Map<HPhi, String>(), 209 logicalOperations = new Set<HInstruction>(),
210 breakAction = new Map<Element, ElementAction>(), 210 breakAction = new Map<Element, ElementAction>(),
211 continueAction = new Map<Element, ElementAction>(), 211 continueAction = new Map<Element, ElementAction>(),
212 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { 212 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] {
213 213
214 Interceptors interceptors = backend.builder.interceptors; 214 Interceptors interceptors = backend.builder.interceptors;
215 equalsNullElement = interceptors.getEqualsNullInterceptor(); 215 equalsNullElement = interceptors.getEqualsNullInterceptor();
216 boolifiedEqualsNullElement = 216 boolifiedEqualsNullElement =
217 interceptors.getBoolifiedVersionOf(equalsNullElement); 217 interceptors.getBoolifiedVersionOf(equalsNullElement);
218 } 218 }
219 219
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 buffer.add("var "); 480 buffer.add("var ");
481 } 481 }
482 buffer.add(variableName); 482 buffer.add(variableName);
483 } 483 }
484 484
485 void declareInstruction(HInstruction instruction) { 485 void declareInstruction(HInstruction instruction) {
486 declareVariable(variableNames.getName(instruction)); 486 declareVariable(variableNames.getName(instruction));
487 } 487 }
488 488
489 void define(HInstruction instruction) { 489 void define(HInstruction instruction) {
490 if (isGeneratingExpression()) {
491 addExpressionSeparator();
492 } else {
493 addIndentation();
494 }
490 if (instruction is !HCheck && variableNames.hasName(instruction)) { 495 if (instruction is !HCheck && variableNames.hasName(instruction)) {
491 declareInstruction(instruction); 496 declareInstruction(instruction);
492 buffer.add(" = "); 497 buffer.add(" = ");
493 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); 498 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
494 } else { 499 } else {
495 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 500 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
496 } 501 }
502 if (!isGeneratingExpression()) buffer.add(';\n');
497 } 503 }
498 504
499 void use(HInstruction argument, int expectedPrecedenceForArgument) { 505 void use(HInstruction argument, int expectedPrecedenceForArgument) {
500 if (isGenerateAtUseSite(argument)) { 506 if (isGenerateAtUseSite(argument)) {
501 visit(argument, expectedPrecedenceForArgument); 507 visit(argument, expectedPrecedenceForArgument);
502 } else if (argument is HCheck) { 508 } else if (argument is HCheck) {
503 HCheck check = argument; 509 HCheck check = argument;
504 use(argument.checkedInput, expectedPrecedenceForArgument); 510 use(argument.checkedInput, expectedPrecedenceForArgument);
505 } else { 511 } else {
506 buffer.add(variableNames.getName(argument)); 512 buffer.add(variableNames.getName(argument));
(...skipping 19 matching lines...) Expand all
526 buffer.add(";\n"); 532 buffer.add(";\n");
527 } 533 }
528 534
529 void implicitBreakWithLabel(TargetElement target) { 535 void implicitBreakWithLabel(TargetElement target) {
530 addIndented("break "); 536 addIndented("break ");
531 writeImplicitLabel(target); 537 writeImplicitLabel(target);
532 buffer.add(";\n"); 538 buffer.add(";\n");
533 } 539 }
534 540
535 bool visitIfInfo(HIfBlockInformation info) { 541 bool visitIfInfo(HIfBlockInformation info) {
542 if (logicalOperations.contains(info.condition.end.last)) return false;
kasperl 2012/06/04 11:12:55 Add a comment that explains what this does.
ngeoffray 2012/06/04 11:37:54 Done.
536 HInstruction condition = info.condition.conditionExpression; 543 HInstruction condition = info.condition.conditionExpression;
537 if (condition.isConstant()) { 544 if (condition.isConstant()) {
538 // If the condition is constant, only generate one branch (if any). 545 // If the condition is constant, only generate one branch (if any).
539 HConstant constantCondition = condition; 546 HConstant constantCondition = condition;
540 Constant constant = constantCondition.constant; 547 Constant constant = constantCondition.constant;
541 generateStatements(info.condition); 548 generateStatements(info.condition);
542 if (constant.isTrue()) { 549 if (constant.isTrue()) {
543 generateStatements(info.thenGraph); 550 generateStatements(info.thenGraph);
544 } else if (info.elseGraph !== null) { 551 } else if (info.elseGraph !== null) {
545 generateStatements(info.elseGraph); 552 generateStatements(info.elseGraph);
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 while (!continueOverrides.isEmpty()) { 809 while (!continueOverrides.isEmpty()) {
803 continueAction.remove(continueOverrides.head); 810 continueAction.remove(continueOverrides.head);
804 continueOverrides = continueOverrides.tail; 811 continueOverrides = continueOverrides.tail;
805 } 812 }
806 } else { 813 } else {
807 breakAction.remove(labeledBlockInfo.target); 814 breakAction.remove(labeledBlockInfo.target);
808 } 815 }
809 return true; 816 return true;
810 } 817 }
811 818
812 void emitLogicalOperation(HPhi node, String operation) {
813 JSBinaryOperatorPrecedence operatorPrecedence =
814 JSPrecedence.binary[operation];
815 beginExpression(operatorPrecedence.precedence);
816 use(node.inputs[0], operatorPrecedence.left);
817 buffer.add(" $operation ");
818 use(node.inputs[1], operatorPrecedence.right);
819 endExpression(operatorPrecedence.precedence);
820 }
821
822 // Wraps a loop body in a block to make continues have a target to break 819 // Wraps a loop body in a block to make continues have a target to break
823 // to (if necessary). 820 // to (if necessary).
824 void wrapLoopBodyForContinue(HLoopBlockInformation info) { 821 void wrapLoopBodyForContinue(HLoopBlockInformation info) {
825 TargetElement target = info.target; 822 TargetElement target = info.target;
826 if (target !== null && target.isContinueTarget) { 823 if (target !== null && target.isContinueTarget) {
827 addIndentation(); 824 addIndentation();
828 for (LabelElement label in info.labels) { 825 for (LabelElement label in info.labels) {
829 if (label.isContinueTarget) { 826 if (label.isContinueTarget) {
830 writeContinueLabel(label); 827 writeContinueLabel(label);
831 buffer.add(":"); 828 buffer.add(":");
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 buffer.add(' = '); 1002 buffer.add(' = ');
1006 use(copy.source, JSPrecedence.ASSIGNMENT_PRECEDENCE); 1003 use(copy.source, JSPrecedence.ASSIGNMENT_PRECEDENCE);
1007 if (!isGeneratingExpression()) { 1004 if (!isGeneratingExpression()) {
1008 buffer.add(';\n'); 1005 buffer.add(';\n');
1009 } 1006 }
1010 } 1007 }
1011 } 1008 }
1012 1009
1013 void iterateBasicBlock(HBasicBlock node) { 1010 void iterateBasicBlock(HBasicBlock node) {
1014 HInstruction instruction = node.first; 1011 HInstruction instruction = node.first;
1015 while (instruction != null) { 1012 while (instruction !== node.last) {
1016 if (instruction === node.last) { 1013 if (instruction is HTypeGuard) {
1017 assignPhisOfSuccessors(node);
1018 }
1019
1020 if (isGenerateAtUseSite(instruction)) {
1021 if (instruction is HIf) {
1022 HIf hif = instruction;
1023 // The "if" is implementing part of a logical expression.
1024 // Skip directly forward to to its latest successor, since everything
1025 // in-between must also be generateAtUseSite.
1026 assert(hif.trueBranch.id < hif.falseBranch.id);
1027 visitBasicBlock(hif.falseBranch);
1028 }
1029 } else if (instruction is HControlFlow) {
1030 if (instruction is HLoopBranch && isGeneratingExpression()) {
1031 addExpressionSeparator();
1032 }
1033 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 1014 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
1034 } else if (instruction is HTypeGuard) { 1015 } else if (!isGenerateAtUseSite(instruction)) {
1035 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
1036 } else {
1037 if (isGeneratingExpression()) {
1038 addExpressionSeparator();
1039 } else {
1040 addIndentation();
1041 }
1042 define(instruction); 1016 define(instruction);
1043 if (!isGeneratingExpression()) buffer.add(';\n');
1044 } 1017 }
1045 instruction = instruction.next; 1018 instruction = instruction.next;
1046 } 1019 }
1020 assignPhisOfSuccessors(node);
1021 if (instruction is HLoopBranch && isGeneratingExpression()) {
1022 addExpressionSeparator();
1023 }
1024 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
1047 } 1025 }
1048 1026
1049 visitInvokeBinary(HInvokeBinary node, String op) { 1027 visitInvokeBinary(HInvokeBinary node, String op) {
1050 if (node.builtin) { 1028 if (node.builtin) {
1051 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; 1029 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op];
1052 beginExpression(operatorPrecedences.precedence); 1030 beginExpression(operatorPrecedences.precedence);
1053 use(node.left, operatorPrecedences.left); 1031 use(node.left, operatorPrecedences.left);
1054 buffer.add(' $op '); 1032 buffer.add(' $op ');
1055 use(node.right, operatorPrecedences.right); 1033 use(node.right, operatorPrecedences.right);
1056 endExpression(operatorPrecedences.precedence); 1034 endExpression(operatorPrecedences.precedence);
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1256 compiler.internalError('visitTry should not be called', instruction: node); 1234 compiler.internalError('visitTry should not be called', instruction: node);
1257 } 1235 }
1258 1236
1259 bool isEmptyElse(HBasicBlock start, HBasicBlock end) { 1237 bool isEmptyElse(HBasicBlock start, HBasicBlock end) {
1260 if (start !== end) return false; 1238 if (start !== end) return false;
1261 if (start.last is !HGoto 1239 if (start.last is !HGoto
1262 || start.last is HBreak 1240 || start.last is HBreak
1263 || start.last is HContinue) { 1241 || start.last is HContinue) {
1264 return false; 1242 return false;
1265 } 1243 }
1266 HInstruction instruction = start.first;
1267 for (HInstruction instruction = start.first; 1244 for (HInstruction instruction = start.first;
1268 instruction != start.last; 1245 instruction != start.last;
1269 instruction = instruction.next) { 1246 instruction = instruction.next) {
1270 // Instructions generated at use site are okay because they do 1247 // Instructions generated at use site are okay because they do
1271 // not generate code in this else block. 1248 // not generate code in this else block.
1272 if (!isGenerateAtUseSite(instruction)) return false; 1249 if (!isGenerateAtUseSite(instruction)) return false;
1273 } 1250 }
1274 CopyHandler handler = variableNames.getCopyHandler(start); 1251 CopyHandler handler = variableNames.getCopyHandler(start);
1275 if (handler == null || handler.isEmpty()) return true; 1252 if (handler == null || handler.isEmpty()) return true;
1276 if (!handler.assignments.isEmpty()) return false; 1253 if (!handler.assignments.isEmpty()) return false;
1277 // If the block has a copy where the destination and source are 1254 // If the block has a copy where the destination and source are
1278 // different, we will emit that copy, and therefore the block is 1255 // different, we will emit that copy, and therefore the block is
1279 // not empty. 1256 // not empty.
1280 for (Copy copy in handler.copies) { 1257 for (Copy copy in handler.copies) {
1281 String sourceName = variableNames.getName(copy.source); 1258 String sourceName = variableNames.getName(copy.source);
1282 String destinationName = variableNames.getName(copy.destination); 1259 String destinationName = variableNames.getName(copy.destination);
1283 if (sourceName != destinationName) return false; 1260 if (sourceName != destinationName) return false;
1284 } 1261 }
1285 return true; 1262 return true;
1286 } 1263 }
1287 1264
1288 visitIf(HIf node) { 1265 visitIf(HIf node) {
1289 if (subGraph !== null && node.block === subGraph.end) { 1266 if (logicalOperations.contains(node)) {
1267 HPhi phi = node.joinBlock.phis.first;
1268 if (!isGenerateAtUseSite(phi)) define(phi);
1269 visitBasicBlock(node.joinBlock);
1270 return;
kasperl 2012/06/04 11:12:55 Maybe get rid of the two returns and add the last
ngeoffray 2012/06/04 11:37:54 Removed the else if.
1271 } else if (subGraph !== null && node.block === subGraph.end) {
1290 if (isGeneratingExpression()) { 1272 if (isGeneratingExpression()) {
1291 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); 1273 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
1292 } 1274 }
1293 return; 1275 return;
1294 } 1276 }
1295 HInstruction condition = node.inputs[0]; 1277 HInstruction condition = node.inputs[0];
1296 int preVisitedBlocks = 0; 1278 int preVisitedBlocks = 0;
1297 List<HBasicBlock> dominated = node.block.dominatedBlocks; 1279 List<HBasicBlock> dominated = node.block.dominatedBlocks;
1298 HIfBlockInformation info = node.blockInformation.body; 1280 HIfBlockInformation info = node.blockInformation.body;
1299 HBasicBlock joinBlock = node.joinBlock; 1281 HBasicBlock joinBlock = node.joinBlock;
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1580 visitBasicBlock(branchBlock.successors[1]); 1562 visitBasicBlock(branchBlock.successors[1]);
1581 // With labeled breaks we can have more dominated blocks. 1563 // With labeled breaks we can have more dominated blocks.
1582 if (dominated.length >= 3) { 1564 if (dominated.length >= 3) {
1583 for (int i = 2; i < dominated.length; i++) { 1565 for (int i = 2; i < dominated.length; i++) {
1584 visitBasicBlock(dominated[i]); 1566 visitBasicBlock(dominated[i]);
1585 } 1567 }
1586 } 1568 }
1587 } 1569 }
1588 1570
1589 visitNot(HNot node) { 1571 visitNot(HNot node) {
1572 assert(node.inputs.length == 1);
1573 generateNot(node.inputs[0]);
1574 }
1575
1576
1577 void generateNot(HInstruction input) {
1590 bool isBuiltinRelational(HInstruction instruction) { 1578 bool isBuiltinRelational(HInstruction instruction) {
1591 if (instruction is !HRelational) return false; 1579 if (instruction is !HRelational) return false;
1592 HRelational relational = instruction; 1580 HRelational relational = instruction;
1593 return relational.builtin; 1581 return relational.builtin;
1594 } 1582 }
1595 1583
1596 assert(node.inputs.length == 1);
1597 HInstruction input = node.inputs[0];
1598 if (input is HBoolify && isGenerateAtUseSite(input)) { 1584 if (input is HBoolify && isGenerateAtUseSite(input)) {
1599 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); 1585 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1600 assert(node.inputs.length == 1);
1601 use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE); 1586 use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE);
1602 buffer.add(' !== true'); 1587 buffer.add(' !== true');
1603 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); 1588 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1604 } else if (isBuiltinRelational(input) && 1589 } else if (isBuiltinRelational(input) &&
1605 isGenerateAtUseSite(input) && 1590 isGenerateAtUseSite(input) &&
1606 input.inputs[0].propagatedType.isUseful() && 1591 input.inputs[0].propagatedType.isUseful() &&
1607 !input.inputs[0].isDouble() && 1592 !input.inputs[0].isDouble() &&
1608 input.inputs[1].propagatedType.isUseful() && 1593 input.inputs[1].propagatedType.isUseful() &&
1609 !input.inputs[1].isDouble()) { 1594 !input.inputs[1].isDouble()) {
1610 // This optimization doesn't work for NaN, so we only do it if the 1595 // This optimization doesn't work for NaN, so we only do it if the
(...skipping 18 matching lines...) Expand all
1629 endExpression(JSPrecedence.PREFIX_PRECEDENCE); 1614 endExpression(JSPrecedence.PREFIX_PRECEDENCE);
1630 } 1615 }
1631 } 1616 }
1632 1617
1633 visitParameterValue(HParameterValue node) { 1618 visitParameterValue(HParameterValue node) {
1634 assert(isGenerateAtUseSite(node)); 1619 assert(isGenerateAtUseSite(node));
1635 buffer.add(variableNames.getName(node)); 1620 buffer.add(variableNames.getName(node));
1636 } 1621 }
1637 1622
1638 visitPhi(HPhi node) { 1623 visitPhi(HPhi node) {
1639 String operation = logicalOperations[node]; 1624 HBasicBlock ifBlock = node.block.predecessors[0].predecessors[0];
1640 if (operation !== null) { 1625 // A phi can be generated at use site only if it is the result of a
1641 emitLogicalOperation(node, operation); 1626 // logical operation.
Lasse Reichstein Nielsen 2012/06/04 11:09:22 Is this method only called for phis that are gener
ngeoffray 2012/06/04 11:37:54 Done.
1627 assert(logicalOperations.contains(ifBlock.last));
1628 HInstruction input = ifBlock.last.inputs[0];
1629 if (input.isConstantFalse()) {
1630 use(node.inputs[1], JSPrecedence.EXPRESSION_PRECEDENCE);
Lasse Reichstein Nielsen 2012/06/04 11:09:22 You should pass expectedPrecedence as second argum
ngeoffray 2012/06/04 11:37:54 Done.
1631 } else if (input.isConstantTrue()) {
1632 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
1642 } else { 1633 } else {
1643 buffer.add('${variableNames.getName(node)}'); 1634 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||';
1635 JSBinaryOperatorPrecedence operatorPrecedence =
1636 JSPrecedence.binary[operation];
1637 beginExpression(operatorPrecedence.precedence);
1638 if (operation == '||') {
1639 if (input is HNot) {
1640 use(input.inputs[0], operatorPrecedence.left);
1641 } else {
1642 generateNot(input);
1643 }
1644 } else {
1645 use(input, operatorPrecedence.left);
1646 }
1647 buffer.add(" $operation ");
1648 use(node.inputs[0], operatorPrecedence.right);
1649 endExpression(operatorPrecedence.precedence);
1644 } 1650 }
1645 } 1651 }
1646 1652
1647 visitReturn(HReturn node) { 1653 visitReturn(HReturn node) {
1648 addIndentation(); 1654 addIndentation();
1649 assert(node.inputs.length == 1); 1655 assert(node.inputs.length == 1);
1650 HInstruction input = node.inputs[0]; 1656 HInstruction input = node.inputs[0];
1651 if (input.isConstantNull()) { 1657 if (input.isConstantNull()) {
1652 buffer.add('return;\n'); 1658 buffer.add('return;\n');
1653 } else { 1659 } else {
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after
2505 startBailoutSwitch(); 2511 startBailoutSwitch();
2506 } 2512 }
2507 } 2513 }
2508 2514
2509 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { 2515 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
2510 if (labeledBlockInfo.body.start.hasGuards()) { 2516 if (labeledBlockInfo.body.start.hasGuards()) {
2511 endBailoutSwitch(); 2517 endBailoutSwitch();
2512 } 2518 }
2513 } 2519 }
2514 } 2520 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698