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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Replaces some instructions with specialized versions to make codegen easier. | 8 * Replaces some instructions with specialized versions to make codegen easier. |
| 9 * Caches codegen information on nodes. | 9 * Caches codegen information on nodes. |
| 10 */ | 10 */ |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 for (HInstruction instruction = block.last.previous; | 278 for (HInstruction instruction = block.last.previous; |
| 279 instruction != null; | 279 instruction != null; |
| 280 instruction = instruction.previous) { | 280 instruction = instruction.previous) { |
| 281 if (generateAtUseSite.contains(instruction)) { | 281 if (generateAtUseSite.contains(instruction)) { |
| 282 continue; | 282 continue; |
| 283 } | 283 } |
| 284 if (instruction.isCodeMotionInvariant()) { | 284 if (instruction.isCodeMotionInvariant()) { |
| 285 markAsGenerateAtUseSite(instruction); | 285 markAsGenerateAtUseSite(instruction); |
| 286 continue; | 286 continue; |
| 287 } | 287 } |
| 288 if (instruction.isJsStatement()) { | |
|
kasperl
2014/03/15 07:14:48
Can you enumerate the things we use isJsStatement
floitsch
2014/03/17 10:26:14
It informs `generateAtUseSite` that the node must
| |
| 289 expectedInputs.clear(); | |
| 290 } | |
| 291 if (instruction.isPure()) { | 288 if (instruction.isPure()) { |
| 292 if (pureInputs.contains(instruction)) { | 289 if (pureInputs.contains(instruction)) { |
| 293 tryGenerateAtUseSite(instruction); | 290 tryGenerateAtUseSite(instruction); |
| 294 } else { | 291 } else { |
| 295 // If the input is not in the [pureInputs] set, it has not | 292 // If the input is not in the [pureInputs] set, it has not |
| 296 // been visited. | 293 // been visited or should not be generated at use-site. The most |
| 294 // likely reason for the latter, is that the instruction is used | |
| 295 // in more than one location. | |
| 296 // We must either clear the expectedInputs, or move the pure | |
| 297 // instruction's inputs in front of the existing ones. | |
| 298 // Example: | |
| 299 // t1 = foo(); // side-effect. | |
| 300 // t2 = bar(); // side-effect. | |
| 301 // t3 = pure(t2); // used more than once. | |
| 302 // f(t1, t3); // expected inputs of 'f': t1. | |
| 303 // use(t3); | |
| 304 // | |
| 305 // If we don't clear the expected inputs we end up in a situation | |
| 306 // where pure pushes "t2" on top of "t1" leading to: | |
| 307 // | |
| 308 // t3 = pure(bar()); | |
| 309 // f(foo(), t3); | |
| 310 // use(t3); | |
| 311 // | |
| 312 // If we clear the expected-inputs list we have the correct | |
| 313 // output: | |
| 314 // t1 = foo(); | |
| 315 // t3 = pure(bar()); | |
| 316 // f(t1, t3); | |
| 317 // use(t3); | |
| 318 // | |
| 319 // Clearing is, however, not optimal. | |
| 320 // Example: | |
| 321 // t1 = foo(); // t1 is now used by `pure`. | |
| 322 // t2 = bar(); // t2 is now used by `f`. | |
| 323 // t3 = pure(t1); | |
| 324 // f(t2, t3); | |
| 325 // use(t3); | |
| 326 // | |
| 327 // If we clear the expected-inputs we can't generate-at-use any of | |
| 328 // the instructions. | |
| 329 // | |
| 330 // The optimal solution is to store move the inputs of 'pure' in | |
|
kasperl
2014/03/15 07:10:56
store move -> move
floitsch
2014/03/17 10:26:14
Done.
| |
| 331 // front of the expectedInputs list. This makes sense, since we | |
| 332 // push expected-inputs from left-to right, and the `pure` function | |
| 333 // invocation is "more left" (i.e. before) the first argument of `f`. | |
| 334 // With that approach we would end up with: | |
| 335 // t3 = pure(foo(); | |
| 336 // f(bar(), t3); | |
| 337 // use(t3); | |
| 338 // | |
| 339 // TODO(floitsch): should we keep existing inputs and move new inputs | |
|
kasperl
2014/03/15 07:10:56
File a bug for this?
floitsch
2014/03/17 10:26:14
Just implemented the optimization. -> removed the
| |
| 340 // to the front of the list? | |
| 341 expectedInputs.clear(); | |
| 297 instruction.accept(this); | 342 instruction.accept(this); |
| 298 } | 343 } |
| 299 } else { | 344 } else { |
| 300 if (findInInputsAndPopNonMatching(instruction)) { | 345 if (findInInputsAndPopNonMatching(instruction)) { |
| 301 // The current instruction is the next non-trivial | 346 // The current instruction is the next non-trivial |
| 302 // expected input. | 347 // expected input. |
| 303 tryGenerateAtUseSite(instruction); | 348 tryGenerateAtUseSite(instruction); |
| 304 } else { | 349 } else { |
| 305 assert(expectedInputs.isEmpty); | 350 assert(expectedInputs.isEmpty); |
| 306 } | 351 } |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 } | 529 } |
| 485 | 530 |
| 486 // If [thenInput] is defined in the first predecessor, then it is only used | 531 // If [thenInput] is defined in the first predecessor, then it is only used |
| 487 // by [phi] and can be generated at use site. | 532 // by [phi] and can be generated at use site. |
| 488 if (identical(thenInput.block, end.predecessors[0])) { | 533 if (identical(thenInput.block, end.predecessors[0])) { |
| 489 assert(thenInput.usedBy.length == 1); | 534 assert(thenInput.usedBy.length == 1); |
| 490 markAsGenerateAtUseSite(thenInput); | 535 markAsGenerateAtUseSite(thenInput); |
| 491 } | 536 } |
| 492 } | 537 } |
| 493 } | 538 } |
| OLD | NEW |