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 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
901 if (success) return; | 913 if (success) return; |
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 |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Please add dart-doc describing what the method doe
floitsch
2012/05/03 09:11:29
Done.
| |
924 void assignPhisOfAllSuccessors(HBasicBlock node) { | |
925 Map<HInstruction, String> phiTemporaries = null; | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Can you give a better name to this map? I gives no
floitsch
2012/05/03 09:11:29
renamed to temporaryNamesOfPhis. (dart-editor for
| |
926 | |
927 void assignPhi(HPhi canonicalPhi, HInstruction value) { | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
assignPhi -> generateAssignment.
You don't assign
floitsch
2012/05/03 09:11:29
Renamed and added doc.
| |
928 if (isGeneratingExpression()) { | |
929 addExpressionSeparator(); | |
930 } else { | |
931 addIndentation(); | |
932 } | |
933 if (phiTemporaries !== null && | |
934 canonicalPhi !== value && | |
935 phiTemporaries.containsKey(canonicalPhi)) { | |
936 // This is the assignment to the temporary. | |
937 declareVariable(phiTemporaries[canonicalPhi]); | |
938 } else if (!temporaryExists(canonicalPhi)) { | |
939 declareVariable(temporary(canonicalPhi)); | |
940 } else { | |
941 buffer.add(temporary(canonicalPhi)); | |
942 } | |
943 buffer.add(" = "); | |
944 bool isLogicalOperation = logicalOperations.containsKey(canonicalPhi); | |
945 if (isLogicalOperation) { | |
946 emitLogicalOperation(canonicalPhi, logicalOperations[canonicalPhi]); | |
947 } else if (canonicalPhi === value) { | |
948 buffer.add(phiTemporaries[value]); | |
949 } else { | |
950 use(value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
951 } | |
952 if (!isGeneratingExpression()) { | |
953 buffer.add(';\n'); | |
954 } | |
955 } | |
956 | |
957 void collectInputPhis(HInstruction input, Set<HPhi> inputPhis, | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Dart-doc description of what the function does, pl
floitsch
2012/05/03 09:11:29
Done.
| |
958 bool shouldBeAdded(HPhi phi)) { | |
959 if (input is HPhi) { | |
960 HPhi canonicalPhi = phiEquivalence.getRepresentative(input); | |
961 if (shouldBeAdded(canonicalPhi)) inputPhis.add(canonicalPhi); | |
962 } else if (isGenerateAtUseSite(input)) { | |
963 for (HInstruction inputOfInput in input.inputs) { | |
964 collectInputPhis(inputOfInput, inputPhis, shouldBeAdded); | |
965 } | |
966 } | |
967 } | |
968 | |
969 // Assignments are delayed so that we don't overwrite phis that might | |
970 // be used as inputs. | |
971 // TODO(floitsch): improve phi assignments. Currently we introduce | |
972 // way too many temporary variables. | |
973 Map<HPhi, HInstruction> phiAssignments = new Map<HPhi, HInstruction>(); | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Please add empty line after declaration.
floitsch
2012/05/03 09:11:29
Done.
| |
974 for (HBasicBlock successor in node.successors) { | |
975 int index = successor.predecessors.indexOf(node); | |
976 successor.forEachPhi((HPhi phi) { | |
977 bool isLogicalOperation = logicalOperations.containsKey(phi); | |
978 // In case the phi is being generated by another | |
979 // instruction. | |
980 if (isLogicalOperation && isGenerateAtUseSite(phi)) return; | |
981 HPhi canonicalPhi = phiEquivalence.getRepresentative(phi); | |
982 assert(canonicalPhi === phi || !isLogicalOperation); | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Reading this now, I actually prefer:
assert(!isL
floitsch
2012/05/03 09:11:29
Done.
| |
983 HInstruction input = phi.inputs[index]; | |
984 if (input is HPhi) { | |
985 input = phiEquivalence.getRepresentative(input); | |
986 // If we use the same variable, we don't need to create an | |
987 // assignment. | |
988 if (input === canonicalPhi) { | |
989 assert(!isLogicalOperation); | |
990 return; | |
991 } | |
992 } | |
993 phiAssignments[canonicalPhi] = input; | |
994 }); | |
995 } | |
996 | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Remove extra empty line.
floitsch
2012/05/03 09:11:29
Done.
| |
997 | |
998 List<HPhi> phis = <HPhi>[]; | |
999 Set<HPhi> inputPhis = new Set<HPhi>(); | |
1000 phiAssignments.forEach((HPhi targetPhi, HInstruction input) { | |
1001 phis.add(targetPhi); | |
1002 collectInputPhis(input, inputPhis, (HPhi phi) { | |
1003 // Self-assignments are ok. | |
1004 return phi !== targetPhi && phiAssignments.containsKey(phi); | |
1005 }); | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
Inline the shouldBeAdded function in collectInputP
floitsch
2012/05/03 09:11:29
Done.
| |
1006 }); | |
1007 | |
1008 bool phisAreUsedAsInputs = !inputPhis.isEmpty(); | |
1009 | |
1010 if (!phisAreUsedAsInputs) { | |
1011 phiAssignments.forEach(assignPhi); | |
1012 } else { | |
1013 // Emit the phiX=phiY assignments, taking care to break cycles. | |
1014 // Example program: | |
1015 // var x = 499; | |
1016 // var y = 99; | |
1017 // while (x != 99) { | |
1018 // var tmp = x; // <=== The tmp variable is removed in Ssa-form. | |
1019 // x = y; | |
1020 // y = tmp; | |
1021 // } | |
1022 // | |
1023 int length = phis.length; | |
1024 phiTemporaries = new HashMap<HInstruction, String>(); | |
1025 // For phis that are used as inputs simply *always* allocate a | |
1026 // temporary. | |
1027 for (int i = 0; i < length; i++) { | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
You don't use "i", so perhaps just
for (HPhi phi
floitsch
2012/05/03 09:11:29
Done.
| |
1028 HPhi phi = phis[i]; | |
1029 if (inputPhis.contains(phi)) { | |
1030 String temporaryPhi = freshTemporary(); | |
1031 phiTemporaries[phi] = temporaryPhi; | |
1032 } | |
1033 // The assignPhi uses temporary variables for the left-hand side if | |
1034 // they exist. | |
1035 assignPhi(phi, phiAssignments[phi]); | |
1036 } | |
1037 // Finally assign the input phis. | |
1038 for (HPhi phi in inputPhis) { | |
1039 // The assignPhi special-cases phi assignments to itself and recognizes | |
1040 // it as assignment from the temporary variable to the actual phi. | |
1041 assignPhi(phi, phi); | |
1042 } | |
Lasse Reichstein Nielsen
2012/05/03 08:22:02
For a later version, maybe we can try sorting the
floitsch
2012/05/03 09:11:29
That's what the TODO implies.
| |
1043 } | |
1044 } | |
1045 | |
912 void iterateBasicBlock(HBasicBlock node) { | 1046 void iterateBasicBlock(HBasicBlock node) { |
913 HInstruction instruction = node.first; | 1047 HInstruction instruction = node.first; |
914 while (instruction != null) { | 1048 while (instruction != null) { |
915 if (instruction === node.last) { | 1049 if (instruction === node.last) { |
916 for (HBasicBlock successor in node.successors) { | 1050 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 } | 1051 } |
957 | 1052 |
958 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 1053 if (instruction is HGoto || instruction is HExit || instruction is HTry) { |
959 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1054 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
960 return; | 1055 return; |
961 } else if (!isGenerateAtUseSite(instruction)) { | 1056 } else if (!isGenerateAtUseSite(instruction)) { |
962 if (instruction is !HIf && instruction is !HTypeGuard && | 1057 if (instruction is !HIf && instruction is !HTypeGuard && |
963 instruction is !HLoopBranch && !isGeneratingExpression()) { | 1058 instruction is !HLoopBranch && !isGeneratingExpression()) { |
964 addIndentation(); | 1059 addIndentation(); |
965 } | 1060 } |
(...skipping 1328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2294 startBailoutSwitch(); | 2389 startBailoutSwitch(); |
2295 } | 2390 } |
2296 } | 2391 } |
2297 | 2392 |
2298 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2393 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
2299 if (labeledBlockInfo.body.start.hasGuards()) { | 2394 if (labeledBlockInfo.body.start.hasGuards()) { |
2300 endBailoutSwitch(); | 2395 endBailoutSwitch(); |
2301 } | 2396 } |
2302 } | 2397 } |
2303 } | 2398 } |
OLD | NEW |