Chromium Code Reviews| 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(); |
| 307 | 319 |
| 308 String toString() => '[$lower, $upper]'; | 320 String toString() => '[$lower, $upper]'; |
| 309 } | 321 } |
| 310 | 322 |
| 311 /** | 323 /** |
| 312 * Visits the graph in dominator order, and computes value ranges for | 324 * Visits the graph in dominator order, and computes value ranges for |
| 313 * integer instructions. While visiting the graph, this phase also | 325 * integer instructions. While visiting the graph, this phase also |
| 314 * removes unnecessary bounds checks, and comparisons that are proven | 326 * removes unnecessary bounds checks, and comparisons that are proven |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 && indexRange.upper.min(maxIndex) == indexRange.upper; | 440 && indexRange.upper.min(maxIndex) == indexRange.upper; |
| 429 | 441 |
| 430 // Check if the index is strictly below the lower bound of the length | 442 // Check if the index is strictly below the lower bound of the length |
| 431 // range. | 443 // range. |
| 432 belowLength = belowLength | 444 belowLength = belowLength |
| 433 || (indexRange.upper != lengthRange.lower | 445 || (indexRange.upper != lengthRange.lower |
| 434 && indexRange.upper.min(lengthRange.lower) == indexRange.upper); | 446 && indexRange.upper.min(lengthRange.lower) == indexRange.upper); |
| 435 if (indexRange.isPositive() && belowLength) { | 447 if (indexRange.isPositive() && belowLength) { |
| 436 check.block.rewrite(check, check.index); | 448 check.block.rewrite(check, check.index); |
| 437 check.block.remove(check); | 449 check.block.remove(check); |
| 438 } else if (indexRange.isNegative() || lengthRange.isLessThan(indexRange)) { | 450 } else if (indexRange.isNegative() || lengthRange < indexRange) { |
| 439 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; | 451 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; |
| 440 // The check is always false, and whatever instruction it | 452 // The check is always false, and whatever instruction it |
| 441 // dominates is dead code. | 453 // dominates is dead code. |
| 442 return indexRange; | 454 return indexRange; |
| 443 } else if (indexRange.isPositive()) { | 455 } else if (indexRange.isPositive()) { |
| 444 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; | 456 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; |
| 445 } else if (belowLength) { | 457 } else if (belowLength) { |
| 446 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; | 458 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; |
| 447 } | 459 } |
| 448 | 460 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 464 new Range(lengthRange.lower, maxIndex)); | 476 new Range(lengthRange.lower, maxIndex)); |
| 465 if (indexRange == newIndexRange) return indexRange; | 477 if (indexRange == newIndexRange) return indexRange; |
| 466 HInstruction instruction = createRangeConversion(next, check.index); | 478 HInstruction instruction = createRangeConversion(next, check.index); |
| 467 ranges[instruction] = newIndexRange; | 479 ranges[instruction] = newIndexRange; |
| 468 return newIndexRange; | 480 return newIndexRange; |
| 469 } | 481 } |
| 470 | 482 |
| 471 return indexRange; | 483 return indexRange; |
| 472 } | 484 } |
| 473 | 485 |
| 474 Range visitLess(HLess less) { | 486 Range visitRelational(HRelation relational) { |
| 475 HInstruction right = less.right; | 487 HInstruction right = relational.right; |
| 476 HInstruction left = less.left; | 488 HInstruction left = relational.left; |
| 477 if (!left.isInteger(types)) return const Range.unbound(); | 489 if (!left.isInteger(types)) return const Range.unbound(); |
| 478 if (!right.isInteger(types)) return const Range.unbound(); | 490 if (!right.isInteger(types)) return const Range.unbound(); |
| 479 if (ranges[left].isLessThan(ranges[right])) { | 491 Operation operation = relational.operation(constantSystem); |
| 480 less.block.rewrite(less, graph.addConstantBool(true, constantSystem)); | 492 Range rightRange = ranges[relational.right]; |
| 481 less.block.remove(less); | 493 Range leftRange = ranges[relational.left]; |
| 482 return const Range.unbound(); | 494 |
| 483 } | 495 if (relational is HEquals || relational is HIdentity) { |
| 484 if (ranges[right].isLessThan(ranges[left])) { | 496 handleEqualityCheck(relational); |
| 485 less.block.rewrite(less, graph.addConstantBool(false, constantSystem)); | 497 } else if (operation.apply(leftRange, rightRange)) { |
| 486 less.block.remove(less); | 498 relational.block.rewrite( |
| 487 return const Range.unbound(); | 499 relational, graph.addConstantBool(true, constantSystem)); |
| 500 relational.block.remove(relational); | |
| 501 } else if (reverseOperation(operation).apply(leftRange, rightRange)) { | |
| 502 relational.block.rewrite( | |
| 503 relational, graph.addConstantBool(false, constantSystem)); | |
| 504 relational.block.remove(relational); | |
| 488 } | 505 } |
| 489 return const Range.unbound(); | 506 return const Range.unbound(); |
| 490 } | 507 } |
| 491 | 508 |
| 509 void handleEqualityCheck(HRelational node) { | |
| 510 Range right = ranges[node.right]; | |
| 511 Range left = ranges[node.left]; | |
| 512 if (left.lower == left.upper && left == right) { | |
|
Søren Gjesse
2012/10/02 08:07:20
Maybe have an isSingleValue on Range and express t
ngeoffray
2012/10/04 08:51:08
Done.
| |
| 513 node.block.rewrite( | |
| 514 node, graph.addConstantBool(true, constantSystem)); | |
| 515 node.block.remove(node); | |
| 516 } | |
| 517 } | |
| 518 | |
| 492 Range handleBinaryOperation(HBinaryArithmetic instruction) { | 519 Range handleBinaryOperation(HBinaryArithmetic instruction) { |
| 493 if (!instruction.isInteger(types)) return const Range.unbound(); | 520 if (!instruction.isInteger(types)) return const Range.unbound(); |
| 494 return instruction.operation(constantSystem).apply( | 521 return instruction.operation(constantSystem).apply( |
| 495 ranges[instruction.left], ranges[instruction.right]); | 522 ranges[instruction.left], ranges[instruction.right]); |
| 496 } | 523 } |
| 497 | 524 |
| 498 Range visitAdd(HAdd add) { | 525 Range visitAdd(HAdd add) { |
| 499 return handleBinaryOperation(add); | 526 return handleBinaryOperation(add); |
| 500 } | 527 } |
| 501 | 528 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 cursor.block.addBefore(cursor, newInstruction); | 570 cursor.block.addBefore(cursor, newInstruction); |
| 544 // Update the users of the instruction dominated by [cursor] to | 571 // Update the users of the instruction dominated by [cursor] to |
| 545 // use the new instruction, that has an narrower range. | 572 // use the new instruction, that has an narrower range. |
| 546 Set<HInstruction> dominatedUsers = instruction.dominatedUsers(cursor); | 573 Set<HInstruction> dominatedUsers = instruction.dominatedUsers(cursor); |
| 547 for (HInstruction user in dominatedUsers) { | 574 for (HInstruction user in dominatedUsers) { |
| 548 user.changeUse(instruction, newInstruction); | 575 user.changeUse(instruction, newInstruction); |
| 549 } | 576 } |
| 550 return newInstruction; | 577 return newInstruction; |
| 551 } | 578 } |
| 552 | 579 |
| 580 static Operation reverseOperation(BinaryOperation operation) { | |
| 581 if (operation == const LessOperation()) { | |
| 582 return const GreaterEqualOperation(); | |
| 583 } else if (operation == const LessEqualOperation()) { | |
| 584 return const GreaterOperation(); | |
| 585 } else if (operation == const GreaterOperation()) { | |
| 586 return const LessEqualOperation(); | |
| 587 } else if (operation == const GreaterEqualOperation()) { | |
| 588 return const LessOperation(); | |
| 589 } else { | |
| 590 return null; | |
| 591 } | |
| 592 } | |
| 593 | |
| 594 static Range computeNewRange(BinaryOperation operation, Range range) { | |
| 595 if (operation == const LessOperation()) { | |
| 596 return new Range(const MinIntValue(), range.upper - const IntValue(1)); | |
| 597 } else if (operation == const LessEqualOperation()) { | |
| 598 return new Range(const MinIntValue(), range.upper); | |
| 599 } else if (operation == const GreaterOperation()) { | |
| 600 return new Range(range.lower + const IntValue(1), const MaxIntValue()); | |
| 601 } else if (operation == const GreaterEqualOperation()) { | |
| 602 return new Range(range.lower, const MaxIntValue()); | |
| 603 } else { | |
| 604 return const Range.unbound(); | |
| 605 } | |
| 606 } | |
| 607 | |
| 553 Range visitConditionalBranch(HConditionalBranch branch) { | 608 Range visitConditionalBranch(HConditionalBranch branch) { |
| 554 var condition = branch.condition; | 609 var condition = branch.condition; |
| 555 // TODO(ngeoffray): Handle more condition kinds. | 610 // TODO(ngeoffray): Handle complex conditions. |
| 556 if (condition is !HLess) return const Range.unbound(); | 611 if (condition is !HRelational) return const Range.unbound(); |
| 612 if (condition is HEquals) return const Range.unbound(); | |
| 613 if (condition is HIdentity) return const Range.unbound(); | |
| 557 HInstruction right = condition.right; | 614 HInstruction right = condition.right; |
| 558 HInstruction left = condition.left; | 615 HInstruction left = condition.left; |
| 559 if (!left.isInteger(types)) return const Range.unbound(); | 616 if (!left.isInteger(types)) return const Range.unbound(); |
| 560 if (!right.isInteger(types)) return const Range.unbound(); | 617 if (!right.isInteger(types)) return const Range.unbound(); |
| 561 | 618 |
| 562 // Update the true branch to use a narrower range for [left]. | 619 Range rightRange = ranges[right]; |
| 563 // TODO(ngeoffray): Also do it for [right]. | 620 Range leftRange = ranges[left]; |
| 564 HInstruction instruction = | 621 Operation operation = condition.operation(constantSystem); |
| 565 createRangeConversion(branch.trueBranch.first, left); | 622 Operation reverse = reverseOperation(operation); |
| 566 Range range = new Range( | 623 // Update the true branch to use narrower ranges for [left] and |
| 567 const MinIntValue(), ranges[right].upper - const IntValue(1)); | 624 // [right]. |
| 568 range = range.intersection(ranges[left]); | 625 Range range = computeNewRange(operation, rightRange); |
|
Søren Gjesse
2012/10/02 08:07:20
Wouldn't it be better to include the intersection
ngeoffray
2012/10/02 16:03:09
Not sure I understand that comment. Could you expa
Søren Gjesse
2012/10/02 16:26:56
What I ment was to change
Range range = compute
ngeoffray
2012/10/04 08:51:08
Done.
| |
| 569 ranges[instruction] = range; | 626 range = range.intersection(leftRange); |
| 627 if (leftRange != range) { | |
| 628 HInstruction instruction = | |
| 629 createRangeConversion(branch.trueBranch.first, left); | |
| 630 ranges[instruction] = range; | |
| 631 } | |
| 570 | 632 |
| 571 // Update the false branch to use a narrower range for [left]. | 633 range = computeNewRange(reverse, leftRange); |
| 572 // TODO(ngeoffray): Also do it for [right]. | 634 range = range.intersection(rightRange); |
| 573 instruction = createRangeConversion(branch.falseBranch.first, left); | 635 if (rightRange != range) { |
| 574 range = new Range(ranges[right].lower, const MaxIntValue()); | 636 HInstruction instruction = |
| 575 range = range.intersection(ranges[left]); | 637 createRangeConversion(branch.trueBranch.first, right); |
| 576 ranges[instruction] = range; | 638 ranges[instruction] = range; |
| 639 } | |
| 640 | |
| 641 // Update the false branch to use narrower ranges for [left] and | |
| 642 // [right]. | |
| 643 range = computeNewRange(reverse, rightRange); | |
| 644 range = range.intersection(leftRange); | |
| 645 if (leftRange != range) { | |
| 646 HInstruction instruction = | |
| 647 createRangeConversion(branch.falseBranch.first, left); | |
| 648 ranges[instruction] = range; | |
| 649 } | |
| 650 | |
| 651 range = computeNewRange(operation, leftRange); | |
| 652 range = range.intersection(rightRange); | |
| 653 if (rightRange != range) { | |
| 654 HInstruction instruction = | |
| 655 createRangeConversion(branch.falseBranch.first, right); | |
| 656 ranges[instruction] = range; | |
| 657 } | |
| 577 | 658 |
| 578 return const Range.unbound(); | 659 return const Range.unbound(); |
| 579 } | 660 } |
| 580 | 661 |
| 581 Range visitRangeConversion(HRangeConversion conversion) { | 662 Range visitRangeConversion(HRangeConversion conversion) { |
| 582 return ranges[conversion]; | 663 return ranges[conversion]; |
| 583 } | 664 } |
| 584 } | 665 } |
| 585 | 666 |
| 586 /** | 667 /** |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 679 if (instruction is HPhi && !instruction.block.isLoopHeader()) { | 760 if (instruction is HPhi && !instruction.block.isLoopHeader()) { |
| 680 HInstruction result = unwrap(instruction.inputs[0]); | 761 HInstruction result = unwrap(instruction.inputs[0]); |
| 681 for (int i = 1; i < instruction.inputs.length; i++) { | 762 for (int i = 1; i < instruction.inputs.length; i++) { |
| 682 if (result != unwrap(instruction.inputs[i])) return instruction; | 763 if (result != unwrap(instruction.inputs[i])) return instruction; |
| 683 } | 764 } |
| 684 return result; | 765 return result; |
| 685 } | 766 } |
| 686 return instruction; | 767 return instruction; |
| 687 } | 768 } |
| 688 } | 769 } |
| OLD | NEW |