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 |