| 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 |