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 // unless they have been zapped before. | |
982 block.forEachPhi((HPhi phi) { | |
983 for (int i = 0; i < phi.inputs.length; ++i) { | |
984 if (!predecessors[i].isLive && | |
985 phi.inputs[i] != zapInstruction) { | |
986 phi.inputs[i].usedBy.remove(phi); | |
987 HInstruction zap = zapInstruction; | |
karlklose
2014/03/12 14:43:45
Is this a performance optimization? I would prefer
herhut
2014/03/13 13:27:45
Done.
| |
988 phi.inputs[i] = zap; | |
989 zap.usedBy.add(phi); | |
990 } | |
991 } | |
992 }); | |
972 if (predecessors.length < 2) continue L; | 993 if (predecessors.length < 2) continue L; |
973 // Find the index of the single live predecessor if it exists. | 994 // Find the index of the single live predecessor if it exists. |
974 int indexOfLive = -1; | 995 int indexOfLive = -1; |
975 for (int i = 0; i < predecessors.length; i++) { | 996 for (int i = 0; i < predecessors.length; i++) { |
976 if (predecessors[i].isLive) { | 997 if (predecessors[i].isLive) { |
977 if (indexOfLive >= 0) continue L; | 998 if (indexOfLive >= 0) continue L; |
978 indexOfLive = i; | 999 indexOfLive = i; |
979 } | 1000 } |
980 } | 1001 } |
981 // Run through the phis of the block and replace them with their input | 1002 // Run through the phis of the block and replace them with their input |
(...skipping 23 matching lines...) Expand all Loading... | |
1005 HInstruction zap = zapInstruction; | 1026 HInstruction zap = zapInstruction; |
1006 inputs[i] = zap; | 1027 inputs[i] = zap; |
1007 zap.usedBy.add(user); | 1028 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 Map<HInstruction, Range> get ranges => | |
1043 (this.compiler.backend as JavaScriptBackend).optimizer.ranges; | |
karlklose
2014/03/12 14:43:45
If you added a 'backend' field of type JavaScriptB
herhut
2014/03/13 13:27:45
I need the compiler, too, so I have decided to jus
| |
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.inputs[0].isInteger(compiler)) { | |
karlklose
2014/03/12 14:43:45
'node.inputs[0]' -> 'node.expression'.
herhut
2014/03/13 13:27:45
Done.
| |
1081 Range switchRange = ranges[node.inputs[0]]; | |
karlklose
2014/03/12 14:43:45
Ditto.
herhut
2014/03/13 13:27:45
Done.
| |
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 assert(input.isConstantInteger()); | |
karlklose
2014/03/12 14:43:45
I think this assertion is unnecessary, the code be
herhut
2014/03/13 13:27:45
You are probably right about the assert, it is a l
| |
1093 IntConstant constant = input.constant; | |
floitsch
2014/03/12 16:20:25
Pay attention that "-0.0" is a double-constant but
herhut
2014/03/13 13:27:45
0.0 should be illegal in case statements (and hope
| |
1094 int label = constant.value; | |
1095 if (!liveLabels.contains(label) && | |
1096 (label <= upper) && | |
karlklose
2014/03/12 14:43:45
No need for parentheses.
herhut
2014/03/13 13:27:45
I just like the visual grouping they provide. To k
| |
1097 (label >= lower)) { | |
karlklose
2014/03/12 14:43:45
Ditto.
herhut
2014/03/13 13:27:45
Done.
| |
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 |