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