| 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 /** | 5 /** |
| 6 * Instead of emitting each SSA instruction with a temporary variable | 6 * Instead of emitting each SSA instruction with a temporary variable |
| 7 * mark instructions that can be emitted at their use-site. | 7 * mark instructions that can be emitted at their use-site. |
| 8 * For example, in: | 8 * For example, in: |
| 9 * t0 = 4; | 9 * t0 = 4; |
| 10 * t1 = 3; | 10 * t1 = 3; |
| 11 * t2 = add(t0, t1); | 11 * t2 = add(t0, t1); |
| 12 * t0 and t1 would be marked and the resulting code would then be: | 12 * t0 and t1 would be marked and the resulting code would then be: |
| 13 * t2 = add(4, 3); | 13 * t2 = add(4, 3); |
| 14 */ | 14 */ |
| 15 class SsaInstructionMerger extends HBaseVisitor { | 15 class SsaInstructionMerger extends HBaseVisitor { |
| 16 List<HInstruction> expectedInputs; | 16 List<HInstruction> expectedInputs; |
| 17 Set<HInstruction> generateAtUseSite; | 17 Set<HInstruction> generateAtUseSite; |
| 18 | 18 |
| 19 SsaInstructionMerger(this.generateAtUseSite); | 19 SsaInstructionMerger(this.generateAtUseSite); |
| 20 | 20 |
| 21 void visitGraph(HGraph graph) { | 21 void visitGraph(HGraph graph) { |
| 22 visitDominatorTree(graph); | 22 visitDominatorTree(graph); |
| 23 } | 23 } |
| 24 | 24 |
| 25 bool usedOnlyByPhis(instruction) { | 25 bool usedOnlyByPhis(instruction) { |
| 26 for (HInstruction user in instruction.usedBy) { | 26 for (HInstruction user in instruction.usedBy) { |
| 27 if (user is !HPhi) return false; | 27 if (user is! HPhi) return false; |
| 28 } | 28 } |
| 29 return true; | 29 return true; |
| 30 } | 30 } |
| 31 | 31 |
| 32 void visitInstruction(HInstruction instruction) { | 32 void visitInstruction(HInstruction instruction) { |
| 33 // A code motion invariant instruction is dealt before visiting it. | 33 // A code motion invariant instruction is dealt before visiting it. |
| 34 assert(!instruction.isCodeMotionInvariant()); | 34 assert(!instruction.isCodeMotionInvariant()); |
| 35 for (HInstruction input in instruction.inputs) { | 35 for (HInstruction input in instruction.inputs) { |
| 36 if (!generateAtUseSite.contains(input) | 36 if (!generateAtUseSite.contains(input) |
| 37 && !input.isCodeMotionInvariant() | 37 && !input.isCodeMotionInvariant() |
| 38 && input.usedBy.length == 1) { | 38 && input.usedBy.length == 1 |
| 39 && input is! HPhi) { |
| 39 expectedInputs.add(input); | 40 expectedInputs.add(input); |
| 40 } | 41 } |
| 41 } | 42 } |
| 42 } | 43 } |
| 43 | 44 |
| 44 // The codegen might use the input multiple times, so it must not be | 45 // The codegen might use the input multiple times, so it must not be |
| 45 // set generate at use site. | 46 // set generate at use site. |
| 46 void visitIs(HIs instruction) {} | 47 void visitIs(HIs instruction) {} |
| 47 | 48 |
| 48 // A check method must not have its input generate at use site, | 49 // A check method must not have its input generate at use site, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 // be generated at their use site, if they occur in the correct order. | 90 // be generated at their use site, if they occur in the correct order. |
| 90 if (expectedInputs === null) expectedInputs = new List<HInstruction>(); | 91 if (expectedInputs === null) expectedInputs = new List<HInstruction>(); |
| 91 | 92 |
| 92 // Pop instructions from expectedInputs until instruction is found. | 93 // Pop instructions from expectedInputs until instruction is found. |
| 93 // Return true if it is found, or false if not. | 94 // Return true if it is found, or false if not. |
| 94 bool findInInputs(HInstruction instruction) { | 95 bool findInInputs(HInstruction instruction) { |
| 95 while (!expectedInputs.isEmpty()) { | 96 while (!expectedInputs.isEmpty()) { |
| 96 HInstruction nextInput = expectedInputs.removeLast(); | 97 HInstruction nextInput = expectedInputs.removeLast(); |
| 97 assert(!generateAtUseSite.contains(nextInput)); | 98 assert(!generateAtUseSite.contains(nextInput)); |
| 98 assert(nextInput.usedBy.length == 1); | 99 assert(nextInput.usedBy.length == 1); |
| 99 if (nextInput == instruction) { | 100 if (nextInput === instruction) { |
| 100 return true; | 101 return true; |
| 101 } | 102 } |
| 102 } | 103 } |
| 103 return false; | 104 return false; |
| 104 } | 105 } |
| 105 | 106 |
| 107 for (HBasicBlock successor in block.successors) { |
| 108 // Only add the input of the first phi. Making inputs of |
| 109 // later phis generate-at-use-site would make them move |
| 110 // accross the assignment of the first phi, and we need |
| 111 // more analysis before we can do that. |
| 112 HPhi phi = successor.phis.first; |
| 113 if (phi != null) { |
| 114 int index = successor.predecessors.indexOf(block); |
| 115 HInstruction input = phi.inputs[index]; |
| 116 if (!generateAtUseSite.contains(input) |
| 117 && !input.isCodeMotionInvariant() |
| 118 && input.usedBy.length == 1 |
| 119 && input is! HPhi) { |
| 120 expectedInputs.add(input); |
| 121 } |
| 122 break; |
| 123 } |
| 124 } |
| 125 |
| 106 block.last.accept(this); | 126 block.last.accept(this); |
| 107 for (HInstruction instruction = block.last.previous; | 127 for (HInstruction instruction = block.last.previous; |
| 108 instruction !== null; | 128 instruction !== null; |
| 109 instruction = instruction.previous) { | 129 instruction = instruction.previous) { |
| 110 if (generateAtUseSite.contains(instruction)) { | 130 if (generateAtUseSite.contains(instruction)) { |
| 111 continue; | 131 continue; |
| 112 } | 132 } |
| 113 if (instruction.isCodeMotionInvariant()) { | 133 if (instruction.isCodeMotionInvariant()) { |
| 114 generateAtUseSite.add(instruction); | 134 generateAtUseSite.add(instruction); |
| 115 continue; | 135 continue; |
| 116 } | 136 } |
| 117 bool foundInInputs = false; | 137 bool foundInInputs = false; |
| 118 // See if the current instruction is the next non-trivial | 138 // See if the current instruction is the next non-trivial |
| 119 // expected input. If not, drop the expectedInputs and | 139 // expected input. If not, drop the expectedInputs and |
| 120 // start over. | 140 // start over. |
| 121 if (findInInputs(instruction)) { | 141 if (findInInputs(instruction)) { |
| 122 foundInInputs = true; | 142 foundInInputs = true; |
| 123 tryGenerateAtUseSite(instruction); | 143 tryGenerateAtUseSite(instruction); |
| 124 } else { | 144 } else { |
| 125 assert(expectedInputs.isEmpty()); | 145 assert(expectedInputs.isEmpty()); |
| 126 } | 146 } |
| 127 if (foundInInputs || usedOnlyByPhis(instruction)) { | 147 if (foundInInputs || usedOnlyByPhis(instruction)) { |
| 128 // Try merging all non-trivial inputs. | 148 // Try merging all non-trivial inputs. |
| 129 instruction.accept(this); | 149 instruction.accept(this); |
| 130 } | 150 } |
| 131 } | 151 } |
| 132 | 152 |
| 133 if (block.predecessors.length === 1 | 153 if (block.predecessors.length === 1 |
| 134 && isBlockSinglePredecessor(block.predecessors[0])) { | 154 && isBlockSinglePredecessor(block.predecessors[0])) { |
| 155 assert(block.phis.isEmpty()); |
| 135 tryMergingExpressions(block.predecessors[0]); | 156 tryMergingExpressions(block.predecessors[0]); |
| 136 } else { | 157 } else { |
| 137 expectedInputs = null; | 158 expectedInputs = null; |
| 138 } | 159 } |
| 139 } | 160 } |
| 140 } | 161 } |
| 141 | 162 |
| 142 /** | 163 /** |
| 143 * Detect control flow arising from short-circuit logical operators, and | 164 * Detect control flow arising from short-circuit logical operators, and |
| 144 * prepare the program to be generated using these operators instead of | 165 * prepare the program to be generated using these operators instead of |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 // improving the performance of future lookups. | 431 // improving the performance of future lookups. |
| 411 T root = getRepresentative(parent); | 432 T root = getRepresentative(parent); |
| 412 if (root !== parent) representative[element] = root; | 433 if (root !== parent) representative[element] = root; |
| 413 return root; | 434 return root; |
| 414 } | 435 } |
| 415 | 436 |
| 416 bool areEquivalent(T a, T b) { | 437 bool areEquivalent(T a, T b) { |
| 417 return getRepresentative(a) === getRepresentative(b); | 438 return getRepresentative(a) === getRepresentative(b); |
| 418 } | 439 } |
| 419 } | 440 } |
| OLD | NEW |