| 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 |