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 (isEffectivelyPure(input)) { | 356 if (input.isPure()) { |
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 | |
404 void visitInstruction(HInstruction instruction) { | 385 void visitInstruction(HInstruction instruction) { |
405 // A code motion invariant instruction is dealt before visiting it. | 386 // A code motion invariant instruction is dealt before visiting it. |
406 assert(!instruction.isCodeMotionInvariant()); | 387 assert(!instruction.isCodeMotionInvariant()); |
407 analyzeInputs(instruction, 0); | 388 analyzeInputs(instruction, 0); |
408 } | 389 } |
409 | 390 |
410 void visitInvokeSuper(HInvokeSuper instruction) { | 391 void visitInvokeSuper(HInvokeSuper instruction) { |
411 Element superMethod = instruction.element; | 392 Element superMethod = instruction.element; |
412 Selector selector = instruction.selector; | 393 Selector selector = instruction.selector; |
413 // If aliased super members cannot be used, we will generate code like | 394 // 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... |
493 // included in the expression. | 474 // included in the expression. |
494 | 475 |
495 // The expectedInputs list holds non-trivial instructions that may | 476 // The expectedInputs list holds non-trivial instructions that may |
496 // be generated at their use site, if they occur in the correct order. | 477 // be generated at their use site, if they occur in the correct order. |
497 if (expectedInputs == null) expectedInputs = new List<HInstruction>(); | 478 if (expectedInputs == null) expectedInputs = new List<HInstruction>(); |
498 if (pureInputs == null) pureInputs = new Set<HInstruction>(); | 479 if (pureInputs == null) pureInputs = new Set<HInstruction>(); |
499 | 480 |
500 // Pop instructions from expectedInputs until instruction is found. | 481 // Pop instructions from expectedInputs until instruction is found. |
501 // Return true if it is found, or false if not. | 482 // Return true if it is found, or false if not. |
502 bool findInInputsAndPopNonMatching(HInstruction instruction) { | 483 bool findInInputsAndPopNonMatching(HInstruction instruction) { |
503 assert(!isEffectivelyPure(instruction)); | 484 assert(!instruction.isPure()); |
504 while (!expectedInputs.isEmpty) { | 485 while (!expectedInputs.isEmpty) { |
505 HInstruction nextInput = expectedInputs.removeLast(); | 486 HInstruction nextInput = expectedInputs.removeLast(); |
506 assert(!generateAtUseSite.contains(nextInput)); | 487 assert(!generateAtUseSite.contains(nextInput)); |
507 assert(nextInput.usedBy.length == 1); | 488 assert(nextInput.usedBy.length == 1); |
508 if (identical(nextInput, instruction)) { | 489 if (identical(nextInput, instruction)) { |
509 return true; | 490 return true; |
510 } | 491 } |
511 } | 492 } |
512 return false; | 493 return false; |
513 } | 494 } |
514 | 495 |
515 block.last.accept(this); | 496 block.last.accept(this); |
516 for (HInstruction instruction = block.last.previous; | 497 for (HInstruction instruction = block.last.previous; |
517 instruction != null; | 498 instruction != null; |
518 instruction = instruction.previous) { | 499 instruction = instruction.previous) { |
519 if (generateAtUseSite.contains(instruction)) { | 500 if (generateAtUseSite.contains(instruction)) { |
520 continue; | 501 continue; |
521 } | 502 } |
522 if (instruction.isCodeMotionInvariant()) { | 503 if (instruction.isCodeMotionInvariant()) { |
523 markAsGenerateAtUseSite(instruction); | 504 markAsGenerateAtUseSite(instruction); |
524 continue; | 505 continue; |
525 } | 506 } |
526 if (isEffectivelyPure(instruction)) { | 507 if (instruction.isPure()) { |
527 if (pureInputs.contains(instruction)) { | 508 if (pureInputs.contains(instruction)) { |
528 tryGenerateAtUseSite(instruction); | 509 tryGenerateAtUseSite(instruction); |
529 } else { | 510 } else { |
530 // If the input is not in the [pureInputs] set, it has not | 511 // If the input is not in the [pureInputs] set, it has not |
531 // been visited or should not be generated at use-site. The most | 512 // been visited or should not be generated at use-site. The most |
532 // likely reason for the latter, is that the instruction is used | 513 // likely reason for the latter, is that the instruction is used |
533 // in more than one location. | 514 // in more than one location. |
534 // We must either clear the expectedInputs, or move the pure | 515 // We must either clear the expectedInputs, or move the pure |
535 // instruction's inputs in front of the existing ones. | 516 // instruction's inputs in front of the existing ones. |
536 // Example: | 517 // Example: |
(...skipping 25 matching lines...) Expand all Loading... |
562 // use(t3); | 543 // use(t3); |
563 // | 544 // |
564 // If we clear the expected-inputs we can't generate-at-use any of | 545 // If we clear the expected-inputs we can't generate-at-use any of |
565 // the instructions. | 546 // the instructions. |
566 // | 547 // |
567 // The optimal solution is to move the inputs of 'pure' in | 548 // The optimal solution is to move the inputs of 'pure' in |
568 // front of the expectedInputs list. This makes sense, since we | 549 // front of the expectedInputs list. This makes sense, since we |
569 // push expected-inputs from left-to right, and the `pure` function | 550 // push expected-inputs from left-to right, and the `pure` function |
570 // invocation is "more left" (i.e. before) the first argument of `f`. | 551 // invocation is "more left" (i.e. before) the first argument of `f`. |
571 // With that approach we end up with: | 552 // With that approach we end up with: |
572 // t3 = pure(foo()); | 553 // t3 = pure(foo(); |
573 // f(bar(), t3); | 554 // f(bar(), t3); |
574 // use(t3); | 555 // use(t3); |
575 // | 556 // |
576 int oldLength = expectedInputs.length; | 557 int oldLength = expectedInputs.length; |
577 instruction.accept(this); | 558 instruction.accept(this); |
578 if (oldLength != 0 && oldLength != expectedInputs.length) { | 559 if (oldLength != 0 && oldLength != expectedInputs.length) { |
579 // Move the pure instruction's inputs to the front. | 560 // Move the pure instruction's inputs to the front. |
580 List<HInstruction> newInputs = expectedInputs.sublist(oldLength); | 561 List<HInstruction> newInputs = expectedInputs.sublist(oldLength); |
581 int newCount = newInputs.length; | 562 int newCount = newInputs.length; |
582 expectedInputs.setRange( | 563 expectedInputs.setRange( |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 } | 758 } |
778 | 759 |
779 // If [thenInput] is defined in the first predecessor, then it is only used | 760 // If [thenInput] is defined in the first predecessor, then it is only used |
780 // by [phi] and can be generated at use site. | 761 // by [phi] and can be generated at use site. |
781 if (identical(thenInput.block, end.predecessors[0])) { | 762 if (identical(thenInput.block, end.predecessors[0])) { |
782 assert(thenInput.usedBy.length == 1); | 763 assert(thenInput.usedBy.length == 1); |
783 markAsGenerateAtUseSite(thenInput); | 764 markAsGenerateAtUseSite(thenInput); |
784 } | 765 } |
785 } | 766 } |
786 } | 767 } |
OLD | NEW |