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

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

Issue 10440087: Compute liveness of instructions to get better and fewer variable names. (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 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 * or possibly several comma-separated expressions. 134 * or possibly several comma-separated expressions.
135 * - [TYPE_DECLARATION] means that the graph can be generated as an 135 * - [TYPE_DECLARATION] means that the graph can be generated as an
136 * expression, and that it only generates expressions of the form 136 * expression, and that it only generates expressions of the form
137 * variable = expression 137 * variable = expression
138 * which are also valid as parts of a "var" declaration. 138 * which are also valid as parts of a "var" declaration.
139 */ 139 */
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 static final String TEMPORARY_PREFIX = 't';
145
146 final JavaScriptBackend backend; 144 final JavaScriptBackend backend;
147 final WorkItem work; 145 final WorkItem work;
148 final StringBuffer buffer; 146 final StringBuffer buffer;
149 final String parameters; 147 final String parameters;
150 148
151 final Map<Element, String> parameterNames;
152 final Map<int, String> names;
153 final Set<String> usedNames;
154 final Set<HInstruction> declaredInstructions;
155 final Map<String, int> prefixes;
156 final Set<HInstruction> generateAtUseSite; 149 final Set<HInstruction> generateAtUseSite;
157 final Map<HPhi, String> logicalOperations; 150 final Map<HPhi, String> logicalOperations;
158 final Map<Element, ElementAction> breakAction; 151 final Map<Element, ElementAction> breakAction;
159 final Map<Element, ElementAction> continueAction; 152 final Map<Element, ElementAction> continueAction;
160 final Equivalence<HPhi> phiEquivalence; 153 final Map<Element, String> parameterNames;
154
155 /**
156 * Contains the names of the instructions, as well as the parallel
157 * copies to perform on block transitioning.
158 */
159 VariableNames variableNames;
160
161 /**
162 * While generating expressions, we can't insert variable declarations.
163 * Instead we declare them at the end of the function
164 */
165 final List<String> delayedVariablesDeclaration;
166
167 /**
168 * Set of variables that have already been declared.
169 */
170 final Set<String> declaredVariables;
161 171
162 Element equalsNullElement; 172 Element equalsNullElement;
163 Element boolifiedEqualsNullElement; 173 Element boolifiedEqualsNullElement;
164 int indent = 0; 174 int indent = 0;
165 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; 175 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE;
166 JSBinaryOperatorPrecedence unsignedShiftPrecedences; 176 JSBinaryOperatorPrecedence unsignedShiftPrecedences;
167 HGraph currentGraph; 177 HGraph currentGraph;
168 /** 178 /**
169 * Whether the code-generation should try to generate an expression 179 * Whether the code-generation should try to generate an expression
170 * instead of a sequence of statements. 180 * instead of a sequence of statements.
171 */ 181 */
172 int generationState = STATE_STATEMENT; 182 int generationState = STATE_STATEMENT;
173 /**
174 * While generating expressions, we can't insert variable declarations.
175 * Instead we declare them at the end of the function
176 */
177 Link<String> delayedVarDecl = const EmptyLink<String>();
178 HBasicBlock currentBlock; 183 HBasicBlock currentBlock;
179 184
180 // Records a block-information that is being handled specially. 185 // Records a block-information that is being handled specially.
181 // Used to break bad recursion. 186 // Used to break bad recursion.
182 HBlockInformation currentBlockInformation; 187 HBlockInformation currentBlockInformation;
183 // The subgraph is used to delimit traversal for some constructions, e.g., 188 // The subgraph is used to delimit traversal for some constructions, e.g.,
184 // if branches. 189 // if branches.
185 SubGraph subGraph; 190 SubGraph subGraph;
186 191
187 LibraryElement get currentLibrary() => work.element.getLibrary(); 192 LibraryElement get currentLibrary() => work.element.getLibrary();
188 Compiler get compiler() => backend.compiler; 193 Compiler get compiler() => backend.compiler;
189 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; 194 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter;
190 Enqueuer get world() => backend.compiler.enqueuer.codegen; 195 Enqueuer get world() => backend.compiler.enqueuer.codegen;
191 196
192 bool isGenerateAtUseSite(HInstruction instruction) { 197 bool isGenerateAtUseSite(HInstruction instruction) {
193 return generateAtUseSite.contains(instruction); 198 return generateAtUseSite.contains(instruction);
194 } 199 }
195 200
196 SsaCodeGenerator(this.backend, 201 SsaCodeGenerator(this.backend,
197 this.work, 202 this.work,
198 this.parameters, 203 this.parameters,
199 this.parameterNames) 204 this.parameterNames)
200 : names = new Map<int, String>(), 205 : declaredVariables = new Set<String>(),
201 prefixes = new Map<String, int>(), 206 delayedVariablesDeclaration = new List<String>(),
202 usedNames = new Set<String>(),
203 declaredInstructions = new Set<HInstruction>(),
204 buffer = new StringBuffer(), 207 buffer = new StringBuffer(),
205 generateAtUseSite = new Set<HInstruction>(), 208 generateAtUseSite = new Set<HInstruction>(),
206 logicalOperations = new Map<HPhi, String>(), 209 logicalOperations = new Map<HPhi, String>(),
207 breakAction = new Map<Element, ElementAction>(), 210 breakAction = new Map<Element, ElementAction>(),
208 continueAction = new Map<Element, ElementAction>(), 211 continueAction = new Map<Element, ElementAction>(),
209 phiEquivalence = new Equivalence<HPhi>(),
210 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { 212 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] {
211 213
212 for (final name in parameterNames.getValues()) {
213 prefixes[name] = 0;
214 }
215
216 // Create a namespace for temporaries.
217 prefixes[TEMPORARY_PREFIX] = 0;
218
219 Interceptors interceptors = backend.builder.interceptors; 214 Interceptors interceptors = backend.builder.interceptors;
220 equalsNullElement = interceptors.getEqualsNullInterceptor(); 215 equalsNullElement = interceptors.getEqualsNullInterceptor();
221 boolifiedEqualsNullElement = 216 boolifiedEqualsNullElement =
222 interceptors.getBoolifiedVersionOf(equalsNullElement); 217 interceptors.getBoolifiedVersionOf(equalsNullElement);
223 } 218 }
224 219
225 abstract visitTypeGuard(HTypeGuard node); 220 abstract visitTypeGuard(HTypeGuard node);
226 221
227 abstract beginGraph(HGraph graph); 222 abstract beginGraph(HGraph graph);
228 abstract endGraph(HGraph graph); 223 abstract endGraph(HGraph graph);
(...skipping 22 matching lines...) Expand all
251 void endExpression(int precedence) { 246 void endExpression(int precedence) {
252 if (precedence < expectedPrecedence) { 247 if (precedence < expectedPrecedence) {
253 buffer.add(')'); 248 buffer.add(')');
254 } 249 }
255 } 250 }
256 251
257 void preGenerateMethod(HGraph graph) { 252 void preGenerateMethod(HGraph graph) {
258 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); 253 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
259 new SsaConditionMerger(generateAtUseSite, 254 new SsaConditionMerger(generateAtUseSite,
260 logicalOperations).visitGraph(graph); 255 logicalOperations).visitGraph(graph);
261 new PhiEquivalator(phiEquivalence, logicalOperations).analyzeGraph(graph); 256 SsaLiveIntervalBuilder intervalBuilder =
257 new SsaLiveIntervalBuilder(compiler);
258 intervalBuilder.visitGraph(graph);
259 SsaVariableAllocator allocator = new SsaVariableAllocator(
260 compiler,
261 intervalBuilder.liveInstructions,
262 intervalBuilder.liveIntervals,
263 generateAtUseSite);
264 allocator.visitGraph(graph);
265 variableNames = allocator.names;
262 } 266 }
263 267
264 visitGraph(HGraph graph) { 268 visitGraph(HGraph graph) {
265 preGenerateMethod(graph); 269 preGenerateMethod(graph);
266 currentGraph = graph; 270 currentGraph = graph;
267 indent++; // We are already inside a function. 271 indent++; // We are already inside a function.
268 subGraph = new SubGraph(graph.entry, graph.exit); 272 subGraph = new SubGraph(graph.entry, graph.exit);
269 beginGraph(graph); 273 beginGraph(graph);
270 visitBasicBlock(graph.entry); 274 visitBasicBlock(graph.entry);
271 if (!delayedVarDecl.isEmpty()) { 275 if (!delayedVariablesDeclaration.isEmpty()) {
272 addIndented("var "); 276 addIndented("var ");
273 while (true) { 277 buffer.add(Strings.join(delayedVariablesDeclaration, ', '));
274 buffer.add(delayedVarDecl.head);
275 delayedVarDecl = delayedVarDecl.tail;
276 if (delayedVarDecl.isEmpty()) break;
277 buffer.add(", ");
278 }
279 buffer.add(";\n"); 278 buffer.add(";\n");
280 } 279 }
281 endGraph(graph); 280 endGraph(graph);
282 } 281 }
283 282
284 void visitSubGraph(SubGraph newSubGraph) { 283 void visitSubGraph(SubGraph newSubGraph) {
285 SubGraph oldSubGraph = subGraph; 284 SubGraph oldSubGraph = subGraph;
286 subGraph = newSubGraph; 285 subGraph = newSubGraph;
287 visitBasicBlock(subGraph.start); 286 visitBasicBlock(subGraph.start);
288 subGraph = oldSubGraph; 287 subGraph = oldSubGraph;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 int oldState = generationState; 405 int oldState = generationState;
407 generationState = STATE_FIRST_DECLARATION; 406 generationState = STATE_FIRST_DECLARATION;
408 visitSubGraph(expressionSubGraph.subExpression); 407 visitSubGraph(expressionSubGraph.subExpression);
409 generationState = oldState; 408 generationState = oldState;
410 } 409 }
411 410
412 void generateCondition(HBlockInformation condition) { 411 void generateCondition(HBlockInformation condition) {
413 generateExpression(condition); 412 generateExpression(condition);
414 } 413 }
415 414
416 String temporary(HInstruction instruction) {
417 int id = instruction.id;
418 String name = names[id];
419 if (name !== null) return name;
420
421 String prefix = TEMPORARY_PREFIX;
422 if (instruction.sourceElement !== null) {
423 Element element = instruction.sourceElement;
424 if (element !== null && !element.name.isEmpty()) {
425 prefix = element.name.slowToString();
426 // Special case the variable named [TEMPORARY_PREFIX] to allow
427 // keeping its name.
428 if (prefix == TEMPORARY_PREFIX && !usedNames.contains(prefix)) {
429 return newName(id, prefix);
430 }
431 // If we've never seen that prefix before, try to use it
432 // directly.
433 if (!prefixes.containsKey(prefix)) {
434 // Make sure the variable name does not conflict with our mangling.
435 while (usedNames.contains(prefix)) {
436 prefix = '${prefix}_';
437 }
438 prefixes[prefix] = 0;
439 return newName(id, prefix);
440 }
441 }
442 }
443
444 name = '${prefix}${prefixes[prefix]++}';
445 while (usedNames.contains(name)) {
446 name = '${prefix}${prefixes[prefix]++}';
447 }
448 return newName(id, name);
449 }
450
451 // TODO(floitsch): share more code with [temporary].
452 String freshTemporary() {
453 String prefix = TEMPORARY_PREFIX;
454 String name = '${prefix}${prefixes[prefix]++}';
455 while (usedNames.contains(name)) {
456 name = '${prefix}${prefixes[prefix]++}';
457 }
458 String result = JsNames.getValid(name);
459 usedNames.add(result);
460 return result;
461 }
462
463 String newName(int id, String name) {
464 String result = JsNames.getValid(name);
465 names[id] = result;
466 usedNames.add(result);
467 return result;
468 }
469
470 /** 415 /**
471 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. 416 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
472 */ 417 */
473 void visitArguments(List<HInstruction> inputs) { 418 void visitArguments(List<HInstruction> inputs) {
474 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); 419 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET);
475 buffer.add('('); 420 buffer.add('(');
476 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { 421 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) {
477 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); 422 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', ');
478 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); 423 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
479 } 424 }
(...skipping 14 matching lines...) Expand all
494 bool isGeneratingDeclaration() { 439 bool isGeneratingDeclaration() {
495 return (generationState == STATE_DECLARATION || 440 return (generationState == STATE_DECLARATION ||
496 generationState == STATE_FIRST_DECLARATION); 441 generationState == STATE_FIRST_DECLARATION);
497 } 442 }
498 443
499 /** 444 /**
500 * Called before writing an expression. 445 * Called before writing an expression.
501 * Ensures that expressions are comma spearated. 446 * Ensures that expressions are comma spearated.
502 */ 447 */
503 void addExpressionSeparator() { 448 void addExpressionSeparator() {
504 if (generationState == STATE_FIRST_DECLARATION) { 449 if (generationState == STATE_FIRST_EXPRESSION) {
505 buffer.add("var ");
506 generationState = STATE_DECLARATION;
507 } else if (generationState == STATE_FIRST_EXPRESSION) {
508 generationState = STATE_EXPRESSION; 450 generationState = STATE_EXPRESSION;
509 } else { 451 } else if (generationState != STATE_FIRST_DECLARATION) {
510 buffer.add(", "); 452 buffer.add(", ");
511 } 453 }
454 // If the state is [STATE_FIRST_DECLARATION] the potential
455 // declaration of the variable will be done by the instruction.
456 }
457
458 bool isVariableDeclared(String variableName) {
459 return declaredVariables.contains(variableName);
512 } 460 }
513 461
514 void declareVariable(String variableName) { 462 void declareVariable(String variableName) {
515 if (isGeneratingExpression()) { 463 if (isGeneratingExpression()) {
516 buffer.add(variableName); 464 if (generationState == STATE_FIRST_DECLARATION) {
517 if (!isGeneratingDeclaration()) { 465 generationState = STATE_DECLARATION;
518 delayedVarDecl = delayedVarDecl.prepend(variableName); 466 if (!isVariableDeclared(variableName)) {
467 declaredVariables.add(variableName);
468 buffer.add("var ");
469 }
470 } else if (!isGeneratingDeclaration()
471 && !isVariableDeclared(variableName)) {
472 delayedVariablesDeclaration.add(variableName);
519 } 473 }
520 } else { 474 } else if (!isVariableDeclared(variableName)) {
475 declaredVariables.add(variableName);
521 buffer.add("var "); 476 buffer.add("var ");
522 buffer.add(variableName);
523 } 477 }
478 buffer.add(variableName);
524 } 479 }
525 480
526 void declareInstruction(HInstruction instruction) { 481 void declareInstruction(HInstruction instruction) {
527 declaredInstructions.add(instruction); 482 declareVariable(variableNames.getName(instruction));
528 String name = temporary(instruction);
529 declareVariable(name);
530 }
531
532 bool needsNewVariable(HInstruction instruction) {
533 bool needsVar = !instruction.usedBy.isEmpty();
534 if (needsVar && instruction is HCheck) {
535 HCheck check = instruction;
536 HInstruction input = check.checkedInput;
537 // We only need a new var if [input] is generated at use site
538 // but is not a trivial code motion invariant instruction like
539 // for parameters or this.
540 //
541 // For example:
542 // Foo a = this;
543 // print(a);
544 // print(a);
545 //
546 // In checked mode no new variable is needed.
547 // FooTypeCheck(this);
548 // print(this);
549 // print(this);
550 //
551 // But for this example:
552 // Foo a = foo();
553 // print(a);
554 // print(a);
555 //
556 // We need a new variable:
557 // var a = FooTypeCheck(foo());
558 // print(a);
559 // print(a);
560 needsVar = isGenerateAtUseSite(input) && !input.isCodeMotionInvariant();
561 }
562 return needsVar;
563 } 483 }
564 484
565 void define(HInstruction instruction) { 485 void define(HInstruction instruction) {
566 if (needsNewVariable(instruction)) { 486 if (instruction is !HCheck && variableNames.hasName(instruction)) {
567 declareInstruction(instruction); 487 declareInstruction(instruction);
568 buffer.add(" = "); 488 buffer.add(" = ");
569 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); 489 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
570 } else { 490 } else {
571 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 491 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
572 } 492 }
573 } 493 }
574 494
575 void use(HInstruction argument, int expectedPrecedenceForArgument) { 495 void use(HInstruction argument, int expectedPrecedenceForArgument) {
576 if (argument is HCheck) { 496 if (isGenerateAtUseSite(argument)) {
577 HCheck instruction = argument;
578 HInstruction input = instruction.checkedInput;
579 if (isGenerateAtUseSite(argument) && isGenerateAtUseSite(input)) {
580 // If both instructions can be generated at use site, we can
581 // just visit [argument].
582 //
583 // For example:
584 // Foo a = foo();
585 // print(a);
586 //
587 // In checked mode will turn into:
588 // print(FooTypeCheck(foo()));
589 visit(argument, expectedPrecedenceForArgument);
590 } else if (isGenerateAtUseSite(input)) {
591 // Get the real input of that checked instruction.
592 while (input is HCheck) {
593 HCheck check = input;
594 input = check.checkedInput;
595 }
596
597 // If [argument] cannot be generated at use site, but [input]
598 // can, use the temporary of [argument]. A code motion
599 // invariant instruction does not have a temporary, so we just
600 //
601 // For example:
602 // Foo a = foo();
603 // print(a);
604 // print(a);
605 //
606 // In checked mode will turn into:
607 // var a = FooTypeCheck(foo());
608 // print(a);
609 // print(a);
610 //
611 // Note that in case the input is code motion invariant, like
612 // for parameters or this, we just need to visit it, since
613 // there is no temporary for such instruction.
614 if (input.isCodeMotionInvariant()) {
615 visit(input, expectedPrecedenceForArgument);
616 } else {
617 buffer.add(temporary(argument));
618 }
619 } else {
620 // Otherwise we just use [input]. [argument] has already been
621 // emitted, and we just need the temporary of [input].
622 //
623 // For example:
624 // var a = foo();
625 // print(a);
626 // Foo b = a;
627 // print(b);
628 //
629 // In checked mode will turn into:
630 // var a = foo();
631 // print(a);
632 // FooTypeCheck(a);
633 // print(a);
634 use(input, expectedPrecedenceForArgument);
635 }
636 } else if (isGenerateAtUseSite(argument)) {
637 visit(argument, expectedPrecedenceForArgument); 497 visit(argument, expectedPrecedenceForArgument);
498 } else if (argument is HCheck) {
499 HCheck check = argument;
500 use(argument.checkedInput, expectedPrecedenceForArgument);
638 } else { 501 } else {
639 buffer.add(temporary(argument)); 502 buffer.add(variableNames.getName(argument));
640 } 503 }
641 } 504 }
642 505
643 visit(HInstruction node, int expectedPrecedenceForNode) { 506 visit(HInstruction node, int expectedPrecedenceForNode) {
644 int oldPrecedence = this.expectedPrecedence; 507 int oldPrecedence = this.expectedPrecedence;
645 this.expectedPrecedence = expectedPrecedenceForNode; 508 this.expectedPrecedence = expectedPrecedenceForNode;
646 node.accept(this); 509 node.accept(this);
647 this.expectedPrecedence = oldPrecedence; 510 this.expectedPrecedence = oldPrecedence;
648 } 511 }
649 512
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 580
718 bool visitTryInfo(HTryBlockInformation info) { 581 bool visitTryInfo(HTryBlockInformation info) {
719 addIndented("try {\n"); 582 addIndented("try {\n");
720 indent++; 583 indent++;
721 generateStatements(info.body); 584 generateStatements(info.body);
722 indent--; 585 indent--;
723 addIndented("}"); 586 addIndented("}");
724 if (info.catchBlock !== null) { 587 if (info.catchBlock !== null) {
725 // Printing the catch part. 588 // Printing the catch part.
726 HParameterValue exception = info.catchVariable; 589 HParameterValue exception = info.catchVariable;
727 String name = temporary(exception); 590 String name = variableNames.getName(exception);
728 parameterNames[exception.element] = name; 591 parameterNames[exception.element] = name;
729 buffer.add(' catch ($name) {\n'); 592 buffer.add(' catch ($name) {\n');
730 indent++; 593 indent++;
731 generateStatements(info.catchBlock); 594 generateStatements(info.catchBlock);
732 parameterNames.remove(exception.element); 595 parameterNames.remove(exception.element);
733 indent--; 596 indent--;
734 addIndented('}'); 597 addIndented('}');
735 } 598 }
736 if (info.finallyBlock != null) { 599 if (info.finallyBlock != null) {
737 buffer.add(" finally {\n"); 600 buffer.add(" finally {\n");
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 return; 881 return;
1019 } 882 }
1020 // Flow based traversal. 883 // Flow based traversal.
1021 if (node.isLoopHeader() && 884 if (node.isLoopHeader() &&
1022 node.loopInformation.loopBlockInformation !== currentBlockInformation) { 885 node.loopInformation.loopBlockInformation !== currentBlockInformation) {
1023 beginLoop(node); 886 beginLoop(node);
1024 } 887 }
1025 iterateBasicBlock(node); 888 iterateBasicBlock(node);
1026 } 889 }
1027 890
1028 /** Generates the assignments for all phis of successors blocks. */ 891 void emitAssignment(String destination, String source) {
1029 void assignPhisOfAllSuccessors(HBasicBlock node) { 892 if (isGeneratingExpression()) {
1030 Map<HInstruction, String> temporaryNamesOfPhis = null; 893 addExpressionSeparator();
894 } else {
895 addIndentation();
896 }
897 declareVariable(destination);
898 buffer.add(' = $source');
899 if (!isGeneratingExpression()) {
900 buffer.add(';\n');
901 }
902 }
1031 903
1032 /** 904 /**
1033 * Generates the assignment [canonicalPhi] = [value]. 905 * Sequentialize a list of conceptually parallel copies. Parallel
1034 * 906 * copies may contain cycles, that this method breaks.
1035 * If the [canonicalPhi] has a temporary name (in [temporaryNamesOfPhis]) 907 */
1036 * then the temporary is assigned instead of the [canonicalPhi]. However, 908 void sequentializeCopies(List<Copy> copies) {
1037 * when the left and right-hand side are equal ([:canonicalPhi === value:]) 909 // Map to keep track of the current location (ie the variable that
1038 * then the [canonicalPhi] is assigned with the temporary. 910 // holds the initial value) of a variable.
1039 */ 911 Map<String, String> currentLocation = new Map<String, String>();
1040 void generateAssignment(HPhi canonicalPhi, HInstruction value) { 912
913 // Map to keep track of the initial value of a variable.
914 Map<String, String> initialValue = new Map<String, String>();
915
916 // List of variables to assign a value.
917 List<String> worklist = <String>[];
918
919 // List of variables that we can assign a value to (ie are not
920 // being used anymore).
921 List<String> ready = <String>[];
922
923 // Prune [copies] by removing self-copies.
924 List<Copy> prunedCopies = <Copy>[];
925 for (Copy copy in copies) {
926 String sourceName = variableNames.getName(copy.source);
927 String destinationName = variableNames.getName(copy.destination);
928 if (sourceName != destinationName) {
929 prunedCopies.add(new Copy(sourceName, destinationName));
930 }
931 }
932 copies = prunedCopies;
933
934
935 // For each copy, set the current location of the source to
936 // itself, and the initial value of the destination to the source.
937 // Add the destination to the list of copies to make.
938 for (Copy copy in copies) {
939 currentLocation[copy.source] = copy.source;
940 initialValue[copy.destination] = copy.source;
941 worklist.add(copy.destination);
942 }
943
944 // For each copy, if the destination does not have a current
945 // location, then we can safely assign to it.
946 for (Copy copy in copies) {
947 if (currentLocation[copy.destination] === null) {
948 ready.add(copy.destination);
949 }
950 }
951
952 while (!worklist.isEmpty()) {
953 while (!ready.isEmpty()) {
954 String destination = ready.removeLast();
955 String source = initialValue[destination];
956 // Since [source] might have been updated, use the current
957 // location of [source]
958 String copy = currentLocation[source];
959 emitAssignment(destination, copy);
960 // Now [destination] is the current location of [source].
961 currentLocation[source] = destination;
962 // If [source] hasn't been updated and needs to have a value,
963 // add it to the list of variables that can be updated. Copies
964 // of [source] will now use [destination].
965 if (source == copy && initialValue[source] !== null) {
966 ready.add(source);
967 }
968 }
969
970 // Check if we have a cycle.
971 String current = worklist.removeLast();
972 // If [current] is used as a source, and the assignment has been
973 // done, we are done with this variable. Otherwise there is a
974 // cycle that we break by using a temporary name.
975 if (currentLocation[current] !== null
976 && current != currentLocation[initialValue[current]]) {
977 String tempName = VariableNames.SWAP_TEMP;
978 emitAssignment(tempName, current);
979 currentLocation[current] = tempName;
980 // [current] can now be safely updated. Copies of [current]
981 // will now use [tempName].
982 ready.add(current);
983 }
984 }
985 }
986
987 void assignPhisOfSuccessors(HBasicBlock node) {
988 CopyHandler handler = variableNames.getCopyHandler(node);
989 if (handler == null) return;
990
991 sequentializeCopies(handler.copies);
992
993 for (Copy copy in handler.assignments) {
1041 if (isGeneratingExpression()) { 994 if (isGeneratingExpression()) {
1042 addExpressionSeparator(); 995 addExpressionSeparator();
1043 } else { 996 } else {
1044 addIndentation(); 997 addIndentation();
1045 } 998 }
1046 if (temporaryNamesOfPhis !== null && 999 declareVariable(variableNames.getName(copy.destination));
1047 canonicalPhi !== value && 1000 buffer.add(' = ');
1048 temporaryNamesOfPhis.containsKey(canonicalPhi)) { 1001 use(copy.source, JSPrecedence.ASSIGNMENT_PRECEDENCE);
1049 // This is the assignment to the temporary.
1050 declareVariable(temporaryNamesOfPhis[canonicalPhi]);
1051 } else if (!declaredInstructions.contains(canonicalPhi)) {
1052 declareInstruction(canonicalPhi);
1053 } else {
1054 buffer.add(temporary(canonicalPhi));
1055 }
1056 buffer.add(" = ");
1057 bool isLogicalOperation = logicalOperations.containsKey(canonicalPhi);
1058 if (isLogicalOperation) {
1059 emitLogicalOperation(canonicalPhi, logicalOperations[canonicalPhi]);
1060 } else if (canonicalPhi === value) {
1061 buffer.add(temporaryNamesOfPhis[value]);
1062 } else {
1063 use(value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
1064 }
1065 if (!isGeneratingExpression()) { 1002 if (!isGeneratingExpression()) {
1066 buffer.add(';\n'); 1003 buffer.add(';\n');
1067 } 1004 }
1068 } 1005 }
1069
1070 // Assignments are delayed so that we don't overwrite phis that might
1071 // be used as inputs.
1072 // TODO(floitsch): improve phi assignments. Currently we introduce
1073 // way too many temporary variables.
1074 Map<HPhi, HInstruction> phiAssignments = new Map<HPhi, HInstruction>();
1075
1076 for (HBasicBlock successor in node.successors) {
1077 int index = successor.predecessors.indexOf(node);
1078 successor.forEachPhi((HPhi phi) {
1079 bool isLogicalOperation = logicalOperations.containsKey(phi);
1080 // In case the phi is being generated by another
1081 // instruction.
1082 if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
1083 HPhi canonicalPhi = phiEquivalence.getRepresentative(phi);
1084 assert(!isLogicalOperation || canonicalPhi === phi);
1085 HInstruction input = phi.inputs[index];
1086 if (input is HPhi) {
1087 input = phiEquivalence.getRepresentative(input);
1088 // If we use the same variable, we don't need to create an
1089 // assignment.
1090 if (input === canonicalPhi) {
1091 assert(!isLogicalOperation);
1092 return;
1093 }
1094 }
1095 phiAssignments[canonicalPhi] = input;
1096 });
1097 }
1098
1099 Set<HPhi> inputPhis = new Set<HPhi>();
1100 List<HPhi> phis = <HPhi>[];
1101
1102 /**
1103 * Transitively collects the phis that are used when emitting the [input]
1104 * and adds them to [inputPhis]. Does not add phis that are equal to the
1105 * [targetPhi] or are not in the [phiAssignments] map.
1106 */
1107 void collectInputPhis(HInstruction input, HPhi targetPhi) {
1108 if (input is HPhi) {
1109 HPhi canonicalPhi = phiEquivalence.getRepresentative(input);
1110 // Self-updates are ok.
1111 if (canonicalPhi !== targetPhi &&
1112 phiAssignments.containsKey(canonicalPhi)) {
1113 inputPhis.add(canonicalPhi);
1114 }
1115 } else if (isGenerateAtUseSite(input)) {
1116 for (HInstruction inputOfInput in input.inputs) {
1117 collectInputPhis(inputOfInput, targetPhi);
1118 }
1119 }
1120 }
1121
1122 phiAssignments.forEach((HPhi targetPhi, HInstruction input) {
1123 phis.add(targetPhi);
1124 collectInputPhis(input, targetPhi);
1125 });
1126
1127 if (inputPhis.isEmpty()) {
1128 phiAssignments.forEach(generateAssignment);
1129 } else {
1130 // Emit the phiX=phiY assignments, taking care to break cycles.
1131 // Example program:
1132 // var x = 499;
1133 // var y = 99;
1134 // while (x != 99) {
1135 // var tmp = x; // <=== The tmp variable is removed in Ssa-form.
1136 // x = y;
1137 // y = tmp;
1138 // }
1139 //
1140 temporaryNamesOfPhis = new HashMap<HInstruction, String>();
1141 // For phis that are used as inputs simply *always* allocate a
1142 // temporary.
1143 for (HPhi phi in phis) {
1144 if (inputPhis.contains(phi)) {
1145 String temporaryPhi = freshTemporary();
1146 temporaryNamesOfPhis[phi] = temporaryPhi;
1147 }
1148 // The assignPhi uses temporary variables for the left-hand side if
1149 // they exist.
1150 generateAssignment(phi, phiAssignments[phi]);
1151 }
1152 // Finally assign the input phis.
1153 for (HPhi phi in inputPhis) {
1154 // The assignPhi special-cases phi assignments to itself and recognizes
1155 // it as assignment from the temporary variable to the actual phi.
1156 generateAssignment(phi, phi);
1157 }
1158 }
1159 } 1006 }
1160 1007
1161 void iterateBasicBlock(HBasicBlock node) { 1008 void iterateBasicBlock(HBasicBlock node) {
1162 HInstruction instruction = node.first; 1009 HInstruction instruction = node.first;
1163 while (instruction != null) { 1010 while (instruction != null) {
1164 if (instruction === node.last) { 1011 if (instruction === node.last) {
1165 assignPhisOfAllSuccessors(node); 1012 assignPhisOfSuccessors(node);
1166 } 1013 }
1167 1014
1168 if (isGenerateAtUseSite(instruction)) { 1015 if (isGenerateAtUseSite(instruction)) {
1169 if (instruction is HIf) { 1016 if (instruction is HIf) {
1170 HIf hif = instruction; 1017 HIf hif = instruction;
1171 // The "if" is implementing part of a logical expression. 1018 // The "if" is implementing part of a logical expression.
1172 // Skip directly forward to to its latest successor, since everything 1019 // Skip directly forward to to its latest successor, since everything
1173 // in-between must also be generateAtUseSite. 1020 // in-between must also be generateAtUseSite.
1174 assert(hif.trueBranch.id < hif.falseBranch.id); 1021 assert(hif.trueBranch.id < hif.falseBranch.id);
1175 visitBasicBlock(hif.falseBranch); 1022 visitBasicBlock(hif.falseBranch);
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
1584 visitFieldSet(HFieldSet node) { 1431 visitFieldSet(HFieldSet node) {
1585 String name; 1432 String name;
1586 if (!node.isFromActivation()) { 1433 if (!node.isFromActivation()) {
1587 name = 1434 name =
1588 compiler.namer.instanceFieldName(currentLibrary, node.name); 1435 compiler.namer.instanceFieldName(currentLibrary, node.name);
1589 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1436 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1590 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); 1437 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
1591 buffer.add('.'); 1438 buffer.add('.');
1592 buffer.add(name); 1439 buffer.add(name);
1593 } else { 1440 } else {
1594 // TODO(ngeoffray): Remove the 'var' once we don't globally box
1595 // variables used in a try/catch.
1596 if (!isGeneratingExpression()) {
1597 buffer.add('var ');
1598 }
1599 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); 1441 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE);
1600 } 1442 }
1601 buffer.add(' = '); 1443 buffer.add(' = ');
1602 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); 1444 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
1603 if (node.receiver !== null) { 1445 if (node.receiver !== null) {
1604 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1446 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1605 } 1447 }
1606 } 1448 }
1607 1449
1608 visitForeign(HForeign node) { 1450 visitForeign(HForeign node) {
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1737 } else { 1579 } else {
1738 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); 1580 beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
1739 buffer.add('!'); 1581 buffer.add('!');
1740 use(input, JSPrecedence.PREFIX_PRECEDENCE); 1582 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1741 endExpression(JSPrecedence.PREFIX_PRECEDENCE); 1583 endExpression(JSPrecedence.PREFIX_PRECEDENCE);
1742 } 1584 }
1743 } 1585 }
1744 1586
1745 visitParameterValue(HParameterValue node) { 1587 visitParameterValue(HParameterValue node) {
1746 assert(isGenerateAtUseSite(node)); 1588 assert(isGenerateAtUseSite(node));
1747 if (parameterNames[node.element] == null) { 1589 buffer.add(variableNames.getName(node));
1748 buffer.add(temporary(node));
1749 } else {
1750 buffer.add(parameterNames[node.element]);
1751 }
1752 } 1590 }
1753 1591
1754 visitPhi(HPhi node) { 1592 visitPhi(HPhi node) {
1755 String operation = logicalOperations[node]; 1593 String operation = logicalOperations[node];
1756 if (operation !== null) { 1594 if (operation !== null) {
1757 emitLogicalOperation(node, operation); 1595 emitLogicalOperation(node, operation);
1758 } else { 1596 } else {
1759 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); 1597 buffer.add('${variableNames.getName(node)}');
1760 buffer.add('${temporary(canonicalPhi)}');
1761 } 1598 }
1762 } 1599 }
1763 1600
1764 visitReturn(HReturn node) { 1601 visitReturn(HReturn node) {
1765 addIndentation(); 1602 addIndentation();
1766 assert(node.inputs.length == 1); 1603 assert(node.inputs.length == 1);
1767 HInstruction input = node.inputs[0]; 1604 HInstruction input = node.inputs[0];
1768 if (input.isConstantNull()) { 1605 if (input.isConstantNull()) {
1769 buffer.add('return;\n'); 1606 buffer.add('return;\n');
1770 } else { 1607 } else {
(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after
2473 void visitTypeGuard(HTypeGuard node) { 2310 void visitTypeGuard(HTypeGuard node) {
2474 indent--; 2311 indent--;
2475 addIndented('case ${node.state}:\n'); 2312 addIndented('case ${node.state}:\n');
2476 indent++; 2313 indent++;
2477 addIndented('state = 0;\n'); 2314 addIndented('state = 0;\n');
2478 2315
2479 setup.add(' case ${node.state}:\n'); 2316 setup.add(' case ${node.state}:\n');
2480 int i = 0; 2317 int i = 0;
2481 for (HInstruction input in node.inputs) { 2318 for (HInstruction input in node.inputs) {
2482 HInstruction instruction = unwrap(input); 2319 HInstruction instruction = unwrap(input);
2483 setup.add(' ${temporary(instruction)} = env$i;\n'); 2320 setup.add(' ${variableNames.getName(instruction)} = env$i;\n');
2484 i++; 2321 i++;
2485 } 2322 }
2486 if (i > maxBailoutParameters) maxBailoutParameters = i; 2323 if (i > maxBailoutParameters) maxBailoutParameters = i;
2487 setup.add(' break;\n'); 2324 setup.add(' break;\n');
2488 } 2325 }
2489 2326
2490 void startBailoutCase(List<HTypeGuard> bailouts1, 2327 void startBailoutCase(List<HTypeGuard> bailouts1,
2491 List<HTypeGuard> bailouts2) { 2328 List<HTypeGuard> bailouts2) {
2492 indent--; 2329 indent--;
2493 handleBailoutCase(bailouts1); 2330 handleBailoutCase(bailouts1);
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2632 startBailoutSwitch(); 2469 startBailoutSwitch();
2633 } 2470 }
2634 } 2471 }
2635 2472
2636 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { 2473 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
2637 if (labeledBlockInfo.body.start.hasGuards()) { 2474 if (labeledBlockInfo.body.start.hasGuards()) {
2638 endBailoutSwitch(); 2475 endBailoutSwitch();
2639 } 2476 }
2640 } 2477 }
2641 } 2478 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/ssa/builder.dart ('k') | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698