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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 * instructions up to the given [limit]. | 174 * instructions up to the given [limit]. |
| 175 * | 175 * |
| 176 * That is, all instructions starting after the [limit] block (at the branch | 176 * That is, all instructions starting after the [limit] block (at the branch |
| 177 * leading to the [instruction]) down to the given [instruction] can be | 177 * leading to the [instruction]) down to the given [instruction] can be |
| 178 * generated at use-site. | 178 * generated at use-site. |
| 179 */ | 179 */ |
| 180 bool isExpression(HInstruction instruction, HBasicBlock limit) { | 180 bool isExpression(HInstruction instruction, HBasicBlock limit) { |
| 181 if (instruction is HPhi && !logicalOperations.containsKey(instruction)) { | 181 if (instruction is HPhi && !logicalOperations.containsKey(instruction)) { |
| 182 return false; | 182 return false; |
| 183 } | 183 } |
| 184 HInstruction previous; | |
|
ngeoffray
2012/04/19 12:52:24
Unused variable?
Lasse Reichstein Nielsen
2012/04/19 13:13:07
Yes, removed.
| |
| 184 while (instruction.previous != null) { | 185 while (instruction.previous != null) { |
| 185 instruction = instruction.previous; | 186 instruction = instruction.previous; |
| 186 if (!generateAtUseSite.contains(instruction)) { | 187 if (!generateAtUseSite.contains(instruction)) { |
| 187 return false; | 188 return false; |
| 188 } | 189 } |
| 189 } | 190 } |
| 190 HBasicBlock block = instruction.block; | 191 HBasicBlock block = instruction.block; |
| 191 if (!block.phis.isEmpty()) return false; | 192 if (!block.phis.isEmpty()) { |
| 193 if (!generateAtUseSite.contains(instruction)) { | |
|
ngeoffray
2012/04/19 12:52:24
So this is the very first instruction of the block
Lasse Reichstein Nielsen
2012/04/19 13:13:07
Done.
Also took care of the case when [instruction
| |
| 194 return false; | |
| 195 } | |
| 196 instruction = block.phis.last; | |
| 197 if (block.phis.first !== instruction) { | |
|
ngeoffray
2012/04/19 12:52:24
block.phis.length != 1 reads better
Lasse Reichstein Nielsen
2012/04/19 13:13:07
But runs worse. [block.phis] is a [HInstructionLis
| |
| 198 return false; | |
| 199 } | |
| 200 } | |
| 192 if (instruction is HPhi && logicalOperations.containsKey(instruction)) { | 201 if (instruction is HPhi && logicalOperations.containsKey(instruction)) { |
| 193 return isExpression(instruction.inputs[0], limit); | 202 return isExpression(instruction.inputs[0], limit); |
| 194 } | 203 } |
| 195 return block.predecessors.length == 1 && block.predecessors[0] == limit; | 204 if (block.predecessors.length !== 1) { |
| 205 return false; | |
| 206 } | |
| 207 HBasicBlock previousBlock = block.predecessors[0]; | |
| 208 if (previousBlock === limit) return true; | |
| 209 if (previousBlock.successors.length !== 1 || | |
| 210 previousBlock.last is! HGoto) { | |
|
ngeoffray
2012/04/19 12:52:24
Should that check be isBlockSinglePredecessor inst
Lasse Reichstein Nielsen
2012/04/19 13:13:07
It's more, since it also checks that the HControlF
| |
| 211 return false; | |
| 212 } | |
| 213 return isExpression(previousBlock.last, limit); | |
| 196 } | 214 } |
| 197 | 215 |
| 198 void replaceWithLogicalOperator(HPhi phi, String type) { | 216 void replaceWithLogicalOperator(HPhi phi, String type) { |
| 199 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi); | 217 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi); |
| 200 logicalOperations[phi] = type; | 218 logicalOperations[phi] = type; |
| 219 // If the phi corresponds to logical control flow, mark the | |
| 220 // control-flow instructions as generate-at-use-site. | |
| 221 generateAtUseSite.add(phi.block.predecessors[0].last); | |
| 222 generateAtUseSite.add(phi.block.predecessors[1].last); | |
| 223 // If the first input is only used as branch condition and result, it too | |
| 224 // can be generate-at-use-site. | |
| 225 if (phi.inputs[0].usedBy.length == 2) { | |
| 226 generateAtUseSite.add(phi.inputs[0]); | |
| 227 } | |
| 228 if (phi.inputs[1].usedBy.length == 1) { | |
| 229 generateAtUseSite.add(phi.inputs[1]); | |
| 230 } | |
| 201 } | 231 } |
| 202 | 232 |
| 203 bool canGenerateAtUseSite(HPhi phi) { | 233 bool canGenerateAtUseSite(HPhi phi) { |
| 204 if (phi.usedBy.length != 1) return false; | 234 if (phi.usedBy.length != 1) { |
| 235 return false; | |
| 236 } | |
| 205 assert(phi.next == null); | 237 assert(phi.next == null); |
| 206 HInstruction use = phi.usedBy[0]; | 238 HInstruction use = phi.usedBy[0]; |
| 207 | 239 |
| 208 HInstruction current = phi.block.first; | 240 HInstruction current = phi.block.first; |
| 209 while (current != use) { | 241 while (current != use) { |
| 210 if (!generateAtUseSite.contains(current)) return false; | 242 if (current is! HControlFlow && !generateAtUseSite.contains(current)) { |
|
ngeoffray
2012/04/19 12:52:24
Please add a comment on why you check that.
Lasse Reichstein Nielsen
2012/04/19 13:13:07
Done.
| |
| 243 return false; | |
| 244 } | |
| 211 if (current.next != null) { | 245 if (current.next != null) { |
| 212 current = current.next; | 246 current = current.next; |
| 213 } else if (current is HPhi) { | 247 } else if (current is HPhi) { |
| 214 current = current.block.first; | 248 current = current.block.first; |
| 215 } else { | 249 } else { |
| 216 assert(current is HControlFlow); | 250 assert(current is HControlFlow); |
| 217 if (current is !HGoto) return false; | 251 if (current is !HGoto) { |
| 252 return false; | |
| 253 } | |
| 218 HBasicBlock nextBlock = current.block.successors[0]; | 254 HBasicBlock nextBlock = current.block.successors[0]; |
| 219 if (!nextBlock.phis.isEmpty()) { | 255 if (!nextBlock.phis.isEmpty()) { |
| 220 current = nextBlock.phis.first; | 256 current = nextBlock.phis.first; |
| 221 } else { | 257 } else { |
| 222 current = nextBlock.first; | 258 current = nextBlock.first; |
| 223 } | 259 } |
| 224 } | 260 } |
| 225 } | 261 } |
| 226 return true; | 262 return true; |
| 227 } | 263 } |
| 228 | 264 |
| 265 HInstruction previousInstruction(HInstruction instruction) { | |
| 266 if (instruction.previous != null) return instruction.previous; | |
| 267 HBasicBlock block = instruction.block; | |
| 268 if (instruction is! HPhi) { | |
| 269 if (block.phis.last != null) return block.phis.last; | |
| 270 } | |
| 271 if (block.predecessors.length == 1) { | |
| 272 HBasicBlock previousBlock = block.predecessors[0]; | |
| 273 if (previousBlock.last is HGoto) { | |
|
ngeoffray
2012/04/19 12:52:24
Use isBlockSinglePredecessor instead?
Lasse Reichstein Nielsen
2012/04/19 13:13:07
Don't have it. I don't think it's worth copying he
| |
| 274 assert(previousBlock.successors.length == 1); | |
| 275 assert(previousBlock.successors[0] === block); | |
| 276 return previousInstruction(previousBlock.last); | |
| 277 } | |
| 278 } | |
| 279 return null; | |
| 280 } | |
| 281 | |
| 229 void detectLogicControlFlow(HPhi phi) { | 282 void detectLogicControlFlow(HPhi phi) { |
| 230 // Check for the most common pattern for a short-circuit logic operation: | 283 // Check for the most common pattern for a short-circuit logic operation: |
| 231 // B0 b0 = ...; if (b0) goto B1 else B2 (or: if (!b0) goto B2 else B1) | 284 // B0 b0 = ...; if (b0) goto B1 else B2 (or: if (!b0) goto B2 else B1) |
| 232 // |\ | 285 // |\ |
| 233 // | B1 b1 = ...; goto B2 | 286 // | B1 b1 = ...; goto B2 |
| 234 // |/ | 287 // |/ |
| 235 // B2 b2 = phi(b0,b1); if(b2) ... | 288 // B2 b2 = phi(b0,b1); if(b2) ... |
| 236 // TODO(lrn): Also recognize ?:-flow? | 289 // TODO(lrn): Also recognize ?:-flow? |
| 237 | |
| 238 if (phi.inputs.length != 2) return; | 290 if (phi.inputs.length != 2) return; |
| 291 HBasicBlock firstBlock = phi.block.predecessors[0]; | |
| 292 HBasicBlock secondBlock = phi.block.predecessors[1]; | |
|
ngeoffray
2012/04/19 12:52:24
How it was written before read better for me.
Lasse Reichstein Nielsen
2012/04/19 13:13:07
Reordered.
| |
| 239 HInstruction first = phi.inputs[0]; | 293 HInstruction first = phi.inputs[0]; |
| 240 HBasicBlock firstBlock = first.block; | |
| 241 HInstruction second = phi.inputs[1]; | 294 HInstruction second = phi.inputs[1]; |
| 242 HBasicBlock secondBlock = second.block; | |
| 243 // Check second input of phi being an expression followed by a goto. | 295 // Check second input of phi being an expression followed by a goto. |
| 244 if (second.usedBy.length != 1) return; | 296 if (second.usedBy.length != 1) return; |
| 245 HInstruction secondNext = | 297 HInstruction secondNext = |
| 246 (second is HPhi) ? secondBlock.first : second.next; | 298 (second is HPhi) ? secondBlock.first : second.next; |
| 247 if (secondNext != secondBlock.last) return; | 299 if (secondNext != secondBlock.last) return; |
| 248 if (secondBlock.last is !HGoto) return; | 300 if (secondBlock.last is !HGoto) return; |
| 249 if (secondBlock.successors[0] != phi.block) return; | 301 if (secondBlock.successors[0] != phi.block) return; |
| 250 if (!isExpression(second, firstBlock)) return; | 302 if (!isExpression(second, firstBlock)) return; |
| 251 // Check first input of phi being followed by a (possibly negated) | 303 // Check first input of phi being followed by a (possibly negated) |
| 252 // conditional branch based on the same value. | 304 // conditional branch based on the same value. |
| 253 if (firstBlock != phi.block.dominator) return; | 305 if (firstBlock != phi.block.dominator) return; |
| 254 if (firstBlock.last is !HConditionalBranch) return; | 306 if (firstBlock.last is! HIf) return; |
| 255 HConditionalBranch firstBranch = firstBlock.last; | |
| 256 // Must be used both for value and for control to avoid the second branch. | |
| 257 if (first.usedBy.length != 2) return; | |
| 258 if (firstBlock.successors[1] != phi.block) return; | 307 if (firstBlock.successors[1] != phi.block) return; |
| 259 HInstruction firstNext = (first is HPhi) ? firstBlock.first : first.next; | 308 HIf firstBranch = firstBlock.last; |
| 260 if (firstNext == firstBranch && | 309 HInstruction condition = firstBranch.inputs[0]; |
| 261 firstBranch.condition == first) { | 310 if (condition === first) { |
| 262 replaceWithLogicalOperator(phi, "&&"); | 311 replaceWithLogicalOperator(phi, "&&"); |
| 263 } else if (firstNext is HNot && | 312 } else if (condition is HNot && |
| 264 firstNext.inputs[0] == first && | 313 condition.inputs[0] == first) { |
| 265 generateAtUseSite.contains(firstNext) && | |
| 266 firstNext.next == firstBlock.last && | |
| 267 firstBranch.condition == firstNext) { | |
| 268 replaceWithLogicalOperator(phi, "||"); | 314 replaceWithLogicalOperator(phi, "||"); |
| 269 } else { | 315 // If the negation is only used by this logical operation, or only by |
| 270 return; | 316 // logical operators in general, it won't need to be generated. |
| 317 if (!generateAtUseSite.contains(condition)) { | |
| 318 for (HInstruction user in condition.usedBy) { | |
| 319 if (user is! HIf || !generateAtUseSite.contains(user)) { | |
| 320 return; | |
| 321 } | |
| 322 } | |
| 323 generateAtUseSite.add(condition); | |
| 324 } | |
| 271 } | 325 } |
| 272 // Detected as logic control flow. Mark the corresponding | 326 return; |
| 273 // inputs as generated at use site. These will now be generated | |
| 274 // as part of an expression. | |
| 275 generateAtUseSite.add(first); | |
| 276 generateAtUseSite.add(firstBlock.last); | |
| 277 generateAtUseSite.add(second); | |
| 278 generateAtUseSite.add(secondBlock.last); | |
| 279 } | 327 } |
| 280 | 328 |
| 281 void visitBasicBlock(HBasicBlock block) { | 329 void visitBasicBlock(HBasicBlock block) { |
| 282 if (!block.phis.isEmpty() && | 330 if (!block.phis.isEmpty() && |
| 283 block.phis.first == block.phis.last) { | 331 block.phis.first === block.phis.last) { |
| 284 detectLogicControlFlow(block.phis.first); | 332 detectLogicControlFlow(block.phis.first); |
| 285 } | 333 } |
| 286 } | 334 } |
| 287 } | 335 } |
| 288 | 336 |
| 289 // Precedence information for JavaScript operators. | 337 // Precedence information for JavaScript operators. |
| 290 class JSPrecedence { | 338 class JSPrecedence { |
| 291 // Used as precedence for something that's not even an expression. | 339 // Used as precedence for something that's not even an expression. |
| 292 static final int STATEMENT_PRECEDENCE = 0; | 340 static final int STATEMENT_PRECEDENCE = 0; |
| 293 // Precedences of JS operators. | 341 // Precedences of JS operators. |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 // improving the performance of future lookups. | 473 // improving the performance of future lookups. |
| 426 T root = getRepresentative(parent); | 474 T root = getRepresentative(parent); |
| 427 if (root !== parent) representative[element] = root; | 475 if (root !== parent) representative[element] = root; |
| 428 return root; | 476 return root; |
| 429 } | 477 } |
| 430 | 478 |
| 431 bool areEquivalent(T a, T b) { | 479 bool areEquivalent(T a, T b) { |
| 432 return getRepresentative(a) === getRepresentative(b); | 480 return getRepresentative(a) === getRepresentative(b); |
| 433 } | 481 } |
| 434 } | 482 } |
| OLD | NEW |