OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 SsaTypePropagator extends HGraphVisitor implements OptimizationPhase { | 5 class SsaTypePropagator extends HGraphVisitor implements OptimizationPhase { |
6 | 6 |
7 final Map<int, HInstruction> workmap; | 7 final Map<int, HInstruction> workmap; |
8 final List<int> worklist; | 8 final List<int> worklist; |
9 final Compiler compiler; | 9 final Compiler compiler; |
10 String get name() => 'type propagator'; | 10 String get name() => 'type propagator'; |
11 | 11 |
12 SsaTypePropagator(Compiler this.compiler) | 12 SsaTypePropagator(Compiler this.compiler) |
13 : workmap = new Map<int, HInstruction>(), | 13 : workmap = new Map<int, HInstruction>(), |
14 worklist = new List<int>(); | 14 worklist = new List<int>(); |
15 | 15 |
16 | 16 |
17 HType computeType(HInstruction instruction) { | 17 HType computeType(HInstruction instruction) => instruction.computeType(); |
18 return instruction.computeTypeFromInputTypes(); | |
19 } | |
20 | 18 |
21 // Re-compute and update the type of the instruction. Returns | 19 // Re-compute and update the type of the instruction. Returns |
22 // whether or not the type was changed. | 20 // whether or not the type was changed. |
23 bool updateType(HInstruction instruction) { | 21 bool updateType(HInstruction instruction) { |
24 if (instruction.propagatedType.isConflicting()) return false; | 22 if (instruction.type.isConflicting()) return false; |
| 23 // Constants have the type they have. It can't be changed. |
| 24 if (instruction.isConstant()) return false; |
25 | 25 |
26 HType oldType = instruction.propagatedType; | 26 HType oldType = instruction.type; |
27 HType newType = instruction.hasGuaranteedType() | 27 HType newType = computeType(instruction); |
28 ? instruction.guaranteedType | 28 instruction.type = oldType.combine(newType); |
29 : computeType(instruction); | 29 return oldType !== instruction.type; |
30 instruction.propagatedType = oldType.combine(newType); | |
31 return oldType !== instruction.propagatedType; | |
32 } | 30 } |
33 | 31 |
34 void visitGraph(HGraph graph) { | 32 void visitGraph(HGraph graph) { |
35 visitDominatorTree(graph); | 33 visitDominatorTree(graph); |
36 processWorklist(); | 34 processWorklist(); |
37 } | 35 } |
38 | 36 |
39 visitBasicBlock(HBasicBlock block) { | 37 visitBasicBlock(HBasicBlock block) { |
40 if (block.isLoopHeader()) { | 38 if (block.isLoopHeader()) { |
41 block.forEachPhi((HPhi phi) { | 39 block.forEachPhi((HPhi phi) { |
42 // Set the initial type for the phi. In theory we would need to mark the | 40 // Set the initial type for the phi. |
43 // type of all other incoming edges as "unitialized" and take this into | 41 phi.type = phi.inputs[0].type; |
44 // account when doing the propagation inside the phis. Just setting | |
45 // the [propagatedType] is however easier. | |
46 phi.propagatedType = phi.inputs[0].propagatedType; | |
47 addToWorkList(phi); | 42 addToWorkList(phi); |
48 }); | 43 }); |
49 } else { | 44 } else { |
50 block.forEachPhi((HPhi phi) { | 45 block.forEachPhi((HPhi phi) { |
51 if (updateType(phi)) addDependentInstructionsToWorkList(phi); | 46 if (updateType(phi)) addUsersAndInputsToWorklist(phi); |
52 }); | 47 }); |
53 } | 48 } |
54 | 49 |
55 HInstruction instruction = block.first; | 50 HInstruction instruction = block.first; |
56 while (instruction !== null) { | 51 while (instruction !== null) { |
57 if (updateType(instruction)) { | 52 if (updateType(instruction)) addUsersAndInputsToWorklist(instruction); |
58 addDependentInstructionsToWorkList(instruction); | |
59 } | |
60 instruction = instruction.next; | 53 instruction = instruction.next; |
61 } | 54 } |
62 } | 55 } |
63 | 56 |
64 void processWorklist() { | 57 void processWorklist() { |
65 while (!worklist.isEmpty()) { | 58 while (!worklist.isEmpty()) { |
66 int id = worklist.removeLast(); | 59 int id = worklist.removeLast(); |
67 HInstruction instruction = workmap[id]; | 60 HInstruction instruction = workmap[id]; |
68 assert(instruction !== null); | 61 assert(instruction !== null); |
69 workmap.remove(id); | 62 workmap.remove(id); |
70 if (updateType(instruction)) { | 63 if (updateType(instruction)) addUsersAndInputsToWorklist(instruction); |
71 addDependentInstructionsToWorkList(instruction); | |
72 } | |
73 } | 64 } |
74 } | 65 } |
75 | 66 |
76 void addDependentInstructionsToWorkList(HInstruction instruction) { | 67 void addUsersAndInputsToWorklist(HInstruction instruction) { |
77 for (int i = 0, length = instruction.usedBy.length; i < length; i++) { | 68 for (int i = 0, length = instruction.usedBy.length; i < length; i++) { |
78 // The non-speculative type propagator only propagates types forward. We | |
79 // thus only need to add the users of the [instruction] to the list. | |
80 addToWorkList(instruction.usedBy[i]); | 69 addToWorkList(instruction.usedBy[i]); |
81 } | 70 } |
| 71 for (int i = 0, length = instruction.inputs.length; i < length; i++) { |
| 72 addToWorkList(instruction.inputs[i]); |
| 73 } |
82 } | 74 } |
83 | 75 |
84 void addToWorkList(HInstruction instruction) { | 76 void addToWorkList(HInstruction instruction) { |
85 final int id = instruction.id; | 77 final int id = instruction.id; |
86 if (!workmap.containsKey(id)) { | 78 if (!workmap.containsKey(id)) { |
87 worklist.add(id); | 79 worklist.add(id); |
88 workmap[id] = instruction; | 80 workmap[id] = instruction; |
89 } | 81 } |
90 } | 82 } |
91 } | 83 } |
92 | 84 |
93 class SsaSpeculativeTypePropagator extends SsaTypePropagator { | 85 class SsaSpeculativeTypePropagator extends SsaTypePropagator { |
94 final String name = 'speculative type propagator'; | 86 final String name = 'speculative type propagator'; |
95 SsaSpeculativeTypePropagator(Compiler compiler) : super(compiler); | 87 SsaSpeculativeTypePropagator(Compiler compiler) : super(compiler); |
96 | 88 |
97 void addDependentInstructionsToWorkList(HInstruction instruction) { | |
98 // The speculative type propagator propagates types forward and backward. | |
99 // Not only do we need to add the users of the [instruction] to the list. | |
100 // We also need to add the inputs fo the [instruction], since they might | |
101 // want to propagate the desired outgoing type. | |
102 for (int i = 0, length = instruction.usedBy.length; i < length; i++) { | |
103 addToWorkList(instruction.usedBy[i]); | |
104 } | |
105 for (int i = 0, length = instruction.inputs.length; i < length; i++) { | |
106 addToWorkList(instruction.inputs[i]); | |
107 } | |
108 } | |
109 | |
110 HType computeDesiredType(HInstruction instruction) { | 89 HType computeDesiredType(HInstruction instruction) { |
111 HType desiredType = HType.UNKNOWN; | 90 HType desiredType = HType.UNKNOWN; |
112 for (final user in instruction.usedBy) { | 91 for (final user in instruction.usedBy) { |
113 desiredType = | 92 desiredType = |
114 desiredType.combine(user.computeDesiredTypeForInput(instruction)); | 93 desiredType.combine(user.computeDesiredInputType(instruction)); |
115 // No need to continue if two users disagree on the type. | 94 // No need to continue if two users disagree on the type. |
116 if (desiredType.isConflicting()) break; | 95 if (desiredType.isConflicting()) break; |
117 } | 96 } |
118 return desiredType; | 97 return desiredType; |
119 } | 98 } |
120 | 99 |
121 HType computeType(HInstruction instruction) { | 100 HType computeType(HInstruction instruction) { |
122 HType newType = super.computeType(instruction); | 101 HType newType = super.computeType(instruction); |
123 // [computeDesiredType] goes to all usedBys and lets them compute their | |
124 // desired type. By setting the [newType] here we give them more context to | |
125 // work with. | |
126 instruction.propagatedType = newType; | |
127 HType desiredType = computeDesiredType(instruction); | 102 HType desiredType = computeDesiredType(instruction); |
128 // If the desired type is conflicting just return the computed type. | 103 // If the desired type is conflicting just return the computed |
| 104 // type. |
129 if (desiredType.isConflicting()) return newType; | 105 if (desiredType.isConflicting()) return newType; |
130 return newType.combine(desiredType); | 106 return newType.combine(desiredType); |
131 } | 107 } |
132 } | 108 } |
OLD | NEW |