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

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; 149 final Set<String> declaredVariables;
Lasse Reichstein Nielsen 2012/05/31 08:24:56 Can you add a doc-comment describing what this mea
ngeoffray 2012/05/31 08:48:22 Done.
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; 150 final Set<HInstruction> generateAtUseSite;
157 final Map<HPhi, String> logicalOperations; 151 final Map<HPhi, String> logicalOperations;
158 final Map<Element, ElementAction> breakAction; 152 final Map<Element, ElementAction> breakAction;
159 final Map<Element, ElementAction> continueAction; 153 final Map<Element, ElementAction> continueAction;
160 final Equivalence<HPhi> phiEquivalence; 154 final List<String> delayedVariablesDeclaration;
155 final Map<Element, String> parameterNames;
156 VariableNames variableNames;
Lasse Reichstein Nielsen 2012/05/31 08:24:56 And this one too, to explain the difference from t
ngeoffray 2012/05/31 08:48:22 Done.
161 157
162 Element equalsNullElement; 158 Element equalsNullElement;
163 Element boolifiedEqualsNullElement; 159 Element boolifiedEqualsNullElement;
164 int indent = 0; 160 int indent = 0;
165 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; 161 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE;
166 JSBinaryOperatorPrecedence unsignedShiftPrecedences; 162 JSBinaryOperatorPrecedence unsignedShiftPrecedences;
167 HGraph currentGraph; 163 HGraph currentGraph;
168 /** 164 /**
169 * Whether the code-generation should try to generate an expression 165 * Whether the code-generation should try to generate an expression
170 * instead of a sequence of statements. 166 * instead of a sequence of statements.
171 */ 167 */
172 int generationState = STATE_STATEMENT; 168 int generationState = STATE_STATEMENT;
173 /** 169 /**
174 * While generating expressions, we can't insert variable declarations. 170 * While generating expressions, we can't insert variable declarations.
175 * Instead we declare them at the end of the function 171 * Instead we declare them at the end of the function
floitsch 2012/05/30 18:45:03 Move this comment too.
ngeoffray 2012/05/31 08:12:46 Done.
176 */ 172 */
177 Link<String> delayedVarDecl = const EmptyLink<String>();
178 HBasicBlock currentBlock; 173 HBasicBlock currentBlock;
179 174
180 // Records a block-information that is being handled specially. 175 // Records a block-information that is being handled specially.
181 // Used to break bad recursion. 176 // Used to break bad recursion.
182 HBlockInformation currentBlockInformation; 177 HBlockInformation currentBlockInformation;
183 // The subgraph is used to delimit traversal for some constructions, e.g., 178 // The subgraph is used to delimit traversal for some constructions, e.g.,
184 // if branches. 179 // if branches.
185 SubGraph subGraph; 180 SubGraph subGraph;
186 181
187 LibraryElement get currentLibrary() => work.element.getLibrary(); 182 LibraryElement get currentLibrary() => work.element.getLibrary();
188 Compiler get compiler() => backend.compiler; 183 Compiler get compiler() => backend.compiler;
189 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; 184 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter;
190 Enqueuer get world() => backend.compiler.enqueuer.codegen; 185 Enqueuer get world() => backend.compiler.enqueuer.codegen;
191 186
192 bool isGenerateAtUseSite(HInstruction instruction) { 187 bool isGenerateAtUseSite(HInstruction instruction) {
193 return generateAtUseSite.contains(instruction); 188 return generateAtUseSite.contains(instruction);
194 } 189 }
195 190
196 SsaCodeGenerator(this.backend, 191 SsaCodeGenerator(this.backend,
197 this.work, 192 this.work,
198 this.parameters, 193 this.parameters,
199 this.parameterNames) 194 this.parameterNames)
200 : names = new Map<int, String>(), 195 : declaredVariables = new Set<String>(),
201 prefixes = new Map<String, int>(), 196 delayedVariablesDeclaration = new List<String>(),
202 usedNames = new Set<String>(),
203 declaredInstructions = new Set<HInstruction>(),
204 buffer = new StringBuffer(), 197 buffer = new StringBuffer(),
205 generateAtUseSite = new Set<HInstruction>(), 198 generateAtUseSite = new Set<HInstruction>(),
206 logicalOperations = new Map<HPhi, String>(), 199 logicalOperations = new Map<HPhi, String>(),
207 breakAction = new Map<Element, ElementAction>(), 200 breakAction = new Map<Element, ElementAction>(),
208 continueAction = new Map<Element, ElementAction>(), 201 continueAction = new Map<Element, ElementAction>(),
209 phiEquivalence = new Equivalence<HPhi>(),
210 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { 202 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] {
211 203
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; 204 Interceptors interceptors = backend.builder.interceptors;
220 equalsNullElement = interceptors.getEqualsNullInterceptor(); 205 equalsNullElement = interceptors.getEqualsNullInterceptor();
221 boolifiedEqualsNullElement = 206 boolifiedEqualsNullElement =
222 interceptors.getBoolifiedVersionOf(equalsNullElement); 207 interceptors.getBoolifiedVersionOf(equalsNullElement);
223 } 208 }
224 209
225 abstract visitTypeGuard(HTypeGuard node); 210 abstract visitTypeGuard(HTypeGuard node);
226 211
227 abstract beginGraph(HGraph graph); 212 abstract beginGraph(HGraph graph);
228 abstract endGraph(HGraph graph); 213 abstract endGraph(HGraph graph);
(...skipping 22 matching lines...) Expand all
251 void endExpression(int precedence) { 236 void endExpression(int precedence) {
252 if (precedence < expectedPrecedence) { 237 if (precedence < expectedPrecedence) {
253 buffer.add(')'); 238 buffer.add(')');
254 } 239 }
255 } 240 }
256 241
257 void preGenerateMethod(HGraph graph) { 242 void preGenerateMethod(HGraph graph) {
258 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); 243 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
259 new SsaConditionMerger(generateAtUseSite, 244 new SsaConditionMerger(generateAtUseSite,
260 logicalOperations).visitGraph(graph); 245 logicalOperations).visitGraph(graph);
261 new PhiEquivalator(phiEquivalence, logicalOperations).analyzeGraph(graph); 246 SsaLiveIntervalBuilder intervalBuilder =
floitsch 2012/05/30 18:45:03 new SsaLiveIntervalBuilder(compiler).visitGraph(gr
ngeoffray 2012/05/31 08:12:46 No, I need the object to take its liveInstructions
Lasse Reichstein Nielsen 2012/05/31 08:24:56 It's also used below.
247 new SsaLiveIntervalBuilder(compiler);
248 intervalBuilder.visitGraph(graph);
249 SsaVariableAllocator allocator = new SsaVariableAllocator(
250 compiler,
251 intervalBuilder.liveInstructions,
252 intervalBuilder.liveIntervals,
253 generateAtUseSite);
254 allocator.visitGraph(graph);
255 variableNames = allocator.names;
262 } 256 }
263 257
264 visitGraph(HGraph graph) { 258 visitGraph(HGraph graph) {
265 preGenerateMethod(graph); 259 preGenerateMethod(graph);
266 currentGraph = graph; 260 currentGraph = graph;
267 indent++; // We are already inside a function. 261 indent++; // We are already inside a function.
268 subGraph = new SubGraph(graph.entry, graph.exit); 262 subGraph = new SubGraph(graph.entry, graph.exit);
269 beginGraph(graph); 263 beginGraph(graph);
270 visitBasicBlock(graph.entry); 264 visitBasicBlock(graph.entry);
271 if (!delayedVarDecl.isEmpty()) { 265 if (!delayedVariablesDeclaration.isEmpty()) {
272 addIndented("var "); 266 addIndented("var ");
273 while (true) { 267 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"); 268 buffer.add(";\n");
280 } 269 }
281 endGraph(graph); 270 endGraph(graph);
282 } 271 }
283 272
284 void visitSubGraph(SubGraph newSubGraph) { 273 void visitSubGraph(SubGraph newSubGraph) {
285 SubGraph oldSubGraph = subGraph; 274 SubGraph oldSubGraph = subGraph;
286 subGraph = newSubGraph; 275 subGraph = newSubGraph;
287 visitBasicBlock(subGraph.start); 276 visitBasicBlock(subGraph.start);
288 subGraph = oldSubGraph; 277 subGraph = oldSubGraph;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 int oldState = generationState; 395 int oldState = generationState;
407 generationState = STATE_FIRST_DECLARATION; 396 generationState = STATE_FIRST_DECLARATION;
408 visitSubGraph(expressionSubGraph.subExpression); 397 visitSubGraph(expressionSubGraph.subExpression);
409 generationState = oldState; 398 generationState = oldState;
410 } 399 }
411 400
412 void generateCondition(HBlockInformation condition) { 401 void generateCondition(HBlockInformation condition) {
413 generateExpression(condition); 402 generateExpression(condition);
414 } 403 }
415 404
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 /** 405 /**
471 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. 406 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
472 */ 407 */
473 void visitArguments(List<HInstruction> inputs) { 408 void visitArguments(List<HInstruction> inputs) {
474 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); 409 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET);
475 buffer.add('('); 410 buffer.add('(');
476 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { 411 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) {
477 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); 412 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', ');
478 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); 413 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
479 } 414 }
(...skipping 15 matching lines...) Expand all
495 return (generationState == STATE_DECLARATION || 430 return (generationState == STATE_DECLARATION ||
496 generationState == STATE_FIRST_DECLARATION); 431 generationState == STATE_FIRST_DECLARATION);
497 } 432 }
498 433
499 /** 434 /**
500 * Called before writing an expression. 435 * Called before writing an expression.
501 * Ensures that expressions are comma spearated. 436 * Ensures that expressions are comma spearated.
502 */ 437 */
503 void addExpressionSeparator() { 438 void addExpressionSeparator() {
504 if (generationState == STATE_FIRST_DECLARATION) { 439 if (generationState == STATE_FIRST_DECLARATION) {
505 buffer.add("var "); 440 return;
kasperl 2012/05/31 05:26:03 Maybe change the structure so that you check for S
ngeoffray 2012/05/31 08:12:46 Done.
Lasse Reichstein Nielsen 2012/05/31 08:24:56 Why this change? Where do you change the state to
ngeoffray 2012/05/31 08:48:22 In declareVariable line 454. I need this change be
506 generationState = STATE_DECLARATION;
507 } else if (generationState == STATE_FIRST_EXPRESSION) { 441 } else if (generationState == STATE_FIRST_EXPRESSION) {
508 generationState = STATE_EXPRESSION; 442 generationState = STATE_EXPRESSION;
509 } else { 443 } else {
510 buffer.add(", "); 444 buffer.add(", ");
511 } 445 }
512 } 446 }
513 447
448 bool isVariableDeclared(String variableName) {
449 return declaredVariables.contains(variableName);
450 }
451
514 void declareVariable(String variableName) { 452 void declareVariable(String variableName) {
515 if (isGeneratingExpression()) { 453 if (isGeneratingExpression()) {
516 buffer.add(variableName); 454 if (generationState == STATE_FIRST_DECLARATION) {
517 if (!isGeneratingDeclaration()) { 455 generationState = STATE_DECLARATION;
518 delayedVarDecl = delayedVarDecl.prepend(variableName); 456 if (!isVariableDeclared(variableName)) {
457 declaredVariables.add(variableName);
458 buffer.add("var ");
floitsch 2012/05/30 18:45:03 The 'var' is emitted conditionally. This means tha
ngeoffray 2012/05/31 08:12:46 After the first declaration we must go into STATE_
459 }
460 } else if (!isGeneratingDeclaration()
461 && !isVariableDeclared(variableName)) {
462 delayedVariablesDeclaration.add(variableName);
519 } 463 }
520 } else { 464 } else if (!isVariableDeclared(variableName)) {
465 declaredVariables.add(variableName);
521 buffer.add("var "); 466 buffer.add("var ");
522 buffer.add(variableName);
523 } 467 }
468 buffer.add(variableName);
524 } 469 }
525 470
526 void declareInstruction(HInstruction instruction) { 471 void declareInstruction(HInstruction instruction) {
527 declaredInstructions.add(instruction); 472 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 } 473 }
564 474
565 void define(HInstruction instruction) { 475 void define(HInstruction instruction) {
566 if (needsNewVariable(instruction)) { 476 if (instruction is !HCheck && variableNames.hasName(instruction)) {
567 declareInstruction(instruction); 477 declareInstruction(instruction);
568 buffer.add(" = "); 478 buffer.add(" = ");
569 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); 479 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
570 } else { 480 } else {
571 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 481 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
572 } 482 }
573 } 483 }
574 484
575 void use(HInstruction argument, int expectedPrecedenceForArgument) { 485 void use(HInstruction argument, int expectedPrecedenceForArgument) {
576 if (argument is HCheck) { 486 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); 487 visit(argument, expectedPrecedenceForArgument);
488 } else if (argument is HCheck) {
489 HCheck check = argument;
490 use(argument.checkedInput, expectedPrecedenceForArgument);
638 } else { 491 } else {
639 buffer.add(temporary(argument)); 492 buffer.add(variableNames.getName(argument));
640 } 493 }
641 } 494 }
642 495
643 visit(HInstruction node, int expectedPrecedenceForNode) { 496 visit(HInstruction node, int expectedPrecedenceForNode) {
644 int oldPrecedence = this.expectedPrecedence; 497 int oldPrecedence = this.expectedPrecedence;
645 this.expectedPrecedence = expectedPrecedenceForNode; 498 this.expectedPrecedence = expectedPrecedenceForNode;
646 node.accept(this); 499 node.accept(this);
647 this.expectedPrecedence = oldPrecedence; 500 this.expectedPrecedence = oldPrecedence;
648 } 501 }
649 502
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 570
718 bool visitTryInfo(HTryBlockInformation info) { 571 bool visitTryInfo(HTryBlockInformation info) {
719 addIndented("try {\n"); 572 addIndented("try {\n");
720 indent++; 573 indent++;
721 generateStatements(info.body); 574 generateStatements(info.body);
722 indent--; 575 indent--;
723 addIndented("}"); 576 addIndented("}");
724 if (info.catchBlock !== null) { 577 if (info.catchBlock !== null) {
725 // Printing the catch part. 578 // Printing the catch part.
726 HParameterValue exception = info.catchVariable; 579 HParameterValue exception = info.catchVariable;
727 String name = temporary(exception); 580 String name = variableNames.getName(exception);
728 parameterNames[exception.element] = name; 581 parameterNames[exception.element] = name;
729 buffer.add(' catch ($name) {\n'); 582 buffer.add(' catch ($name) {\n');
730 indent++; 583 indent++;
731 generateStatements(info.catchBlock); 584 generateStatements(info.catchBlock);
732 parameterNames.remove(exception.element); 585 parameterNames.remove(exception.element);
733 indent--; 586 indent--;
734 addIndented('}'); 587 addIndented('}');
735 } 588 }
736 if (info.finallyBlock != null) { 589 if (info.finallyBlock != null) {
737 buffer.add(" finally {\n"); 590 buffer.add(" finally {\n");
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 return; 871 return;
1019 } 872 }
1020 // Flow based traversal. 873 // Flow based traversal.
1021 if (node.isLoopHeader() && 874 if (node.isLoopHeader() &&
1022 node.loopInformation.loopBlockInformation !== currentBlockInformation) { 875 node.loopInformation.loopBlockInformation !== currentBlockInformation) {
1023 beginLoop(node); 876 beginLoop(node);
1024 } 877 }
1025 iterateBasicBlock(node); 878 iterateBasicBlock(node);
1026 } 879 }
1027 880
1028 /** Generates the assignments for all phis of successors blocks. */ 881 void emitAssignment(String source, String destination) {
1029 void assignPhisOfAllSuccessors(HBasicBlock node) { 882 if (isGeneratingExpression()) {
1030 Map<HInstruction, String> temporaryNamesOfPhis = null; 883 addExpressionSeparator();
884 } else {
885 addIndentation();
886 }
887 declareVariable(destination);
888 buffer.add(' = $source');
889 if (!isGeneratingExpression()) {
890 buffer.add(';\n');
891 }
892 }
1031 893
1032 /** 894 /**
1033 * Generates the assignment [canonicalPhi] = [value]. 895 * Sequentialize a list of parallel copies.
Lasse Reichstein Nielsen 2012/05/31 08:24:56 Describe which criteria are being used to do the o
ngeoffray 2012/05/31 08:48:22 Added the 'conceptually'. As discussed, kept the '
1034 * 896 */
1035 * If the [canonicalPhi] has a temporary name (in [temporaryNamesOfPhis]) 897 void sequentializeCopies(List<Copy> copies) {
1036 * then the temporary is assigned instead of the [canonicalPhi]. However, 898 // Map to keep track of the current location of a variable.
1037 * when the left and right-hand side are equal ([:canonicalPhi === value:]) 899 Map<String, String> currentLocation = new Map<String, String>();
Lasse Reichstein Nielsen 2012/05/31 08:24:56 What is a "location" here?
ngeoffray 2012/05/31 08:48:22 It is a variable. It really is "the variable that
1038 * then the [canonicalPhi] is assigned with the temporary. 900
1039 */ 901 // Map to keep track of the initial value of a variable.
1040 void generateAssignment(HPhi canonicalPhi, HInstruction value) { 902 Map<String, String> initialValue = new Map<String, String>();
903
904 // List of variables to assign a value.
905 List<String> todo = <String>[];
Lasse Reichstein Nielsen 2012/05/31 08:24:56 "todo" -> "worklist".
ngeoffray 2012/05/31 08:48:22 Done.
906
907 // List of variables that we can assign a value to (ie are not
Lasse Reichstein Nielsen 2012/05/31 08:24:56 Describe which criteria are being used to do the o
ngeoffray 2012/05/31 08:48:22 Done.
908 // being used anymore).
909 List<String> ready = <String>[];
910
911 // Prune [copies] by removing self-copies.
912 List<Copy> prunedCopies = <Copy>[];
913 for (Copy copy in copies) {
914 String sourceName = variableNames.getName(copy.source);
915 String destinationName = variableNames.getName(copy.destination);
916 if (sourceName != destinationName) {
917 prunedCopies.add(new Copy(sourceName, destinationName));
918 }
919 }
920 copies = prunedCopies;
921
922
923 // For each copy, set the current location of the source to
924 // itself, and the initial value of the destination to the source.
925 // Add the destination to the list of copies to make.
926 for (Copy copy in copies) {
927 currentLocation[copy.source] = copy.source;
928 initialValue[copy.destination] = copy.source;
929 todo.add(copy.destination);
930 }
931
932 // For each copy, if the destination does not have a current
933 // location, then we can safely assign to it.
934 for (Copy copy in copies) {
935 if (currentLocation[copy.destination] === null) {
936 ready.add(copy.destination);
937 }
938 }
939
940 while (!todo.isEmpty()) {
941 while (!ready.isEmpty()) {
942 String destination = ready.removeLast();
943 String source = initialValue[destination];
944 // Since [source] might have been updated, use the current
945 // location of [source]
946 String copy = currentLocation[source];
947 emitAssignment(copy, destination);
floitsch 2012/05/30 18:45:03 I find it easier to read if the arguments are inve
ngeoffray 2012/05/31 08:12:46 Done.
948 // Now [destination] is the current location of [source].
949 currentLocation[source] = destination;
950 // If [source] hasn't been updated and needs to have a value,
951 // add it to the list of variables that can be updated. Copies
952 // of [source] will now use [destination].
953 if (source == copy && initialValue[source] !== null) {
954 ready.add(source);
955 }
956 }
957
958 // Check if we have a cycle.
959 String current = todo.removeLast();
960 // If [current] is the source of a copy, and the current
961 // location of its initial value is not itself, then there is a
962 // cycle that we break by using a temporary name.
963 if (currentLocation[current] !== null
floitsch 2012/05/30 18:45:03 Is this test necessary? Clearly: current == curre
ngeoffray 2012/05/31 08:12:46 Yes, it is. Because I don't remove a variable that
964 && current != currentLocation[initialValue[current]]) {
965 String tempName = VariableNames.SWAP_TEMP;
966 emitAssignment(current, tempName);
967 currentLocation[current] = tempName;
968 // [current] can now be safely updated. Copies of [current]
969 // will now use [tempName].
970 ready.add(current);
971 }
972 }
973 }
974
975 void assignPhisOfSuccessors(HBasicBlock node) {
976 CopyHandler handler = variableNames.getCopies(node);
977 if (handler == null) return;
978
979 sequentializeCopies(handler.copies);
980
981 for (Copy copy in handler.assignments) {
1041 if (isGeneratingExpression()) { 982 if (isGeneratingExpression()) {
1042 addExpressionSeparator(); 983 addExpressionSeparator();
1043 } else { 984 } else {
1044 addIndentation(); 985 addIndentation();
1045 } 986 }
1046 if (temporaryNamesOfPhis !== null && 987 declareVariable(variableNames.getName(copy.destination));
1047 canonicalPhi !== value && 988 buffer.add(' = ');
1048 temporaryNamesOfPhis.containsKey(canonicalPhi)) { 989 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()) { 990 if (!isGeneratingExpression()) {
1066 buffer.add(';\n'); 991 buffer.add(';\n');
1067 } 992 }
1068 } 993 }
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 } 994 }
1160 995
1161 void iterateBasicBlock(HBasicBlock node) { 996 void iterateBasicBlock(HBasicBlock node) {
1162 HInstruction instruction = node.first; 997 HInstruction instruction = node.first;
1163 while (instruction != null) { 998 while (instruction != null) {
1164 if (instruction === node.last) { 999 if (instruction === node.last) {
1165 assignPhisOfAllSuccessors(node); 1000 assignPhisOfSuccessors(node);
1166 } 1001 }
1167 1002
1168 if (isGenerateAtUseSite(instruction)) { 1003 if (isGenerateAtUseSite(instruction)) {
1169 if (instruction is HIf) { 1004 if (instruction is HIf) {
1170 HIf hif = instruction; 1005 HIf hif = instruction;
1171 // The "if" is implementing part of a logical expression. 1006 // The "if" is implementing part of a logical expression.
1172 // Skip directly forward to to its latest successor, since everything 1007 // Skip directly forward to to its latest successor, since everything
1173 // in-between must also be generateAtUseSite. 1008 // in-between must also be generateAtUseSite.
1174 assert(hif.trueBranch.id < hif.falseBranch.id); 1009 assert(hif.trueBranch.id < hif.falseBranch.id);
1175 visitBasicBlock(hif.falseBranch); 1010 visitBasicBlock(hif.falseBranch);
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
1584 visitFieldSet(HFieldSet node) { 1419 visitFieldSet(HFieldSet node) {
1585 String name; 1420 String name;
1586 if (!node.isFromActivation()) { 1421 if (!node.isFromActivation()) {
1587 name = 1422 name =
1588 compiler.namer.instanceFieldName(currentLibrary, node.name); 1423 compiler.namer.instanceFieldName(currentLibrary, node.name);
1589 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1424 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1590 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); 1425 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
1591 buffer.add('.'); 1426 buffer.add('.');
1592 buffer.add(name); 1427 buffer.add(name);
1593 } else { 1428 } 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); 1429 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE);
1600 } 1430 }
1601 buffer.add(' = '); 1431 buffer.add(' = ');
1602 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); 1432 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
1603 if (node.receiver !== null) { 1433 if (node.receiver !== null) {
1604 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1434 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1605 } 1435 }
1606 } 1436 }
1607 1437
1608 visitForeign(HForeign node) { 1438 visitForeign(HForeign node) {
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1737 } else { 1567 } else {
1738 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); 1568 beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
1739 buffer.add('!'); 1569 buffer.add('!');
1740 use(input, JSPrecedence.PREFIX_PRECEDENCE); 1570 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1741 endExpression(JSPrecedence.PREFIX_PRECEDENCE); 1571 endExpression(JSPrecedence.PREFIX_PRECEDENCE);
1742 } 1572 }
1743 } 1573 }
1744 1574
1745 visitParameterValue(HParameterValue node) { 1575 visitParameterValue(HParameterValue node) {
1746 assert(isGenerateAtUseSite(node)); 1576 assert(isGenerateAtUseSite(node));
1747 if (parameterNames[node.element] == null) { 1577 buffer.add(variableNames.getName(node));
1748 buffer.add(temporary(node));
1749 } else {
1750 buffer.add(parameterNames[node.element]);
1751 }
1752 } 1578 }
1753 1579
1754 visitPhi(HPhi node) { 1580 visitPhi(HPhi node) {
1755 String operation = logicalOperations[node]; 1581 String operation = logicalOperations[node];
1756 if (operation !== null) { 1582 if (operation !== null) {
1757 emitLogicalOperation(node, operation); 1583 emitLogicalOperation(node, operation);
1758 } else { 1584 } else {
1759 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); 1585 buffer.add('${variableNames.getName(node)}');
1760 buffer.add('${temporary(canonicalPhi)}');
1761 } 1586 }
1762 } 1587 }
1763 1588
1764 visitReturn(HReturn node) { 1589 visitReturn(HReturn node) {
1765 addIndentation(); 1590 addIndentation();
1766 assert(node.inputs.length == 1); 1591 assert(node.inputs.length == 1);
1767 HInstruction input = node.inputs[0]; 1592 HInstruction input = node.inputs[0];
1768 if (input.isConstantNull()) { 1593 if (input.isConstantNull()) {
1769 buffer.add('return;\n'); 1594 buffer.add('return;\n');
1770 } else { 1595 } else {
(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after
2473 void visitTypeGuard(HTypeGuard node) { 2298 void visitTypeGuard(HTypeGuard node) {
2474 indent--; 2299 indent--;
2475 addIndented('case ${node.state}:\n'); 2300 addIndented('case ${node.state}:\n');
2476 indent++; 2301 indent++;
2477 addIndented('state = 0;\n'); 2302 addIndented('state = 0;\n');
2478 2303
2479 setup.add(' case ${node.state}:\n'); 2304 setup.add(' case ${node.state}:\n');
2480 int i = 0; 2305 int i = 0;
2481 for (HInstruction input in node.inputs) { 2306 for (HInstruction input in node.inputs) {
2482 HInstruction instruction = unwrap(input); 2307 HInstruction instruction = unwrap(input);
2483 setup.add(' ${temporary(instruction)} = env$i;\n'); 2308 setup.add(' ${variableNames.getName(instruction)} = env$i;\n');
2484 i++; 2309 i++;
2485 } 2310 }
2486 if (i > maxBailoutParameters) maxBailoutParameters = i; 2311 if (i > maxBailoutParameters) maxBailoutParameters = i;
2487 setup.add(' break;\n'); 2312 setup.add(' break;\n');
2488 } 2313 }
2489 2314
2490 void startBailoutCase(List<HTypeGuard> bailouts1, 2315 void startBailoutCase(List<HTypeGuard> bailouts1,
2491 List<HTypeGuard> bailouts2) { 2316 List<HTypeGuard> bailouts2) {
2492 indent--; 2317 indent--;
2493 handleBailoutCase(bailouts1); 2318 handleBailoutCase(bailouts1);
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2632 startBailoutSwitch(); 2457 startBailoutSwitch();
2633 } 2458 }
2634 } 2459 }
2635 2460
2636 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { 2461 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
2637 if (labeledBlockInfo.body.start.hasGuards()) { 2462 if (labeledBlockInfo.body.start.hasGuards()) {
2638 endBailoutSwitch(); 2463 endBailoutSwitch();
2639 } 2464 }
2640 } 2465 }
2641 } 2466 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698