Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: pkg/compiler/lib/src/ssa/codegen_helpers.dart

Issue 1914623002: Fix for issue 26243 - illegal motion of assignments in instruction merging (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698