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

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

Issue 10342002: Make sure that we don't assign phis before its uses. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 7 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
« no previous file with comments | « no previous file | tests/language/loop_exchange2_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 SsaCodeGeneratorTask(Compiler compiler) : super(compiler); 6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler);
7 String get name() => 'SSA code generator'; 7 String get name() => 'SSA code generator';
8 8
9 9
10 String buildJavaScriptFunction(FunctionElement element, 10 String buildJavaScriptFunction(FunctionElement element,
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 } 428 }
429 } 429 }
430 430
431 name = '${prefix}${prefixes[prefix]++}'; 431 name = '${prefix}${prefixes[prefix]++}';
432 while (usedNames.contains(name)) { 432 while (usedNames.contains(name)) {
433 name = '${prefix}${prefixes[prefix]++}'; 433 name = '${prefix}${prefixes[prefix]++}';
434 } 434 }
435 return newName(id, name); 435 return newName(id, name);
436 } 436 }
437 437
438 // TODO(floitsch): share more code with [temporary].
439 String freshTemporary() {
440 String prefix = TEMPORARY_PREFIX;
441 String name = '${prefix}${prefixes[prefix]++}';
442 while (usedNames.contains(name)) {
443 name = '${prefix}${prefixes[prefix]++}';
444 }
445 String result = JsNames.getValid(name);
446 usedNames.add(result);
447 return result;
448 }
449
438 bool temporaryExists(HInstruction instruction) { 450 bool temporaryExists(HInstruction instruction) {
439 return names.containsKey(instruction.id); 451 return names.containsKey(instruction.id);
440 } 452 }
441 453
442 String newName(int id, String name) { 454 String newName(int id, String name) {
443 String result = JsNames.getValid(name); 455 String result = JsNames.getValid(name);
444 names[id] = result; 456 names[id] = result;
445 usedNames.add(result); 457 usedNames.add(result);
446 return result; 458 return result;
447 } 459 }
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 914
903 // If our special handling didn't succeed, we have to emit a generic 915 // If our special handling didn't succeed, we have to emit a generic
904 // version. This still requires special handling for loop-blocks 916 // version. This still requires special handling for loop-blocks
905 if (node.isLoopHeader()) { 917 if (node.isLoopHeader()) {
906 beginLoop(node); 918 beginLoop(node);
907 } 919 }
908 } 920 }
909 iterateBasicBlock(node); 921 iterateBasicBlock(node);
910 } 922 }
911 923
924 /** Generates the assignments for all phis of successors blocks. */
925 void assignPhisOfAllSuccessors(HBasicBlock node) {
926 Map<HInstruction, String> temporaryNamesOfPhis = null;
927
928 /**
929 * Generates the assignment [canonicalPhi] = [value].
930 *
931 * If the [canonicalPhi] has a temporary name (in [temporaryNamesOfPhis])
932 * then the temporary is assigned instead of the [canonicalPhi]. However,
933 * when the left and right-hand side are equal ([:canonicalPhi === value:])
934 * then the [canonicalPhi] is assigned with the temporary.
Lasse Reichstein Nielsen 2012/05/03 12:19:49 Still a slightly odd "modal" function. Acceptable,
floitsch 2012/05/03 12:27:23 It could be split, but there is quite some boiler-
935 */
936 void generateAssignment(HPhi canonicalPhi, HInstruction value) {
937 if (isGeneratingExpression()) {
938 addExpressionSeparator();
939 } else {
940 addIndentation();
941 }
942 if (temporaryNamesOfPhis !== null &&
943 canonicalPhi !== value &&
944 temporaryNamesOfPhis.containsKey(canonicalPhi)) {
945 // This is the assignment to the temporary.
946 declareVariable(temporaryNamesOfPhis[canonicalPhi]);
947 } else if (!temporaryExists(canonicalPhi)) {
948 declareVariable(temporary(canonicalPhi));
949 } else {
950 buffer.add(temporary(canonicalPhi));
951 }
952 buffer.add(" = ");
953 bool isLogicalOperation = logicalOperations.containsKey(canonicalPhi);
954 if (isLogicalOperation) {
955 emitLogicalOperation(canonicalPhi, logicalOperations[canonicalPhi]);
956 } else if (canonicalPhi === value) {
957 buffer.add(temporaryNamesOfPhis[value]);
958 } else {
959 use(value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
960 }
961 if (!isGeneratingExpression()) {
962 buffer.add(';\n');
963 }
964 }
965
966 // Assignments are delayed so that we don't overwrite phis that might
967 // be used as inputs.
968 // TODO(floitsch): improve phi assignments. Currently we introduce
969 // way too many temporary variables.
970 Map<HPhi, HInstruction> phiAssignments = new Map<HPhi, HInstruction>();
971
972 for (HBasicBlock successor in node.successors) {
973 int index = successor.predecessors.indexOf(node);
974 successor.forEachPhi((HPhi phi) {
975 bool isLogicalOperation = logicalOperations.containsKey(phi);
976 // In case the phi is being generated by another
977 // instruction.
978 if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
979 HPhi canonicalPhi = phiEquivalence.getRepresentative(phi);
980 assert(!isLogicalOperation || canonicalPhi === phi);
981 HInstruction input = phi.inputs[index];
982 if (input is HPhi) {
983 input = phiEquivalence.getRepresentative(input);
984 // If we use the same variable, we don't need to create an
985 // assignment.
986 if (input === canonicalPhi) {
987 assert(!isLogicalOperation);
988 return;
989 }
990 }
991 phiAssignments[canonicalPhi] = input;
992 });
993 }
994
995 Set<HPhi> inputPhis = new Set<HPhi>();
996 List<HPhi> phis = <HPhi>[];
997
998 /**
999 * Transitively collects the phis that are used when emitting the [input]
1000 * and adds them to [inputPhis]. Does not add phis that are equal to the
1001 * [targetPhi] or are not in the [phiAssignments] map.
1002 */
1003 void collectInputPhis(HInstruction input, HPhi targetPhi) {
1004 if (input is HPhi) {
1005 HPhi canonicalPhi = phiEquivalence.getRepresentative(input);
1006 // Self-updates are ok.
1007 if (canonicalPhi !== targetPhi &&
1008 phiAssignments.containsKey(canonicalPhi)) {
1009 inputPhis.add(canonicalPhi);
1010 }
1011 } else if (isGenerateAtUseSite(input)) {
1012 for (HInstruction inputOfInput in input.inputs) {
1013 collectInputPhis(inputOfInput, targetPhi);
1014 }
1015 }
1016 }
1017
1018 phiAssignments.forEach((HPhi targetPhi, HInstruction input) {
1019 phis.add(targetPhi);
1020 collectInputPhis(input, targetPhi);
1021 });
1022
1023 if (inputPhis.isEmpty()) {
1024 phiAssignments.forEach(generateAssignment);
1025 } else {
1026 // Emit the phiX=phiY assignments, taking care to break cycles.
1027 // Example program:
1028 // var x = 499;
1029 // var y = 99;
1030 // while (x != 99) {
1031 // var tmp = x; // <=== The tmp variable is removed in Ssa-form.
1032 // x = y;
1033 // y = tmp;
1034 // }
1035 //
1036 temporaryNamesOfPhis = new HashMap<HInstruction, String>();
1037 // For phis that are used as inputs simply *always* allocate a
1038 // temporary.
1039 for (HPhi phi in phis) {
1040 if (inputPhis.contains(phi)) {
1041 String temporaryPhi = freshTemporary();
1042 temporaryNamesOfPhis[phi] = temporaryPhi;
1043 }
1044 // The assignPhi uses temporary variables for the left-hand side if
1045 // they exist.
1046 generateAssignment(phi, phiAssignments[phi]);
1047 }
1048 // Finally assign the input phis.
1049 for (HPhi phi in inputPhis) {
1050 // The assignPhi special-cases phi assignments to itself and recognizes
1051 // it as assignment from the temporary variable to the actual phi.
1052 generateAssignment(phi, phi);
1053 }
1054 }
1055 }
1056
912 void iterateBasicBlock(HBasicBlock node) { 1057 void iterateBasicBlock(HBasicBlock node) {
913 HInstruction instruction = node.first; 1058 HInstruction instruction = node.first;
914 while (instruction != null) { 1059 while (instruction != null) {
915 if (instruction === node.last) { 1060 if (instruction === node.last) {
916 for (HBasicBlock successor in node.successors) { 1061 assignPhisOfAllSuccessors(node);
917 int index = successor.predecessors.indexOf(node);
918 successor.forEachPhi((HPhi phi) {
919 bool isLogicalOperation = logicalOperations.containsKey(phi);
920 // In case the phi is being generated by another
921 // instruction.
922 if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
923 HPhi canonicalPhi = phiEquivalence.getRepresentative(phi);
924 HInstruction input = phi.inputs[index];
925 if (input is HPhi) {
926 HPhi inputPhi = input;
927 HPhi canonicalInput = phiEquivalence.getRepresentative(inputPhi);
928 // If we use the same variable, we don't need to create an
929 // assignment.
930 if (canonicalInput === canonicalPhi) {
931 assert(!isLogicalOperation);
932 return;
933 }
934 }
935 if (isGeneratingExpression()) {
936 addExpressionSeparator();
937 } else {
938 addIndentation();
939 }
940 if (!temporaryExists(canonicalPhi)) {
941 declareVariable(temporary(canonicalPhi));
942 } else {
943 buffer.add(temporary(canonicalPhi));
944 }
945 buffer.add(" = ");
946 if (isLogicalOperation) {
947 emitLogicalOperation(phi, logicalOperations[phi]);
948 } else {
949 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE);
950 }
951 if (!isGeneratingExpression()) {
952 buffer.add(';\n');
953 }
954 });
955 }
956 } 1062 }
957 1063
958 if (instruction is HGoto || instruction is HExit || instruction is HTry) { 1064 if (instruction is HGoto || instruction is HExit || instruction is HTry) {
959 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 1065 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
960 return; 1066 return;
961 } else if (!isGenerateAtUseSite(instruction)) { 1067 } else if (!isGenerateAtUseSite(instruction)) {
962 if (instruction is !HIf && instruction is !HTypeGuard && 1068 if (instruction is !HIf && instruction is !HTypeGuard &&
963 instruction is !HLoopBranch && !isGeneratingExpression()) { 1069 instruction is !HLoopBranch && !isGeneratingExpression()) {
964 addIndentation(); 1070 addIndentation();
965 } 1071 }
(...skipping 1328 matching lines...) Expand 10 before | Expand all | Expand 10 after
2294 startBailoutSwitch(); 2400 startBailoutSwitch();
2295 } 2401 }
2296 } 2402 }
2297 2403
2298 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { 2404 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
2299 if (labeledBlockInfo.body.start.hasGuards()) { 2405 if (labeledBlockInfo.body.start.hasGuards()) {
2300 endBailoutSwitch(); 2406 endBailoutSwitch();
2301 } 2407 }
2302 } 2408 }
2303 } 2409 }
OLDNEW
« no previous file with comments | « no previous file | tests/language/loop_exchange2_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698