| 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 /** | 5 /** |
| 6 * A [Value] represents both symbolic values like the value of a | 6 * A [Value] represents both symbolic values like the value of a |
| 7 * parameter, or the length of an array, and concrete values, like | 7 * parameter, or the length of an array, and concrete values, like |
| 8 * constants. | 8 * constants. |
| 9 */ | 9 */ |
| 10 abstract class Value { | 10 abstract class Value { |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 | 291 |
| 292 Range operator &(Range other) { | 292 Range operator &(Range other) { |
| 293 return new Range.normalize(lower & other.lower, upper & other.upper); | 293 return new Range.normalize(lower & other.lower, upper & other.upper); |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool operator ==(other) { | 296 bool operator ==(other) { |
| 297 if (other is! Range) return false; | 297 if (other is! Range) return false; |
| 298 return other.lower == lower && other.upper == upper; | 298 return other.lower == lower && other.upper == upper; |
| 299 } | 299 } |
| 300 | 300 |
| 301 bool isLessThan(Range other) { | 301 bool operator <(Range other) { |
| 302 return upper != other.lower && upper.min(other.lower) == upper; | 302 return upper != other.lower && upper.min(other.lower) == upper; |
| 303 } | 303 } |
| 304 | 304 |
| 305 bool operator >(Range other) { |
| 306 return lower != other.upper && lower.max(other.upper) == lower; |
| 307 } |
| 308 |
| 309 bool operator <=(Range other) { |
| 310 return upper.min(other.lower) == upper; |
| 311 } |
| 312 |
| 313 bool operator >=(Range other) { |
| 314 return lower.max(other.upper) == lower; |
| 315 } |
| 316 |
| 305 bool isNegative() => upper.isNegative(); | 317 bool isNegative() => upper.isNegative(); |
| 306 bool isPositive() => lower.isPositive(); | 318 bool isPositive() => lower.isPositive(); |
| 319 bool isSingleValue() => lower == upper; |
| 307 | 320 |
| 308 String toString() => '[$lower, $upper]'; | 321 String toString() => '[$lower, $upper]'; |
| 309 } | 322 } |
| 310 | 323 |
| 311 /** | 324 /** |
| 312 * Visits the graph in dominator order, and computes value ranges for | 325 * Visits the graph in dominator order, and computes value ranges for |
| 313 * integer instructions. While visiting the graph, this phase also | 326 * integer instructions. While visiting the graph, this phase also |
| 314 * removes unnecessary bounds checks, and comparisons that are proven | 327 * removes unnecessary bounds checks, and comparisons that are proven |
| 315 * to be true or false. | 328 * to be true or false. |
| 316 */ | 329 */ |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 && indexRange.upper.min(maxIndex) == indexRange.upper; | 441 && indexRange.upper.min(maxIndex) == indexRange.upper; |
| 429 | 442 |
| 430 // Check if the index is strictly below the lower bound of the length | 443 // Check if the index is strictly below the lower bound of the length |
| 431 // range. | 444 // range. |
| 432 belowLength = belowLength | 445 belowLength = belowLength |
| 433 || (indexRange.upper != lengthRange.lower | 446 || (indexRange.upper != lengthRange.lower |
| 434 && indexRange.upper.min(lengthRange.lower) == indexRange.upper); | 447 && indexRange.upper.min(lengthRange.lower) == indexRange.upper); |
| 435 if (indexRange.isPositive() && belowLength) { | 448 if (indexRange.isPositive() && belowLength) { |
| 436 check.block.rewrite(check, check.index); | 449 check.block.rewrite(check, check.index); |
| 437 check.block.remove(check); | 450 check.block.remove(check); |
| 438 } else if (indexRange.isNegative() || lengthRange.isLessThan(indexRange)) { | 451 } else if (indexRange.isNegative() || lengthRange < indexRange) { |
| 439 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; | 452 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; |
| 440 // The check is always false, and whatever instruction it | 453 // The check is always false, and whatever instruction it |
| 441 // dominates is dead code. | 454 // dominates is dead code. |
| 442 return indexRange; | 455 return indexRange; |
| 443 } else if (indexRange.isPositive()) { | 456 } else if (indexRange.isPositive()) { |
| 444 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; | 457 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; |
| 445 } else if (belowLength) { | 458 } else if (belowLength) { |
| 446 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; | 459 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; |
| 447 } | 460 } |
| 448 | 461 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 464 new Range(lengthRange.lower, maxIndex)); | 477 new Range(lengthRange.lower, maxIndex)); |
| 465 if (indexRange == newIndexRange) return indexRange; | 478 if (indexRange == newIndexRange) return indexRange; |
| 466 HInstruction instruction = createRangeConversion(next, check.index); | 479 HInstruction instruction = createRangeConversion(next, check.index); |
| 467 ranges[instruction] = newIndexRange; | 480 ranges[instruction] = newIndexRange; |
| 468 return newIndexRange; | 481 return newIndexRange; |
| 469 } | 482 } |
| 470 | 483 |
| 471 return indexRange; | 484 return indexRange; |
| 472 } | 485 } |
| 473 | 486 |
| 474 Range visitLess(HLess less) { | 487 Range visitRelational(HRelational relational) { |
| 475 HInstruction right = less.right; | 488 HInstruction right = relational.right; |
| 476 HInstruction left = less.left; | 489 HInstruction left = relational.left; |
| 477 if (!left.isInteger(types)) return const Range.unbound(); | 490 if (!left.isInteger(types)) return const Range.unbound(); |
| 478 if (!right.isInteger(types)) return const Range.unbound(); | 491 if (!right.isInteger(types)) return const Range.unbound(); |
| 479 if (ranges[left].isLessThan(ranges[right])) { | 492 Operation operation = relational.operation(constantSystem); |
| 480 less.block.rewrite(less, graph.addConstantBool(true, constantSystem)); | 493 Range rightRange = ranges[relational.right]; |
| 481 less.block.remove(less); | 494 Range leftRange = ranges[relational.left]; |
| 482 return const Range.unbound(); | 495 |
| 483 } | 496 if (relational is HEquals || relational is HIdentity) { |
| 484 if (ranges[right].isLessThan(ranges[left])) { | 497 handleEqualityCheck(relational); |
| 485 less.block.rewrite(less, graph.addConstantBool(false, constantSystem)); | 498 } else if (operation.apply(leftRange, rightRange)) { |
| 486 less.block.remove(less); | 499 relational.block.rewrite( |
| 487 return const Range.unbound(); | 500 relational, graph.addConstantBool(true, constantSystem)); |
| 501 relational.block.remove(relational); |
| 502 } else if (reverseOperation(operation).apply(leftRange, rightRange)) { |
| 503 relational.block.rewrite( |
| 504 relational, graph.addConstantBool(false, constantSystem)); |
| 505 relational.block.remove(relational); |
| 488 } | 506 } |
| 489 return const Range.unbound(); | 507 return const Range.unbound(); |
| 490 } | 508 } |
| 491 | 509 |
| 510 void handleEqualityCheck(HRelational node) { |
| 511 Range right = ranges[node.right]; |
| 512 Range left = ranges[node.left]; |
| 513 if (left.isSingleValue() && right.isSingleValue() && left == right) { |
| 514 node.block.rewrite( |
| 515 node, graph.addConstantBool(true, constantSystem)); |
| 516 node.block.remove(node); |
| 517 } |
| 518 } |
| 519 |
| 492 Range handleBinaryOperation(HBinaryArithmetic instruction) { | 520 Range handleBinaryOperation(HBinaryArithmetic instruction) { |
| 493 if (!instruction.isInteger(types)) return const Range.unbound(); | 521 if (!instruction.isInteger(types)) return const Range.unbound(); |
| 494 return instruction.operation(constantSystem).apply( | 522 return instruction.operation(constantSystem).apply( |
| 495 ranges[instruction.left], ranges[instruction.right]); | 523 ranges[instruction.left], ranges[instruction.right]); |
| 496 } | 524 } |
| 497 | 525 |
| 498 Range visitAdd(HAdd add) { | 526 Range visitAdd(HAdd add) { |
| 499 return handleBinaryOperation(add); | 527 return handleBinaryOperation(add); |
| 500 } | 528 } |
| 501 | 529 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 cursor.block.addBefore(cursor, newInstruction); | 571 cursor.block.addBefore(cursor, newInstruction); |
| 544 // Update the users of the instruction dominated by [cursor] to | 572 // Update the users of the instruction dominated by [cursor] to |
| 545 // use the new instruction, that has an narrower range. | 573 // use the new instruction, that has an narrower range. |
| 546 Set<HInstruction> dominatedUsers = instruction.dominatedUsers(cursor); | 574 Set<HInstruction> dominatedUsers = instruction.dominatedUsers(cursor); |
| 547 for (HInstruction user in dominatedUsers) { | 575 for (HInstruction user in dominatedUsers) { |
| 548 user.changeUse(instruction, newInstruction); | 576 user.changeUse(instruction, newInstruction); |
| 549 } | 577 } |
| 550 return newInstruction; | 578 return newInstruction; |
| 551 } | 579 } |
| 552 | 580 |
| 581 static Operation reverseOperation(BinaryOperation operation) { |
| 582 if (operation == const LessOperation()) { |
| 583 return const GreaterEqualOperation(); |
| 584 } else if (operation == const LessEqualOperation()) { |
| 585 return const GreaterOperation(); |
| 586 } else if (operation == const GreaterOperation()) { |
| 587 return const LessEqualOperation(); |
| 588 } else if (operation == const GreaterEqualOperation()) { |
| 589 return const LessOperation(); |
| 590 } else { |
| 591 return null; |
| 592 } |
| 593 } |
| 594 |
| 595 static Range computeConstrainedRange(BinaryOperation operation, |
| 596 Range leftRange, |
| 597 Range rightRange) { |
| 598 Range range; |
| 599 if (operation == const LessOperation()) { |
| 600 range = new Range( |
| 601 const MinIntValue(), rightRange.upper - const IntValue(1)); |
| 602 } else if (operation == const LessEqualOperation()) { |
| 603 range = new Range(const MinIntValue(), rightRange.upper); |
| 604 } else if (operation == const GreaterOperation()) { |
| 605 range = new Range( |
| 606 rightRange.lower + const IntValue(1), const MaxIntValue()); |
| 607 } else if (operation == const GreaterEqualOperation()) { |
| 608 range = new Range(rightRange.lower, const MaxIntValue()); |
| 609 } else { |
| 610 range = const Range.unbound(); |
| 611 } |
| 612 return range.intersection(leftRange); |
| 613 } |
| 614 |
| 553 Range visitConditionalBranch(HConditionalBranch branch) { | 615 Range visitConditionalBranch(HConditionalBranch branch) { |
| 554 var condition = branch.condition; | 616 var condition = branch.condition; |
| 555 // TODO(ngeoffray): Handle more condition kinds. | 617 // TODO(ngeoffray): Handle complex conditions. |
| 556 if (condition is !HLess) return const Range.unbound(); | 618 if (condition is !HRelational) return const Range.unbound(); |
| 619 if (condition is HEquals) return const Range.unbound(); |
| 620 if (condition is HIdentity) return const Range.unbound(); |
| 557 HInstruction right = condition.right; | 621 HInstruction right = condition.right; |
| 558 HInstruction left = condition.left; | 622 HInstruction left = condition.left; |
| 559 if (!left.isInteger(types)) return const Range.unbound(); | 623 if (!left.isInteger(types)) return const Range.unbound(); |
| 560 if (!right.isInteger(types)) return const Range.unbound(); | 624 if (!right.isInteger(types)) return const Range.unbound(); |
| 561 | 625 |
| 562 // Update the true branch to use a narrower range for [left]. | 626 Range rightRange = ranges[right]; |
| 563 // TODO(ngeoffray): Also do it for [right]. | 627 Range leftRange = ranges[left]; |
| 564 HInstruction instruction = | 628 Operation operation = condition.operation(constantSystem); |
| 565 createRangeConversion(branch.trueBranch.first, left); | 629 Operation reverse = reverseOperation(operation); |
| 566 Range range = new Range( | 630 // Only update the true branch if this block is the only |
| 567 const MinIntValue(), ranges[right].upper - const IntValue(1)); | 631 // predecessor. |
| 568 range = range.intersection(ranges[left]); | 632 if (branch.trueBranch.predecessors.length == 1) { |
| 569 ranges[instruction] = range; | 633 assert(branch.trueBranch.predecessors[0] == branch.block); |
| 634 // Update the true branch to use narrower ranges for [left] and |
| 635 // [right]. |
| 636 Range range = computeConstrainedRange(operation, leftRange, rightRange); |
| 637 if (leftRange != range) { |
| 638 HInstruction instruction = |
| 639 createRangeConversion(branch.trueBranch.first, left); |
| 640 ranges[instruction] = range; |
| 641 } |
| 570 | 642 |
| 571 // Update the false branch to use a narrower range for [left]. | 643 range = computeConstrainedRange(reverse, rightRange, leftRange); |
| 572 // TODO(ngeoffray): Also do it for [right]. | 644 if (rightRange != range) { |
| 573 instruction = createRangeConversion(branch.falseBranch.first, left); | 645 HInstruction instruction = |
| 574 range = new Range(ranges[right].lower, const MaxIntValue()); | 646 createRangeConversion(branch.trueBranch.first, right); |
| 575 range = range.intersection(ranges[left]); | 647 ranges[instruction] = range; |
| 576 ranges[instruction] = range; | 648 } |
| 649 } |
| 650 |
| 651 // Only update the false branch if this block is the only |
| 652 // predecessor. |
| 653 if (branch.falseBranch.predecessors.length == 1) { |
| 654 assert(branch.falseBranch.predecessors[0] == branch.block); |
| 655 // Update the false branch to use narrower ranges for [left] and |
| 656 // [right]. |
| 657 Range range = computeConstrainedRange(reverse, leftRange, rightRange); |
| 658 if (leftRange != range) { |
| 659 HInstruction instruction = |
| 660 createRangeConversion(branch.falseBranch.first, left); |
| 661 ranges[instruction] = range; |
| 662 } |
| 663 |
| 664 range = computeConstrainedRange(operation, rightRange, leftRange); |
| 665 if (rightRange != range) { |
| 666 HInstruction instruction = |
| 667 createRangeConversion(branch.falseBranch.first, right); |
| 668 ranges[instruction] = range; |
| 669 } |
| 670 } |
| 577 | 671 |
| 578 return const Range.unbound(); | 672 return const Range.unbound(); |
| 579 } | 673 } |
| 580 | 674 |
| 581 Range visitRangeConversion(HRangeConversion conversion) { | 675 Range visitRangeConversion(HRangeConversion conversion) { |
| 582 return ranges[conversion]; | 676 return ranges[conversion]; |
| 583 } | 677 } |
| 584 } | 678 } |
| 585 | 679 |
| 586 /** | 680 /** |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 if (instruction is HPhi && !instruction.block.isLoopHeader()) { | 773 if (instruction is HPhi && !instruction.block.isLoopHeader()) { |
| 680 HInstruction result = unwrap(instruction.inputs[0]); | 774 HInstruction result = unwrap(instruction.inputs[0]); |
| 681 for (int i = 1; i < instruction.inputs.length; i++) { | 775 for (int i = 1; i < instruction.inputs.length; i++) { |
| 682 if (result != unwrap(instruction.inputs[i])) return instruction; | 776 if (result != unwrap(instruction.inputs[i])) return instruction; |
| 683 } | 777 } |
| 684 return result; | 778 return result; |
| 685 } | 779 } |
| 686 return instruction; | 780 return instruction; |
| 687 } | 781 } |
| 688 } | 782 } |
| OLD | NEW |