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; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 /** | 144 /** |
| 145 * Check if a block has at least one statement other than | 145 * Check if a block has at least one statement other than |
| 146 * [instruction]. | 146 * [instruction]. |
| 147 */ | 147 */ |
| 148 bool hasStatement(HBasicBlock block, HInstruction instruction) { | 148 bool hasStatement(HBasicBlock block, HInstruction instruction) { |
| 149 // If [instruction] is not in [block], then if the block is not | 149 // If [instruction] is not in [block], then if the block is not |
| 150 // empty, we know there will be a statement to emit. | 150 // empty, we know there will be a statement to emit. |
| 151 if (instruction.block !== block) return block.last !== block.first; | 151 if (instruction.block !== block) return block.last !== block.first; |
| 152 | 152 |
| 153 // If [instruction] is not the last instruction of the block | 153 // If [instruction] is not the last instruction of the block |
| 154 // before the control flow instruction, then we will have to emit | 154 // before the control flow instruction, or the last instruction, |
| 155 // a statement for that last instruction. | 155 // then we will have to emit a statement for that last instruction. |
| 156 if (instruction !== block.last.previous) return true; | 156 if (instruction != block.last |
| 157 && instruction !== block.last.previous) return true; | |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
Putting "&&" at the end of the previous line seems
| |
| 157 | 158 |
| 158 // If one of the instructions in the block until [instruction] is | 159 // If one of the instructions in the block until [instruction] is |
| 159 // not generated at use site, then we will have to emit a | 160 // not generated at use site, then we will have to emit a |
| 160 // statement for it. | 161 // statement for it. |
| 161 // TODO(ngeoffray): we could generate a comma separated | 162 // TODO(ngeoffray): we could generate a comma separated |
| 162 // list of expressions. | 163 // list of expressions. |
| 163 for (HInstruction temp = block.first; | 164 for (HInstruction temp = block.first; |
| 164 temp !== instruction; | 165 temp !== instruction; |
| 165 temp = temp.next) { | 166 temp = temp.next) { |
| 166 if (!generateAtUseSite.contains(temp)) return true; | 167 if (!generateAtUseSite.contains(temp)) return true; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 179 // / \ | 180 // / \ |
| 180 // / \ | 181 // / \ |
| 181 // 1 expr goto | 182 // 1 expr goto |
| 182 // goto / | 183 // goto / |
| 183 // \ / | 184 // \ / |
| 184 // \ / | 185 // \ / |
| 185 // phi(expr, true|false) | 186 // phi(expr, true|false) |
| 186 if (end == null) return; | 187 if (end == null) return; |
| 187 if (end.phis.isEmpty()) return; | 188 if (end.phis.isEmpty()) return; |
| 188 if (end.phis.first !== end.phis.last) return; | 189 if (end.phis.first !== end.phis.last) return; |
| 189 HBasicBlock thenBlock = startIf.thenBlock; | |
| 190 HBasicBlock elseBlock = startIf.elseBlock; | 190 HBasicBlock elseBlock = startIf.elseBlock; |
| 191 if (end.predecessors[0] !== thenBlock) return; | 191 |
| 192 if (end.predecessors[1] !== elseBlock) return; | 192 if (end.predecessors[1] !== elseBlock) return; |
| 193 HPhi phi = end.phis.first; | 193 HPhi phi = end.phis.first; |
| 194 if (!phi.inputs[1].isConstantBoolean()) return; | 194 if (!phi.inputs[1].isConstantBoolean()) return; |
| 195 if (elseBlock.first !== elseBlock.last) return; | |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
Or "if (elseBlock.first is! HGoto) return;"?
ngeoffray
2012/06/07 12:39:18
Done.
| |
| 196 | |
| 197 HBasicBlock thenBlock = startIf.thenBlock; | |
| 198 // Skip trivial goto blocks. | |
| 199 while (thenBlock.successors[0] != end | |
| 200 && thenBlock.first == thenBlock.last | |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
You could just check that thenBlock.first is HGoto
ngeoffray
2012/06/07 12:39:18
Done.
| |
| 201 && thenBlock.last is HGoto) { | |
| 202 thenBlock = thenBlock.successors[0]; | |
| 203 } | |
| 195 | 204 |
| 196 HInstruction thenInput = phi.inputs[0]; | 205 HInstruction thenInput = phi.inputs[0]; |
| 197 if (hasStatement(thenBlock, thenInput)) return; | 206 |
| 198 if (elseBlock.first !== elseBlock.last) return; | 207 // If the [thenBlock] is already a logical operation, and does not |
| 199 | 208 // have statements, we can emit a sequence of logical operation. |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
"have a statement" to match the call to "hasStatem
ngeoffray
2012/06/07 12:39:18
Done.
| |
| 209 if (logicalOperations.contains(thenBlock.last)) { | |
| 210 if (hasStatement(thenBlock, thenBlock.last)) return; | |
| 211 assert(thenInput.usedBy.length == 1); | |
| 212 generateAtUseSite.add(thenInput); | |
| 213 } else { | |
| 214 if (end.predecessors[0] !== thenBlock) return; | |
| 215 if (hasStatement(thenBlock, thenInput)) return; | |
| 216 // If [thenInput] is defined in [thenBlock], then it is only used | |
| 217 // by [phi] and can be generated at use site. | |
| 218 if (thenInput.block === thenBlock) { | |
| 219 assert(thenInput.usedBy.length == 1); | |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
Can't it also be used internally in the block?
ngeoffray
2012/06/07 12:39:18
No, because otherwise there would be an instructio
| |
| 220 generateAtUseSite.add(thenInput); | |
| 221 } | |
| 222 } | |
| 223 | |
| 200 // From now on, we have recognized a logical operation built from | 224 // From now on, we have recognized a logical operation built from |
| 201 // the builder. We don't expect the builder and the optimizers to | 225 // the builder. We don't expect the builder and the optimizers to |
| 202 // generate the then and else branches with multiple successors, | 226 // generate the then and else branches with multiple successors, |
| 203 // and the join branch to have more than two predecessors. | 227 // and the join branch to have more than two predecessors. |
|
Lasse Reichstein Nielsen
2012/06/07 12:02:47
Then check if that's the case and return if it isn
ngeoffray
2012/06/07 12:39:18
Added asserts instead.
| |
| 204 | 228 |
| 205 // Mark the if instruction as a logical operation. | 229 // Mark the if instruction as a logical operation. |
| 206 logicalOperations.add(startIf); | 230 logicalOperations.add(startIf); |
| 207 | 231 |
| 208 // If the logical operation is only used by the first instruction | 232 // If the logical operation is only used by the first instruction |
| 209 // of its block, it can be generated at use site. | 233 // of its block, it can be generated at use site. |
| 210 if (phi.usedBy.length == 1 && phi.usedBy[0] === phi.block.first) { | 234 if (phi.usedBy.length == 1 && phi.usedBy[0] === phi.block.first) { |
| 211 generateAtUseSite.add(phi); | 235 generateAtUseSite.add(phi); |
| 212 } | 236 } |
| 213 | |
| 214 // If [thenInput] is defined in [thenBlock], then it is only used | |
| 215 // by [phi] and can be generated at use site. | |
| 216 if (thenInput.block === thenBlock) { | |
| 217 assert(thenInput.usedBy.length == 1); | |
| 218 generateAtUseSite.add(thenInput); | |
| 219 } | |
| 220 } | 237 } |
| 221 } | 238 } |
| 222 | 239 |
| 223 // Precedence information for JavaScript operators. | 240 // Precedence information for JavaScript operators. |
| 224 class JSPrecedence { | 241 class JSPrecedence { |
| 225 // Used as precedence for something that's not even an expression. | 242 // Used as precedence for something that's not even an expression. |
| 226 static final int STATEMENT_PRECEDENCE = 0; | 243 static final int STATEMENT_PRECEDENCE = 0; |
| 227 // Precedences of JS operators. | 244 // Precedences of JS operators. |
| 228 static final int EXPRESSION_PRECEDENCE = 1; | 245 static final int EXPRESSION_PRECEDENCE = 1; |
| 229 static final int ASSIGNMENT_PRECEDENCE = 2; | 246 static final int ASSIGNMENT_PRECEDENCE = 2; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 }; | 310 }; |
| 294 } | 311 } |
| 295 | 312 |
| 296 class JSBinaryOperatorPrecedence { | 313 class JSBinaryOperatorPrecedence { |
| 297 final int left; | 314 final int left; |
| 298 final int right; | 315 final int right; |
| 299 const JSBinaryOperatorPrecedence(this.left, this.right); | 316 const JSBinaryOperatorPrecedence(this.left, this.right); |
| 300 // All binary operators (excluding assignment) are left associative. | 317 // All binary operators (excluding assignment) are left associative. |
| 301 int get precedence() => left; | 318 int get precedence() => left; |
| 302 } | 319 } |
| OLD | NEW |