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 import '../compiler.dart' show Compiler; | 5 import '../compiler.dart' show Compiler; |
6 import '../constants/values.dart'; | 6 import '../constants/values.dart'; |
7 import '../elements/elements.dart'; | 7 import '../elements/elements.dart'; |
8 import '../js_backend/js_backend.dart'; | 8 import '../js_backend/js_backend.dart'; |
9 import '../types/types.dart'; | 9 import '../types/types.dart'; |
10 import '../universe/selector.dart' show Selector; | 10 import '../universe/selector.dart' show Selector; |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 void analyzeInputs(HInstruction user, int start) { | 346 void analyzeInputs(HInstruction user, int start) { |
347 List<HInstruction> inputs = user.inputs; | 347 List<HInstruction> inputs = user.inputs; |
348 for (int i = start; i < inputs.length; i++) { | 348 for (int i = start; i < inputs.length; i++) { |
349 HInstruction input = inputs[i]; | 349 HInstruction input = inputs[i]; |
350 if (!generateAtUseSite.contains(input) && | 350 if (!generateAtUseSite.contains(input) && |
351 !input.isCodeMotionInvariant() && | 351 !input.isCodeMotionInvariant() && |
352 input.usedBy.length == 1 && | 352 input.usedBy.length == 1 && |
353 input is! HPhi && | 353 input is! HPhi && |
354 input is! HLocalValue && | 354 input is! HLocalValue && |
355 !input.isJsStatement()) { | 355 !input.isJsStatement()) { |
356 if (input.isPure()) { | 356 if (isEffectivelyPure(input)) { |
357 // Only consider a pure input if it is in the same loop. | 357 // Only consider a pure input if it is in the same loop. |
358 // Otherwise, we might move GVN'ed instruction back into the | 358 // Otherwise, we might move GVN'ed instruction back into the |
359 // loop. | 359 // loop. |
360 if (user.hasSameLoopHeaderAs(input)) { | 360 if (user.hasSameLoopHeaderAs(input)) { |
361 // Move it closer to [user], so that instructions in | 361 // Move it closer to [user], so that instructions in |
362 // between do not prevent making it generate at use site. | 362 // between do not prevent making it generate at use site. |
363 input.moveBefore(user); | 363 input.moveBefore(user); |
364 pureInputs.add(input); | 364 pureInputs.add(input); |
365 // Previous computations done on [input] are now invalid | 365 // Previous computations done on [input] are now invalid |
366 // because we moved [input] to another place. So all | 366 // because we moved [input] to another place. So all |
367 // non code motion invariant instructions need | 367 // non code motion invariant instructions need |
368 // to be removed from the [generateAtUseSite] set. | 368 // to be removed from the [generateAtUseSite] set. |
369 input.inputs.forEach((instruction) { | 369 input.inputs.forEach((instruction) { |
370 if (!instruction.isCodeMotionInvariant()) { | 370 if (!instruction.isCodeMotionInvariant()) { |
371 generateAtUseSite.remove(instruction); | 371 generateAtUseSite.remove(instruction); |
372 } | 372 } |
373 }); | 373 }); |
374 // Visit the pure input now so that the expected inputs | 374 // Visit the pure input now so that the expected inputs |
375 // are after the expected inputs of [user]. | 375 // are after the expected inputs of [user]. |
376 input.accept(this); | 376 input.accept(this); |
377 } | 377 } |
378 } else { | 378 } else { |
379 expectedInputs.add(input); | 379 expectedInputs.add(input); |
380 } | 380 } |
381 } | 381 } |
382 } | 382 } |
383 } | 383 } |
384 | 384 |
| 385 // Some non-pure instructions may be treated as pure. HLocalGet depends on |
| 386 // assignments, but we can ignore the initializing assignment since it will by |
| 387 // construction always precede a use. |
| 388 bool isEffectivelyPure(HInstruction instruction) { |
| 389 if (instruction is HLocalGet) return !isAssignedLocal(instruction.local); |
| 390 return instruction.isPure(); |
| 391 } |
| 392 |
| 393 bool isAssignedLocal(HLocalValue local) { |
| 394 // [HLocalValue]s have an initializing assignment which is guaranteed to |
| 395 // precede the use, except for [HParameterValue]s which are 'assigned' at |
| 396 // entry. |
| 397 int initializingAssignmentCount = (local is HParameterValue) ? 0 : 1; |
| 398 return local.usedBy |
| 399 .where((user) => user is HLocalSet) |
| 400 .skip(initializingAssignmentCount) |
| 401 .isNotEmpty; |
| 402 } |
| 403 |
385 void visitInstruction(HInstruction instruction) { | 404 void visitInstruction(HInstruction instruction) { |
386 // A code motion invariant instruction is dealt before visiting it. | 405 // A code motion invariant instruction is dealt before visiting it. |
387 assert(!instruction.isCodeMotionInvariant()); | 406 assert(!instruction.isCodeMotionInvariant()); |
388 analyzeInputs(instruction, 0); | 407 analyzeInputs(instruction, 0); |
389 } | 408 } |
390 | 409 |
391 void visitInvokeSuper(HInvokeSuper instruction) { | 410 void visitInvokeSuper(HInvokeSuper instruction) { |
392 Element superMethod = instruction.element; | 411 Element superMethod = instruction.element; |
393 Selector selector = instruction.selector; | 412 Selector selector = instruction.selector; |
394 // If aliased super members cannot be used, we will generate code like | 413 // If aliased super members cannot be used, we will generate code like |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 // included in the expression. | 493 // included in the expression. |
475 | 494 |
476 // The expectedInputs list holds non-trivial instructions that may | 495 // The expectedInputs list holds non-trivial instructions that may |
477 // be generated at their use site, if they occur in the correct order. | 496 // be generated at their use site, if they occur in the correct order. |
478 if (expectedInputs == null) expectedInputs = new List<HInstruction>(); | 497 if (expectedInputs == null) expectedInputs = new List<HInstruction>(); |
479 if (pureInputs == null) pureInputs = new Set<HInstruction>(); | 498 if (pureInputs == null) pureInputs = new Set<HInstruction>(); |
480 | 499 |
481 // Pop instructions from expectedInputs until instruction is found. | 500 // Pop instructions from expectedInputs until instruction is found. |
482 // Return true if it is found, or false if not. | 501 // Return true if it is found, or false if not. |
483 bool findInInputsAndPopNonMatching(HInstruction instruction) { | 502 bool findInInputsAndPopNonMatching(HInstruction instruction) { |
484 assert(!instruction.isPure()); | 503 assert(!isEffectivelyPure(instruction)); |
485 while (!expectedInputs.isEmpty) { | 504 while (!expectedInputs.isEmpty) { |
486 HInstruction nextInput = expectedInputs.removeLast(); | 505 HInstruction nextInput = expectedInputs.removeLast(); |
487 assert(!generateAtUseSite.contains(nextInput)); | 506 assert(!generateAtUseSite.contains(nextInput)); |
488 assert(nextInput.usedBy.length == 1); | 507 assert(nextInput.usedBy.length == 1); |
489 if (identical(nextInput, instruction)) { | 508 if (identical(nextInput, instruction)) { |
490 return true; | 509 return true; |
491 } | 510 } |
492 } | 511 } |
493 return false; | 512 return false; |
494 } | 513 } |
495 | 514 |
496 block.last.accept(this); | 515 block.last.accept(this); |
497 for (HInstruction instruction = block.last.previous; | 516 for (HInstruction instruction = block.last.previous; |
498 instruction != null; | 517 instruction != null; |
499 instruction = instruction.previous) { | 518 instruction = instruction.previous) { |
500 if (generateAtUseSite.contains(instruction)) { | 519 if (generateAtUseSite.contains(instruction)) { |
501 continue; | 520 continue; |
502 } | 521 } |
503 if (instruction.isCodeMotionInvariant()) { | 522 if (instruction.isCodeMotionInvariant()) { |
504 markAsGenerateAtUseSite(instruction); | 523 markAsGenerateAtUseSite(instruction); |
505 continue; | 524 continue; |
506 } | 525 } |
507 if (instruction.isPure()) { | 526 if (isEffectivelyPure(instruction)) { |
508 if (pureInputs.contains(instruction)) { | 527 if (pureInputs.contains(instruction)) { |
509 tryGenerateAtUseSite(instruction); | 528 tryGenerateAtUseSite(instruction); |
510 } else { | 529 } else { |
511 // If the input is not in the [pureInputs] set, it has not | 530 // If the input is not in the [pureInputs] set, it has not |
512 // been visited or should not be generated at use-site. The most | 531 // been visited or should not be generated at use-site. The most |
513 // likely reason for the latter, is that the instruction is used | 532 // likely reason for the latter, is that the instruction is used |
514 // in more than one location. | 533 // in more than one location. |
515 // We must either clear the expectedInputs, or move the pure | 534 // We must either clear the expectedInputs, or move the pure |
516 // instruction's inputs in front of the existing ones. | 535 // instruction's inputs in front of the existing ones. |
517 // Example: | 536 // Example: |
(...skipping 25 matching lines...) Expand all Loading... |
543 // use(t3); | 562 // use(t3); |
544 // | 563 // |
545 // If we clear the expected-inputs we can't generate-at-use any of | 564 // If we clear the expected-inputs we can't generate-at-use any of |
546 // the instructions. | 565 // the instructions. |
547 // | 566 // |
548 // The optimal solution is to move the inputs of 'pure' in | 567 // The optimal solution is to move the inputs of 'pure' in |
549 // front of the expectedInputs list. This makes sense, since we | 568 // front of the expectedInputs list. This makes sense, since we |
550 // push expected-inputs from left-to right, and the `pure` function | 569 // push expected-inputs from left-to right, and the `pure` function |
551 // invocation is "more left" (i.e. before) the first argument of `f`. | 570 // invocation is "more left" (i.e. before) the first argument of `f`. |
552 // With that approach we end up with: | 571 // With that approach we end up with: |
553 // t3 = pure(foo(); | 572 // t3 = pure(foo()); |
554 // f(bar(), t3); | 573 // f(bar(), t3); |
555 // use(t3); | 574 // use(t3); |
556 // | 575 // |
557 int oldLength = expectedInputs.length; | 576 int oldLength = expectedInputs.length; |
558 instruction.accept(this); | 577 instruction.accept(this); |
559 if (oldLength != 0 && oldLength != expectedInputs.length) { | 578 if (oldLength != 0 && oldLength != expectedInputs.length) { |
560 // Move the pure instruction's inputs to the front. | 579 // Move the pure instruction's inputs to the front. |
561 List<HInstruction> newInputs = expectedInputs.sublist(oldLength); | 580 List<HInstruction> newInputs = expectedInputs.sublist(oldLength); |
562 int newCount = newInputs.length; | 581 int newCount = newInputs.length; |
563 expectedInputs.setRange( | 582 expectedInputs.setRange( |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 } | 777 } |
759 | 778 |
760 // If [thenInput] is defined in the first predecessor, then it is only used | 779 // If [thenInput] is defined in the first predecessor, then it is only used |
761 // by [phi] and can be generated at use site. | 780 // by [phi] and can be generated at use site. |
762 if (identical(thenInput.block, end.predecessors[0])) { | 781 if (identical(thenInput.block, end.predecessors[0])) { |
763 assert(thenInput.usedBy.length == 1); | 782 assert(thenInput.usedBy.length == 1); |
764 markAsGenerateAtUseSite(thenInput); | 783 markAsGenerateAtUseSite(thenInput); |
765 } | 784 } |
766 } | 785 } |
767 } | 786 } |
OLD | NEW |