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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { |
8 String get name; | 8 String get name; |
9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
10 } | 10 } |
11 | 11 |
12 class SsaOptimizerTask extends CompilerTask { | 12 class SsaOptimizerTask extends CompilerTask { |
13 final JavaScriptBackend backend; | 13 final JavaScriptBackend backend; |
14 SsaOptimizerTask(JavaScriptBackend backend) | 14 SsaOptimizerTask(JavaScriptBackend backend) |
15 : this.backend = backend, | 15 : this.backend = backend, |
16 super(backend.compiler); | 16 super(backend.compiler); |
17 String get name => 'SSA optimizer'; | 17 String get name => 'SSA optimizer'; |
18 Compiler get compiler => backend.compiler; | 18 Compiler get compiler => backend.compiler; |
| 19 Map<HInstruction, Range> ranges = <HInstruction, Range>{}; |
19 | 20 |
20 void runPhases(HGraph graph, List<OptimizationPhase> phases) { | 21 void runPhases(HGraph graph, List<OptimizationPhase> phases) { |
21 for (OptimizationPhase phase in phases) { | 22 for (OptimizationPhase phase in phases) { |
22 runPhase(graph, phase); | 23 runPhase(graph, phase); |
23 } | 24 } |
24 } | 25 } |
25 | 26 |
26 void runPhase(HGraph graph, OptimizationPhase phase) { | 27 void runPhase(HGraph graph, OptimizationPhase phase) { |
27 phase.visitGraph(graph); | 28 phase.visitGraph(graph); |
28 compiler.tracer.traceGraph(phase.name, graph); | 29 compiler.tracer.traceGraph(phase.name, graph); |
(...skipping 30 matching lines...) Expand all Loading... |
59 new SsaCodeMotion(), | 60 new SsaCodeMotion(), |
60 new SsaLoadElimination(compiler), | 61 new SsaLoadElimination(compiler), |
61 new SsaDeadPhiEliminator(), | 62 new SsaDeadPhiEliminator(), |
62 new SsaTypePropagator(compiler), | 63 new SsaTypePropagator(compiler), |
63 new SsaValueRangeAnalyzer(compiler, constantSystem, work), | 64 new SsaValueRangeAnalyzer(compiler, constantSystem, work), |
64 // Previous optimizations may have generated new | 65 // Previous optimizations may have generated new |
65 // opportunities for instruction simplification. | 66 // opportunities for instruction simplification. |
66 new SsaInstructionSimplifier(constantSystem, backend, work), | 67 new SsaInstructionSimplifier(constantSystem, backend, work), |
67 new SsaCheckInserter(backend, work, context.boundsChecked), | 68 new SsaCheckInserter(backend, work, context.boundsChecked), |
68 new SsaSimplifyInterceptors(compiler, constantSystem, work), | 69 new SsaSimplifyInterceptors(compiler, constantSystem, work), |
69 dce = new SsaDeadCodeEliminator(compiler)]; | 70 dce = new SsaDeadCodeEliminator(compiler), |
| 71 new SsaTypePropagator(compiler)]; |
70 runPhases(graph, phases); | 72 runPhases(graph, phases); |
71 if (!dce.eliminatedSideEffects) return; | 73 if (dce.eliminatedSideEffects) { |
72 phases = <OptimizationPhase>[ | 74 phases = <OptimizationPhase>[ |
73 new SsaGlobalValueNumberer(compiler), | 75 new SsaGlobalValueNumberer(compiler), |
74 new SsaCodeMotion(), | 76 new SsaCodeMotion(), |
75 new SsaValueRangeAnalyzer(compiler, constantSystem, work), | 77 new SsaValueRangeAnalyzer(compiler, constantSystem, work), |
76 new SsaInstructionSimplifier(constantSystem, backend, work), | 78 new SsaInstructionSimplifier(constantSystem, backend, work), |
77 new SsaCheckInserter(backend, work, context.boundsChecked), | 79 new SsaCheckInserter(backend, work, context.boundsChecked), |
78 new SsaSimplifyInterceptors(compiler, constantSystem, work), | 80 new SsaSimplifyInterceptors(compiler, constantSystem, work), |
79 new SsaDeadCodeEliminator(compiler)]; | 81 new SsaDeadCodeEliminator(compiler)]; |
| 82 } else { |
| 83 phases = <OptimizationPhase>[ |
| 84 // Run the simplifier to remove unneeded type checks inserted |
| 85 // by type propagation. |
| 86 new SsaInstructionSimplifier(constantSystem, backend, work)]; |
| 87 } |
80 runPhases(graph, phases); | 88 runPhases(graph, phases); |
81 }); | 89 }); |
82 } | 90 } |
83 } | 91 } |
84 | 92 |
85 bool isFixedLength(mask, Compiler compiler) { | 93 bool isFixedLength(mask, Compiler compiler) { |
86 JavaScriptBackend backend = compiler.backend; | 94 JavaScriptBackend backend = compiler.backend; |
87 if (mask.isContainer && mask.length != null) { | 95 if (mask.isContainer && mask.length != null) { |
88 // A container on which we have inferred the length. | 96 // A container on which we have inferred the length. |
89 return true; | 97 return true; |
(...skipping 844 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 && instruction.onlyThrowsNSM() | 942 && instruction.onlyThrowsNSM() |
935 && hasFollowingThrowingNSM(instruction)) { | 943 && hasFollowingThrowingNSM(instruction)) { |
936 return true; | 944 return true; |
937 } | 945 } |
938 return !instruction.canThrow() | 946 return !instruction.canThrow() |
939 && instruction is !HParameterValue | 947 && instruction is !HParameterValue |
940 && instruction is !HLocalSet; | 948 && instruction is !HLocalSet; |
941 } | 949 } |
942 | 950 |
943 void visitGraph(HGraph graph) { | 951 void visitGraph(HGraph graph) { |
944 analyzer = new SsaLiveBlockAnalyzer(graph); | 952 analyzer = new SsaLiveBlockAnalyzer(graph, compiler); |
945 analyzer.analyze(); | 953 analyzer.analyze(); |
946 visitPostDominatorTree(graph); | 954 visitPostDominatorTree(graph); |
947 cleanPhis(graph); | 955 cleanPhis(graph); |
948 } | 956 } |
949 | 957 |
950 void visitBasicBlock(HBasicBlock block) { | 958 void visitBasicBlock(HBasicBlock block) { |
951 bool isDeadBlock = analyzer.isDeadBlock(block); | 959 bool isDeadBlock = analyzer.isDeadBlock(block); |
952 block.isLive = !isDeadBlock; | 960 block.isLive = !isDeadBlock; |
953 // Start from the last non-control flow instruction in the block. | 961 // Start from the last non-control flow instruction in the block. |
954 HInstruction instruction = block.last.previous; | 962 HInstruction instruction = block.last.previous; |
955 while (instruction != null) { | 963 while (instruction != null) { |
956 var previous = instruction.previous; | 964 var previous = instruction.previous; |
957 if (isDeadBlock) { | 965 if (isDeadBlock) { |
958 eliminatedSideEffects = eliminatedSideEffects || | 966 eliminatedSideEffects = eliminatedSideEffects || |
959 instruction.sideEffects.hasSideEffects(); | 967 instruction.sideEffects.hasSideEffects(); |
960 removeUsers(instruction); | 968 removeUsers(instruction); |
961 block.remove(instruction); | 969 block.remove(instruction); |
962 } else if (isDeadCode(instruction)) { | 970 } else if (isDeadCode(instruction)) { |
963 block.remove(instruction); | 971 block.remove(instruction); |
964 } | 972 } |
965 instruction = previous; | 973 instruction = previous; |
966 } | 974 } |
967 } | 975 } |
968 | 976 |
969 void cleanPhis(HGraph graph) { | 977 void cleanPhis(HGraph graph) { |
970 L: for (HBasicBlock block in graph.blocks) { | 978 L: for (HBasicBlock block in graph.blocks) { |
971 List<HBasicBlock> predecessors = block.predecessors; | 979 List<HBasicBlock> predecessors = block.predecessors; |
| 980 // Zap all inputs to phis that correspond to dead blocks. |
| 981 block.forEachPhi((HPhi phi) { |
| 982 for (int i = 0; i < phi.inputs.length; ++i) { |
| 983 if (!predecessors[i].isLive && phi.inputs[i] != zapInstruction) { |
| 984 replaceInput(i, phi, zapInstruction); |
| 985 } |
| 986 } |
| 987 }); |
972 if (predecessors.length < 2) continue L; | 988 if (predecessors.length < 2) continue L; |
973 // Find the index of the single live predecessor if it exists. | 989 // Find the index of the single live predecessor if it exists. |
974 int indexOfLive = -1; | 990 int indexOfLive = -1; |
975 for (int i = 0; i < predecessors.length; i++) { | 991 for (int i = 0; i < predecessors.length; i++) { |
976 if (predecessors[i].isLive) { | 992 if (predecessors[i].isLive) { |
977 if (indexOfLive >= 0) continue L; | 993 if (indexOfLive >= 0) continue L; |
978 indexOfLive = i; | 994 indexOfLive = i; |
979 } | 995 } |
980 } | 996 } |
981 // Run through the phis of the block and replace them with their input | 997 // Run through the phis of the block and replace them with their input |
982 // that comes from the only live predecessor if that dominates the phi. | 998 // that comes from the only live predecessor if that dominates the phi. |
983 block.forEachPhi((HPhi phi) { | 999 block.forEachPhi((HPhi phi) { |
984 HInstruction replacement = (indexOfLive >= 0) | 1000 HInstruction replacement = (indexOfLive >= 0) |
985 ? phi.inputs[indexOfLive] : zapInstruction; | 1001 ? phi.inputs[indexOfLive] : zapInstruction; |
986 if (replacement.dominates(phi)) { | 1002 if (replacement.dominates(phi)) { |
987 block.rewrite(phi, replacement); | 1003 block.rewrite(phi, replacement); |
988 block.removePhi(phi); | 1004 block.removePhi(phi); |
989 } | 1005 } |
990 }); | 1006 }); |
991 } | 1007 } |
992 } | 1008 } |
993 | 1009 |
| 1010 void replaceInput(int i, HInstruction from, HInstruction by) { |
| 1011 from.inputs[i].usedBy.remove(from); |
| 1012 from.inputs[i] = by; |
| 1013 by.usedBy.add(from); |
| 1014 } |
| 1015 |
994 void removeUsers(HInstruction instruction) { | 1016 void removeUsers(HInstruction instruction) { |
995 instruction.usedBy.forEach((user) { | 1017 instruction.usedBy.forEach((user) { |
996 removeInput(user, instruction); | 1018 removeInput(user, instruction); |
997 }); | 1019 }); |
998 instruction.usedBy.clear(); | 1020 instruction.usedBy.clear(); |
999 } | 1021 } |
1000 | 1022 |
1001 void removeInput(HInstruction user, HInstruction input) { | 1023 void removeInput(HInstruction user, HInstruction input) { |
1002 List<HInstruction> inputs = user.inputs; | 1024 List<HInstruction> inputs = user.inputs; |
1003 for (int i = 0, length = inputs.length; i < length; i++) { | 1025 for (int i = 0, length = inputs.length; i < length; i++) { |
1004 if (input == inputs[i]) { | 1026 if (input == inputs[i]) { |
1005 HInstruction zap = zapInstruction; | 1027 user.inputs[i] = zapInstruction; |
1006 inputs[i] = zap; | 1028 zapInstruction.usedBy.add(user); |
1007 zap.usedBy.add(user); | |
1008 } | 1029 } |
1009 } | 1030 } |
1010 } | 1031 } |
1011 } | 1032 } |
1012 | 1033 |
1013 class SsaLiveBlockAnalyzer extends HBaseVisitor { | 1034 class SsaLiveBlockAnalyzer extends HBaseVisitor { |
1014 final HGraph graph; | 1035 final HGraph graph; |
| 1036 final Compiler compiler; |
1015 final Set<HBasicBlock> live = new Set<HBasicBlock>(); | 1037 final Set<HBasicBlock> live = new Set<HBasicBlock>(); |
1016 final List<HBasicBlock> worklist = <HBasicBlock>[]; | 1038 final List<HBasicBlock> worklist = <HBasicBlock>[]; |
1017 SsaLiveBlockAnalyzer(this.graph); | 1039 |
| 1040 SsaLiveBlockAnalyzer(this.graph, this.compiler); |
| 1041 |
| 1042 JavaScriptBackend get backend => compiler.backend; |
| 1043 Map<HInstruction, Range> get ranges => backend.optimizer.ranges; |
1018 | 1044 |
1019 bool isDeadBlock(HBasicBlock block) => !live.contains(block); | 1045 bool isDeadBlock(HBasicBlock block) => !live.contains(block); |
1020 | 1046 |
1021 void analyze() { | 1047 void analyze() { |
1022 markBlockLive(graph.entry); | 1048 markBlockLive(graph.entry); |
1023 while (!worklist.isEmpty) { | 1049 while (!worklist.isEmpty) { |
1024 HBasicBlock live = worklist.removeLast(); | 1050 HBasicBlock live = worklist.removeLast(); |
1025 live.last.accept(this); | 1051 live.last.accept(this); |
1026 } | 1052 } |
1027 } | 1053 } |
(...skipping 14 matching lines...) Expand all Loading... |
1042 if (condition.isConstant()) { | 1068 if (condition.isConstant()) { |
1043 if (condition.isConstantTrue()) { | 1069 if (condition.isConstantTrue()) { |
1044 markBlockLive(instruction.thenBlock); | 1070 markBlockLive(instruction.thenBlock); |
1045 } else { | 1071 } else { |
1046 markBlockLive(instruction.elseBlock); | 1072 markBlockLive(instruction.elseBlock); |
1047 } | 1073 } |
1048 } else { | 1074 } else { |
1049 visitControlFlow(instruction); | 1075 visitControlFlow(instruction); |
1050 } | 1076 } |
1051 } | 1077 } |
| 1078 |
| 1079 void visitSwitch(HSwitch node) { |
| 1080 if (!node.isTotal && node.expression.isInteger(compiler)) { |
| 1081 Range switchRange = ranges[node.expression]; |
| 1082 if (switchRange != null && |
| 1083 switchRange.lower is IntValue && |
| 1084 switchRange.upper is IntValue) { |
| 1085 IntValue lowerValue = switchRange.lower; |
| 1086 IntValue upperValue = switchRange.upper; |
| 1087 int lower = lowerValue.value; |
| 1088 int upper = upperValue.value; |
| 1089 Set<int> liveLabels = new Set<int>(); |
| 1090 for (int pos = 1; pos < node.inputs.length; pos++) { |
| 1091 HConstant input = node.inputs[pos]; |
| 1092 if (!input.isConstantInteger()) continue; |
| 1093 IntConstant constant = input.constant; |
| 1094 int label = constant.value; |
| 1095 if (!liveLabels.contains(label) && |
| 1096 label <= upper && |
| 1097 label >= lower) { |
| 1098 markBlockLive(node.block.successors[pos - 1]); |
| 1099 liveLabels.add(label); |
| 1100 } |
| 1101 } |
| 1102 if (liveLabels.length != upper - lower + 1) { |
| 1103 markBlockLive(node.defaultTarget); |
| 1104 } else { |
| 1105 node.isTotal = true; |
| 1106 } |
| 1107 return; |
| 1108 } |
| 1109 } |
| 1110 visitControlFlow(node); |
| 1111 } |
1052 } | 1112 } |
1053 | 1113 |
1054 class SsaDeadPhiEliminator implements OptimizationPhase { | 1114 class SsaDeadPhiEliminator implements OptimizationPhase { |
1055 final String name = "SsaDeadPhiEliminator"; | 1115 final String name = "SsaDeadPhiEliminator"; |
1056 | 1116 |
1057 void visitGraph(HGraph graph) { | 1117 void visitGraph(HGraph graph) { |
1058 final List<HPhi> worklist = <HPhi>[]; | 1118 final List<HPhi> worklist = <HPhi>[]; |
1059 // A set to keep track of the live phis that we found. | 1119 // A set to keep track of the live phis that we found. |
1060 final Set<HPhi> livePhis = new Set<HPhi>(); | 1120 final Set<HPhi> livePhis = new Set<HPhi>(); |
1061 | 1121 |
(...skipping 906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1968 | 2028 |
1969 keyedValues.forEach((receiver, values) { | 2029 keyedValues.forEach((receiver, values) { |
1970 result.keyedValues[receiver] = | 2030 result.keyedValues[receiver] = |
1971 new Map<HInstruction, HInstruction>.from(values); | 2031 new Map<HInstruction, HInstruction>.from(values); |
1972 }); | 2032 }); |
1973 | 2033 |
1974 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2034 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
1975 return result; | 2035 return result; |
1976 } | 2036 } |
1977 } | 2037 } |
OLD | NEW |