Chromium Code Reviews| 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 void markAsGenerateAtUseSite(HInstruction instruction) { | |
| 20 assert(!instruction.isStatement); | |
| 21 generateAtUseSite.add(instruction); | |
| 22 } | |
| 23 | |
| 19 SsaInstructionMerger(this.generateAtUseSite); | 24 SsaInstructionMerger(this.generateAtUseSite); |
| 20 | 25 |
| 21 void visitGraph(HGraph graph) { | 26 void visitGraph(HGraph graph) { |
| 22 visitDominatorTree(graph); | 27 visitDominatorTree(graph); |
| 23 } | 28 } |
| 24 | 29 |
| 25 void visitInstruction(HInstruction instruction) { | 30 void visitInstruction(HInstruction instruction) { |
| 26 // A code motion invariant instruction is dealt before visiting it. | 31 // A code motion invariant instruction is dealt before visiting it. |
| 27 assert(!instruction.isCodeMotionInvariant()); | 32 assert(!instruction.isCodeMotionInvariant()); |
| 28 for (HInstruction input in instruction.inputs) { | 33 for (HInstruction input in instruction.inputs) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 53 if (!instruction.builtin) super.visitEquals(instruction); | 58 if (!instruction.builtin) super.visitEquals(instruction); |
| 54 // Otherwise do nothing. | 59 // Otherwise do nothing. |
| 55 } | 60 } |
| 56 | 61 |
| 57 // Identity operations must not have its input generated at use site, because | 62 // Identity operations must not have its input generated at use site, because |
| 58 // it's using it multiple times (because of null/undefined). | 63 // it's using it multiple times (because of null/undefined). |
| 59 void visitIdentity(HIdentity instruction) {} | 64 void visitIdentity(HIdentity instruction) {} |
| 60 | 65 |
| 61 void visitTypeConversion(HTypeConversion instruction) { | 66 void visitTypeConversion(HTypeConversion instruction) { |
| 62 if (!instruction.isChecked) { | 67 if (!instruction.isChecked) { |
| 63 generateAtUseSite.add(instruction); | 68 markAsGenerateAtUseSite(instruction); |
| 64 } else if (instruction.isCheckedModeCheck) { | 69 } else if (instruction.isCheckedModeCheck) { |
| 65 // Checked mode checks compile to code that only use their input | 70 // Checked mode checks compile to code that only use their input |
| 66 // once, so we can safely visit them and try to merge the input. | 71 // once, so we can safely visit them and try to merge the input. |
| 67 visitInstruction(instruction); | 72 visitInstruction(instruction); |
| 68 } | 73 } |
| 69 } | 74 } |
| 70 | 75 |
| 71 void tryGenerateAtUseSite(HInstruction instruction) { | 76 void tryGenerateAtUseSite(HInstruction instruction) { |
| 72 if (instruction.isControlFlow()) return; | 77 if (instruction.isControlFlow()) return; |
| 73 generateAtUseSite.add(instruction); | 78 markAsGenerateAtUseSite(instruction); |
| 74 } | 79 } |
| 75 | 80 |
| 76 bool isBlockSinglePredecessor(HBasicBlock block) { | 81 bool isBlockSinglePredecessor(HBasicBlock block) { |
| 77 return block.successors.length === 1 | 82 return block.successors.length === 1 |
| 78 && block.successors[0].predecessors.length === 1; | 83 && block.successors[0].predecessors.length === 1; |
| 79 } | 84 } |
| 80 | 85 |
| 81 void visitBasicBlock(HBasicBlock block) { | 86 void visitBasicBlock(HBasicBlock block) { |
| 82 // Compensate from not merging blocks: if the block is the | 87 // Compensate from not merging blocks: if the block is the |
| 83 // single predecessor of its single successor, let the successor | 88 // single predecessor of its single successor, let the successor |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 112 } | 117 } |
| 113 | 118 |
| 114 block.last.accept(this); | 119 block.last.accept(this); |
| 115 for (HInstruction instruction = block.last.previous; | 120 for (HInstruction instruction = block.last.previous; |
| 116 instruction !== null; | 121 instruction !== null; |
| 117 instruction = instruction.previous) { | 122 instruction = instruction.previous) { |
| 118 if (generateAtUseSite.contains(instruction)) { | 123 if (generateAtUseSite.contains(instruction)) { |
| 119 continue; | 124 continue; |
| 120 } | 125 } |
| 121 if (instruction.isCodeMotionInvariant()) { | 126 if (instruction.isCodeMotionInvariant()) { |
| 122 generateAtUseSite.add(instruction); | 127 markAsGenerateAtUseSite(instruction); |
| 123 continue; | 128 continue; |
| 124 } | 129 } |
| 130 if (instruction.isStatement) { | |
|
ngeoffray
2012/08/17 13:08:58
Please explain which inputs can be statements. May
floitsch
2012/08/29 11:03:12
Changed to isJsStatement.
| |
| 131 expectedInputs.clear(); | |
| 132 } | |
| 125 // See if the current instruction is the next non-trivial | 133 // See if the current instruction is the next non-trivial |
| 126 // expected input. | 134 // expected input. |
| 127 if (findInInputsAndPopNonMatching(instruction)) { | 135 if (findInInputsAndPopNonMatching(instruction)) { |
| 128 tryGenerateAtUseSite(instruction); | 136 tryGenerateAtUseSite(instruction); |
| 129 } else { | 137 } else { |
| 130 assert(expectedInputs.isEmpty()); | 138 assert(expectedInputs.isEmpty()); |
| 131 } | 139 } |
| 132 instruction.accept(this); | 140 instruction.accept(this); |
| 133 } | 141 } |
| 134 | 142 |
| 135 if (block.predecessors.length === 1 | 143 if (block.predecessors.length === 1 |
| 136 && isBlockSinglePredecessor(block.predecessors[0])) { | 144 && isBlockSinglePredecessor(block.predecessors[0])) { |
| 137 assert(block.phis.isEmpty()); | 145 assert(block.phis.isEmpty()); |
| 138 tryMergingExpressions(block.predecessors[0]); | 146 tryMergingExpressions(block.predecessors[0]); |
| 139 } else { | 147 } else { |
| 140 expectedInputs = null; | 148 expectedInputs = null; |
| 141 } | 149 } |
| 142 } | 150 } |
| 143 } | 151 } |
| 144 | 152 |
| 145 /** | 153 /** |
| 146 * Detect control flow arising from short-circuit logical and | 154 * Detect control flow arising from short-circuit logical and |
| 147 * conditional operators, and prepare the program to be generated | 155 * conditional operators, and prepare the program to be generated |
| 148 * using these operators instead of nested ifs and boolean variables. | 156 * using these operators instead of nested ifs and boolean variables. |
| 149 */ | 157 */ |
| 150 class SsaConditionMerger extends HGraphVisitor { | 158 class SsaConditionMerger extends HGraphVisitor { |
| 151 Set<HInstruction> generateAtUseSite; | 159 Set<HInstruction> generateAtUseSite; |
| 152 Set<HInstruction> controlFlowOperators; | 160 Set<HInstruction> controlFlowOperators; |
| 153 | 161 |
| 162 void markAsGenerateAtUseSite(HInstruction instruction) { | |
| 163 assert(!instruction.isStatement); | |
| 164 generateAtUseSite.add(instruction); | |
| 165 } | |
| 166 | |
| 154 SsaConditionMerger(this.generateAtUseSite, this.controlFlowOperators); | 167 SsaConditionMerger(this.generateAtUseSite, this.controlFlowOperators); |
| 155 | 168 |
| 156 void visitGraph(HGraph graph) { | 169 void visitGraph(HGraph graph) { |
| 157 visitPostDominatorTree(graph); | 170 visitPostDominatorTree(graph); |
| 158 } | 171 } |
| 159 | 172 |
| 160 /** | 173 /** |
| 161 * Check if a block has at least one statement other than | 174 * Check if a block has at least one statement other than |
| 162 * [instruction]. | 175 * [instruction]. |
| 163 */ | 176 */ |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 215 // phi(expr, true|false) | 228 // phi(expr, true|false) |
| 216 if (end == null) return; | 229 if (end == null) return; |
| 217 if (end.phis.isEmpty()) return; | 230 if (end.phis.isEmpty()) return; |
| 218 if (end.phis.first !== end.phis.last) return; | 231 if (end.phis.first !== end.phis.last) return; |
| 219 HBasicBlock elseBlock = startIf.elseBlock; | 232 HBasicBlock elseBlock = startIf.elseBlock; |
| 220 | 233 |
| 221 if (end.predecessors[1] !== elseBlock) return; | 234 if (end.predecessors[1] !== elseBlock) return; |
| 222 HPhi phi = end.phis.first; | 235 HPhi phi = end.phis.first; |
| 223 HInstruction thenInput = phi.inputs[0]; | 236 HInstruction thenInput = phi.inputs[0]; |
| 224 HInstruction elseInput = phi.inputs[1]; | 237 HInstruction elseInput = phi.inputs[1]; |
| 238 if (thenInput.isStatement || elseInput.isStatement) return; | |
| 225 | 239 |
| 226 if (hasAnyStatement(elseBlock, elseInput)) return; | 240 if (hasAnyStatement(elseBlock, elseInput)) return; |
| 227 assert(elseBlock.successors.length == 1); | 241 assert(elseBlock.successors.length == 1); |
| 228 assert(end.predecessors.length == 2); | 242 assert(end.predecessors.length == 2); |
| 229 | 243 |
| 230 HBasicBlock thenBlock = startIf.thenBlock; | 244 HBasicBlock thenBlock = startIf.thenBlock; |
| 231 // Skip trivial goto blocks. | 245 // Skip trivial goto blocks. |
| 232 while (thenBlock.successors[0] != end && thenBlock.first is HGoto) { | 246 while (thenBlock.successors[0] != end && thenBlock.first is HGoto) { |
| 233 thenBlock = thenBlock.successors[0]; | 247 thenBlock = thenBlock.successors[0]; |
| 234 } | 248 } |
| 235 | 249 |
| 236 // If the [thenBlock] is already a control flow operation, and does not | 250 // If the [thenBlock] is already a control flow operation, and does not |
| 237 // have any statement and its join block is [end], we can emit a | 251 // have any statement and its join block is [end], we can emit a |
| 238 // sequence of control flow operation. | 252 // sequence of control flow operation. |
| 239 if (controlFlowOperators.contains(thenBlock.last)) { | 253 if (controlFlowOperators.contains(thenBlock.last)) { |
| 240 HIf otherIf = thenBlock.last; | 254 HIf otherIf = thenBlock.last; |
| 241 if (otherIf.joinBlock !== end) return; | 255 if (otherIf.joinBlock !== end) return; |
| 242 if (hasAnyStatement(thenBlock, otherIf)) return; | 256 if (hasAnyStatement(thenBlock, otherIf)) return; |
| 243 } else { | 257 } else { |
| 244 if (end.predecessors[0] !== thenBlock) return; | 258 if (end.predecessors[0] !== thenBlock) return; |
| 245 if (hasAnyStatement(thenBlock, thenInput)) return; | 259 if (hasAnyStatement(thenBlock, thenInput)) return; |
| 246 assert(thenBlock.successors.length == 1); | 260 assert(thenBlock.successors.length == 1); |
| 247 } | 261 } |
| 248 | 262 |
| 249 // From now on, we have recognized a control flow operation built from | 263 // From now on, we have recognized a control flow operation built from |
| 250 // the builder. Mark the if instruction as such. | 264 // the builder. Mark the if instruction as such. |
| 251 controlFlowOperators.add(startIf); | 265 controlFlowOperators.add(startIf); |
| 252 | 266 |
| 253 // If the operation is only used by the first instruction | 267 // If the operation is only used by the first instruction |
| 254 // of its block and is safe to be generated at use sute, mark it | 268 // of its block and is safe to be generated at use site, mark it |
| 255 // so. | 269 // so. |
| 256 if (phi.usedBy.length == 1 | 270 if (phi.usedBy.length == 1 |
| 257 && phi.usedBy[0] === phi.block.first | 271 && phi.usedBy[0] === phi.block.first |
| 258 && isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { | 272 && isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { |
| 259 generateAtUseSite.add(phi); | 273 markAsGenerateAtUseSite(phi); |
| 260 } | 274 } |
| 261 | 275 |
| 262 if (elseInput.block === elseBlock) { | 276 if (elseInput.block === elseBlock) { |
| 263 assert(elseInput.usedBy.length == 1); | 277 assert(elseInput.usedBy.length == 1); |
| 264 generateAtUseSite.add(elseInput); | 278 markAsGenerateAtUseSite(elseInput); |
| 265 } | 279 } |
| 266 | 280 |
| 267 // If [thenInput] is defined in the first predecessor, then it is only used | 281 // If [thenInput] is defined in the first predecessor, then it is only used |
| 268 // by [phi] and can be generated at use site. | 282 // by [phi] and can be generated at use site. |
| 269 if (thenInput.block === end.predecessors[0]) { | 283 if (thenInput.block === end.predecessors[0]) { |
| 270 assert(thenInput.usedBy.length == 1); | 284 assert(thenInput.usedBy.length == 1); |
| 271 generateAtUseSite.add(thenInput); | 285 markAsGenerateAtUseSite(thenInput); |
| 272 } | 286 } |
| 273 } | 287 } |
| 274 } | 288 } |
| 275 | 289 |
| 276 // Precedence information for JavaScript operators. | 290 // Precedence information for JavaScript operators. |
| 277 class JSPrecedence { | 291 class JSPrecedence { |
| 278 // Used as precedence for something that's not even an expression. | 292 // Used as precedence for something that's not even an expression. |
| 279 static final int STATEMENT_PRECEDENCE = 0; | 293 static final int STATEMENT_PRECEDENCE = 0; |
| 280 // Precedences of JS operators. | 294 // Precedences of JS operators. |
| 281 static final int EXPRESSION_PRECEDENCE = 1; | 295 static final int EXPRESSION_PRECEDENCE = 1; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 }; | 360 }; |
| 347 } | 361 } |
| 348 | 362 |
| 349 class JSBinaryOperatorPrecedence { | 363 class JSBinaryOperatorPrecedence { |
| 350 final int left; | 364 final int left; |
| 351 final int right; | 365 final int right; |
| 352 const JSBinaryOperatorPrecedence(this.left, this.right); | 366 const JSBinaryOperatorPrecedence(this.left, this.right); |
| 353 // All binary operators (excluding assignment) are left associative. | 367 // All binary operators (excluding assignment) are left associative. |
| 354 int get precedence() => left; | 368 int get precedence() => left; |
| 355 } | 369 } |
| OLD | NEW |