| 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 '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 6 import '../compiler.dart' show Compiler; | 6 import '../compiler.dart' show Compiler; |
| 7 import '../constant_system_dart.dart'; | 7 import '../constant_system_dart.dart'; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
| 10 import '../js_backend/js_backend.dart'; | 10 import '../js_backend/js_backend.dart'; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 | 49 |
| 50 Range newUnboundRange() { | 50 Range newUnboundRange() { |
| 51 return new Range.unbound(this); | 51 return new Range.unbound(this); |
| 52 } | 52 } |
| 53 | 53 |
| 54 Range newNormalizedRange(Value low, Value up) { | 54 Range newNormalizedRange(Value low, Value up) { |
| 55 return new Range.normalize(low, up, this); | 55 return new Range.normalize(low, up, this); |
| 56 } | 56 } |
| 57 | 57 |
| 58 Range newMarkerRange() { | 58 Range newMarkerRange() { |
| 59 return new Range(new MarkerValue(false, this), | 59 return new Range( |
| 60 new MarkerValue(true, this), | 60 new MarkerValue(false, this), new MarkerValue(true, this), this); |
| 61 this); | |
| 62 } | 61 } |
| 63 } | 62 } |
| 64 | 63 |
| 65 /** | 64 /** |
| 66 * A [Value] represents both symbolic values like the value of a | 65 * A [Value] represents both symbolic values like the value of a |
| 67 * parameter, or the length of an array, and concrete values, like | 66 * parameter, or the length of an array, and concrete values, like |
| 68 * constants. | 67 * constants. |
| 69 */ | 68 */ |
| 70 abstract class Value { | 69 abstract class Value { |
| 71 final ValueRangeInfo info; | 70 final ValueRangeInfo info; |
| 72 const Value(this.info); | 71 const Value(this.info); |
| 73 | 72 |
| 74 Value operator +(Value other) => const UnknownValue(); | 73 Value operator +(Value other) => const UnknownValue(); |
| 75 Value operator -(Value other) => const UnknownValue(); | 74 Value operator -(Value other) => const UnknownValue(); |
| 76 Value operator -() => const UnknownValue(); | 75 Value operator -() => const UnknownValue(); |
| 77 Value operator &(Value other) => const UnknownValue(); | 76 Value operator &(Value other) => const UnknownValue(); |
| 78 | 77 |
| 79 Value min(Value other) { | 78 Value min(Value other) { |
| 80 if (this == other) return this; | 79 if (this == other) return this; |
| 81 if (other == const MinIntValue()) return other; | 80 if (other == const MinIntValue()) return other; |
| 82 if (other == const MaxIntValue()) return this; | 81 if (other == const MaxIntValue()) return this; |
| 83 Value value = this - other; | 82 Value value = this - other; |
| 84 if (value.isPositive) return other; | 83 if (value.isPositive) return other; |
| 85 if (value.isNegative) return this; | 84 if (value.isNegative) return this; |
| 86 return const UnknownValue(); | 85 return const UnknownValue(); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 /** | 130 /** |
| 132 * An [IntValue] contains a constant integer value. | 131 * An [IntValue] contains a constant integer value. |
| 133 */ | 132 */ |
| 134 class IntValue extends Value { | 133 class IntValue extends Value { |
| 135 final int value; | 134 final int value; |
| 136 | 135 |
| 137 const IntValue(this.value, info) : super(info); | 136 const IntValue(this.value, info) : super(info); |
| 138 | 137 |
| 139 Value operator +(other) { | 138 Value operator +(other) { |
| 140 if (other.isZero) return this; | 139 if (other.isZero) return this; |
| 141 if (other is !IntValue) return other + this; | 140 if (other is! IntValue) return other + this; |
| 142 ConstantSystem constantSystem = info.constantSystem; | 141 ConstantSystem constantSystem = info.constantSystem; |
| 143 var constant = constantSystem.add.fold( | 142 var constant = constantSystem.add.fold( |
| 144 constantSystem.createInt(value), constantSystem.createInt(other.value)); | 143 constantSystem.createInt(value), constantSystem.createInt(other.value)); |
| 145 if (!constant.isInt) return const UnknownValue(); | 144 if (!constant.isInt) return const UnknownValue(); |
| 146 return info.newIntValue(constant.primitiveValue); | 145 return info.newIntValue(constant.primitiveValue); |
| 147 } | 146 } |
| 148 | 147 |
| 149 Value operator -(other) { | 148 Value operator -(other) { |
| 150 if (other.isZero) return this; | 149 if (other.isZero) return this; |
| 151 if (other is !IntValue) return -other + this; | 150 if (other is! IntValue) return -other + this; |
| 152 ConstantSystem constantSystem = info.constantSystem; | 151 ConstantSystem constantSystem = info.constantSystem; |
| 153 var constant = constantSystem.subtract.fold( | 152 var constant = constantSystem.subtract.fold( |
| 154 constantSystem.createInt(value), constantSystem.createInt(other.value)); | 153 constantSystem.createInt(value), constantSystem.createInt(other.value)); |
| 155 if (!constant.isInt) return const UnknownValue(); | 154 if (!constant.isInt) return const UnknownValue(); |
| 156 return info.newIntValue(constant.primitiveValue); | 155 return info.newIntValue(constant.primitiveValue); |
| 157 } | 156 } |
| 158 | 157 |
| 159 Value operator -() { | 158 Value operator -() { |
| 160 if (isZero) return this; | 159 if (isZero) return this; |
| 161 ConstantSystem constantSystem = info.constantSystem; | 160 ConstantSystem constantSystem = info.constantSystem; |
| 162 var constant = constantSystem.negate.fold( | 161 var constant = constantSystem.negate.fold(constantSystem.createInt(value)); |
| 163 constantSystem.createInt(value)); | |
| 164 if (!constant.isInt) return const UnknownValue(); | 162 if (!constant.isInt) return const UnknownValue(); |
| 165 return info.newIntValue(constant.primitiveValue); | 163 return info.newIntValue(constant.primitiveValue); |
| 166 } | 164 } |
| 167 | 165 |
| 168 Value operator &(other) { | 166 Value operator &(other) { |
| 169 if (other is !IntValue) return const UnknownValue(); | 167 if (other is! IntValue) return const UnknownValue(); |
| 170 ConstantSystem constantSystem = info.constantSystem; | 168 ConstantSystem constantSystem = info.constantSystem; |
| 171 var constant = constantSystem.bitAnd.fold( | 169 var constant = constantSystem.bitAnd.fold( |
| 172 constantSystem.createInt(value), constantSystem.createInt(other.value)); | 170 constantSystem.createInt(value), constantSystem.createInt(other.value)); |
| 173 return info.newIntValue(constant.primitiveValue); | 171 return info.newIntValue(constant.primitiveValue); |
| 174 } | 172 } |
| 175 | 173 |
| 176 Value min(other) { | 174 Value min(other) { |
| 177 if (other is !IntValue) return other.min(this); | 175 if (other is! IntValue) return other.min(this); |
| 178 return this.value < other.value ? this : other; | 176 return this.value < other.value ? this : other; |
| 179 } | 177 } |
| 180 | 178 |
| 181 Value max(other) { | 179 Value max(other) { |
| 182 if (other is !IntValue) return other.max(this); | 180 if (other is! IntValue) return other.max(this); |
| 183 return this.value < other.value ? other : this; | 181 return this.value < other.value ? other : this; |
| 184 } | 182 } |
| 185 | 183 |
| 186 bool operator ==(other) { | 184 bool operator ==(other) { |
| 187 if (other is !IntValue) return false; | 185 if (other is! IntValue) return false; |
| 188 return this.value == other.value; | 186 return this.value == other.value; |
| 189 } | 187 } |
| 190 | 188 |
| 191 int get hashCode => throw new UnsupportedError('IntValue.hashCode'); | 189 int get hashCode => throw new UnsupportedError('IntValue.hashCode'); |
| 192 | 190 |
| 193 String toString() => 'IntValue $value'; | 191 String toString() => 'IntValue $value'; |
| 194 bool get isNegative => value < 0; | 192 bool get isNegative => value < 0; |
| 195 bool get isPositive => value >= 0; | 193 bool get isPositive => value >= 0; |
| 196 bool get isZero => value == 0; | 194 bool get isZero => value == 0; |
| 197 } | 195 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 } | 243 } |
| 246 | 244 |
| 247 /** | 245 /** |
| 248 * A symbolic value representing an [HInstruction]. | 246 * A symbolic value representing an [HInstruction]. |
| 249 */ | 247 */ |
| 250 class InstructionValue extends Value { | 248 class InstructionValue extends Value { |
| 251 final HInstruction instruction; | 249 final HInstruction instruction; |
| 252 InstructionValue(this.instruction, info) : super(info); | 250 InstructionValue(this.instruction, info) : super(info); |
| 253 | 251 |
| 254 bool operator ==(other) { | 252 bool operator ==(other) { |
| 255 if (other is !InstructionValue) return false; | 253 if (other is! InstructionValue) return false; |
| 256 return this.instruction == other.instruction; | 254 return this.instruction == other.instruction; |
| 257 } | 255 } |
| 258 | 256 |
| 259 int get hashCode => throw new UnsupportedError('InstructionValue.hashCode'); | 257 int get hashCode => throw new UnsupportedError('InstructionValue.hashCode'); |
| 260 | 258 |
| 261 Value operator +(Value other) { | 259 Value operator +(Value other) { |
| 262 if (other.isZero) return this; | 260 if (other.isZero) return this; |
| 263 if (other is IntValue) { | 261 if (other is IntValue) { |
| 264 if (other.isNegative) { | 262 if (other.isNegative) { |
| 265 return info.newSubtractValue(this, -other); | 263 return info.newSubtractValue(this, -other); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 class BinaryOperationValue extends Value { | 310 class BinaryOperationValue extends Value { |
| 313 final Value left; | 311 final Value left; |
| 314 final Value right; | 312 final Value right; |
| 315 BinaryOperationValue(this.left, this.right, info) : super(info); | 313 BinaryOperationValue(this.left, this.right, info) : super(info); |
| 316 } | 314 } |
| 317 | 315 |
| 318 class AddValue extends BinaryOperationValue { | 316 class AddValue extends BinaryOperationValue { |
| 319 AddValue(left, right, info) : super(left, right, info); | 317 AddValue(left, right, info) : super(left, right, info); |
| 320 | 318 |
| 321 bool operator ==(other) { | 319 bool operator ==(other) { |
| 322 if (other is !AddValue) return false; | 320 if (other is! AddValue) return false; |
| 323 return (left == other.left && right == other.right) | 321 return (left == other.left && right == other.right) || |
| 324 || (left == other.right && right == other.left); | 322 (left == other.right && right == other.left); |
| 325 } | 323 } |
| 326 | 324 |
| 327 int get hashCode => throw new UnsupportedError('AddValue.hashCode'); | 325 int get hashCode => throw new UnsupportedError('AddValue.hashCode'); |
| 328 | 326 |
| 329 Value operator -() => -left - right; | 327 Value operator -() => -left - right; |
| 330 | 328 |
| 331 Value operator +(Value other) { | 329 Value operator +(Value other) { |
| 332 if (other.isZero) return this; | 330 if (other.isZero) return this; |
| 333 Value value = left + other; | 331 Value value = left + other; |
| 334 if (value != const UnknownValue() && value is! BinaryOperationValue) { | 332 if (value != const UnknownValue() && value is! BinaryOperationValue) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 360 | 358 |
| 361 bool get isNegative => left.isNegative && right.isNegative; | 359 bool get isNegative => left.isNegative && right.isNegative; |
| 362 bool get isPositive => left.isPositive && right.isPositive; | 360 bool get isPositive => left.isPositive && right.isPositive; |
| 363 String toString() => '$left + $right'; | 361 String toString() => '$left + $right'; |
| 364 } | 362 } |
| 365 | 363 |
| 366 class SubtractValue extends BinaryOperationValue { | 364 class SubtractValue extends BinaryOperationValue { |
| 367 SubtractValue(left, right, info) : super(left, right, info); | 365 SubtractValue(left, right, info) : super(left, right, info); |
| 368 | 366 |
| 369 bool operator ==(other) { | 367 bool operator ==(other) { |
| 370 if (other is !SubtractValue) return false; | 368 if (other is! SubtractValue) return false; |
| 371 return left == other.left && right == other.right; | 369 return left == other.left && right == other.right; |
| 372 } | 370 } |
| 373 | 371 |
| 374 int get hashCode => throw new UnsupportedError('SubtractValue.hashCode'); | 372 int get hashCode => throw new UnsupportedError('SubtractValue.hashCode'); |
| 375 | 373 |
| 376 Value operator -() => right - left; | 374 Value operator -() => right - left; |
| 377 | 375 |
| 378 Value operator +(Value other) { | 376 Value operator +(Value other) { |
| 379 if (other.isZero) return this; | 377 if (other.isZero) return this; |
| 380 Value value = left + other; | 378 Value value = left + other; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 408 bool get isNegative => left.isNegative && right.isPositive; | 406 bool get isNegative => left.isNegative && right.isPositive; |
| 409 bool get isPositive => left.isPositive && right.isNegative; | 407 bool get isPositive => left.isPositive && right.isNegative; |
| 410 String toString() => '$left - $right'; | 408 String toString() => '$left - $right'; |
| 411 } | 409 } |
| 412 | 410 |
| 413 class NegateValue extends Value { | 411 class NegateValue extends Value { |
| 414 final Value value; | 412 final Value value; |
| 415 NegateValue(this.value, info) : super(info); | 413 NegateValue(this.value, info) : super(info); |
| 416 | 414 |
| 417 bool operator ==(other) { | 415 bool operator ==(other) { |
| 418 if (other is !NegateValue) return false; | 416 if (other is! NegateValue) return false; |
| 419 return value == other.value; | 417 return value == other.value; |
| 420 } | 418 } |
| 421 | 419 |
| 422 int get hashCode => throw new UnsupportedError('Negate.hashCode'); | 420 int get hashCode => throw new UnsupportedError('Negate.hashCode'); |
| 423 | 421 |
| 424 Value operator +(other) { | 422 Value operator +(other) { |
| 425 if (other.isZero) return this; | 423 if (other.isZero) return this; |
| 426 if (other == value) return info.intZero; | 424 if (other == value) return info.intZero; |
| 427 if (other is NegateValue) return this - other.value; | 425 if (other is NegateValue) return this - other.value; |
| 428 if (other is IntValue) { | 426 if (other is IntValue) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 assert(lower != const UnknownValue()); | 472 assert(lower != const UnknownValue()); |
| 475 assert(upper != const UnknownValue()); | 473 assert(upper != const UnknownValue()); |
| 476 } | 474 } |
| 477 | 475 |
| 478 Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info); | 476 Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info); |
| 479 | 477 |
| 480 /** | 478 /** |
| 481 * Checks if the given values are unknown, and creates a | 479 * Checks if the given values are unknown, and creates a |
| 482 * range that does not have any unknown values. | 480 * range that does not have any unknown values. |
| 483 */ | 481 */ |
| 484 Range.normalize(Value low, Value up, info) : this( | 482 Range.normalize(Value low, Value up, info) |
| 485 low == const UnknownValue() ? const MinIntValue() : low, | 483 : this(low == const UnknownValue() ? const MinIntValue() : low, |
| 486 up == const UnknownValue() ? const MaxIntValue() : up, | 484 up == const UnknownValue() ? const MaxIntValue() : up, info); |
| 487 info); | |
| 488 | 485 |
| 489 Range union(Range other) { | 486 Range union(Range other) { |
| 490 return info.newNormalizedRange( | 487 return info.newNormalizedRange( |
| 491 lower.min(other.lower), upper.max(other.upper)); | 488 lower.min(other.lower), upper.max(other.upper)); |
| 492 } | 489 } |
| 493 | 490 |
| 494 Range intersection(Range other) { | 491 Range intersection(Range other) { |
| 495 Value low = lower.max(other.lower); | 492 Value low = lower.max(other.lower); |
| 496 Value up = upper.min(other.upper); | 493 Value up = upper.min(other.upper); |
| 497 // If we could not compute max or min, pick a value in the two | 494 // If we could not compute max or min, pick a value in the two |
| 498 // ranges, with priority to [IntValue]s because they are simpler. | 495 // ranges, with priority to [IntValue]s because they are simpler. |
| 499 if (low == const UnknownValue()) { | 496 if (low == const UnknownValue()) { |
| 500 if (lower is IntValue) low = lower; | 497 if (lower is IntValue) |
| 501 else if (other.lower is IntValue) low = other.lower; | 498 low = lower; |
| 502 else low = lower; | 499 else if (other.lower is IntValue) |
| 500 low = other.lower; |
| 501 else |
| 502 low = lower; |
| 503 } | 503 } |
| 504 if (up == const UnknownValue()) { | 504 if (up == const UnknownValue()) { |
| 505 if (upper is IntValue) up = upper; | 505 if (upper is IntValue) |
| 506 else if (other.upper is IntValue) up = other.upper; | 506 up = upper; |
| 507 else up = upper; | 507 else if (other.upper is IntValue) |
| 508 up = other.upper; |
| 509 else |
| 510 up = upper; |
| 508 } | 511 } |
| 509 return info.newNormalizedRange(low, up); | 512 return info.newNormalizedRange(low, up); |
| 510 } | 513 } |
| 511 | 514 |
| 512 Range operator +(Range other) { | 515 Range operator +(Range other) { |
| 513 return info.newNormalizedRange(lower + other.lower, upper + other.upper); | 516 return info.newNormalizedRange(lower + other.lower, upper + other.upper); |
| 514 } | 517 } |
| 515 | 518 |
| 516 Range operator -(Range other) { | 519 Range operator -(Range other) { |
| 517 return info.newNormalizedRange(lower - other.upper, upper - other.lower); | 520 return info.newNormalizedRange(lower - other.upper, upper - other.lower); |
| 518 } | 521 } |
| 519 | 522 |
| 520 Range operator -() { | 523 Range operator -() { |
| 521 return info.newNormalizedRange(-upper, -lower); | 524 return info.newNormalizedRange(-upper, -lower); |
| 522 } | 525 } |
| 523 | 526 |
| 524 Range operator &(Range other) { | 527 Range operator &(Range other) { |
| 525 if (isSingleValue | 528 if (isSingleValue && |
| 526 && other.isSingleValue | 529 other.isSingleValue && |
| 527 && lower is IntValue | 530 lower is IntValue && |
| 528 && other.lower is IntValue) { | 531 other.lower is IntValue) { |
| 529 return info.newNormalizedRange(lower & other.lower, upper & other.upper); | 532 return info.newNormalizedRange(lower & other.lower, upper & other.upper); |
| 530 } | 533 } |
| 531 if (isPositive && other.isPositive) { | 534 if (isPositive && other.isPositive) { |
| 532 Value up = upper.min(other.upper); | 535 Value up = upper.min(other.upper); |
| 533 if (up == const UnknownValue()) { | 536 if (up == const UnknownValue()) { |
| 534 // If we could not find a trivial bound, just try to use the | 537 // If we could not find a trivial bound, just try to use the |
| 535 // one that is an int. | 538 // one that is an int. |
| 536 up = upper is IntValue ? upper : other.upper; | 539 up = upper is IntValue ? upper : other.upper; |
| 537 // Make sure we get the same upper bound, whether it's a & b | 540 // Make sure we get the same upper bound, whether it's a & b |
| 538 // or b & a. | 541 // or b & a. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 final Map<HInstruction, Range> ranges = new Map<HInstruction, Range>(); | 603 final Map<HInstruction, Range> ranges = new Map<HInstruction, Range>(); |
| 601 | 604 |
| 602 final Compiler compiler; | 605 final Compiler compiler; |
| 603 final ConstantSystem constantSystem; | 606 final ConstantSystem constantSystem; |
| 604 final ValueRangeInfo info; | 607 final ValueRangeInfo info; |
| 605 final SsaOptimizerTask optimizer; | 608 final SsaOptimizerTask optimizer; |
| 606 | 609 |
| 607 CodegenWorkItem work; | 610 CodegenWorkItem work; |
| 608 HGraph graph; | 611 HGraph graph; |
| 609 | 612 |
| 610 SsaValueRangeAnalyzer(this.compiler, | 613 SsaValueRangeAnalyzer( |
| 611 constantSystem, | 614 this.compiler, constantSystem, this.optimizer, this.work) |
| 612 this.optimizer, | |
| 613 this.work) | |
| 614 : info = new ValueRangeInfo(constantSystem), | 615 : info = new ValueRangeInfo(constantSystem), |
| 615 this.constantSystem = constantSystem; | 616 this.constantSystem = constantSystem; |
| 616 | 617 |
| 617 void visitGraph(HGraph graph) { | 618 void visitGraph(HGraph graph) { |
| 618 this.graph = graph; | 619 this.graph = graph; |
| 619 visitDominatorTree(graph); | 620 visitDominatorTree(graph); |
| 620 // We remove the range conversions after visiting the graph so | 621 // We remove the range conversions after visiting the graph so |
| 621 // that the graph does not get polluted with these instructions | 622 // that the graph does not get polluted with these instructions |
| 622 // only necessary for this phase. | 623 // only necessary for this phase. |
| 623 removeRangeConversion(); | 624 removeRangeConversion(); |
| 624 // TODO(herhut): Find a cleaner way to pass around ranges. | 625 // TODO(herhut): Find a cleaner way to pass around ranges. |
| 625 optimizer.ranges = ranges; | 626 optimizer.ranges = ranges; |
| 626 } | 627 } |
| 627 | 628 |
| 628 void removeRangeConversion() { | 629 void removeRangeConversion() { |
| 629 conversions.forEach((HRangeConversion instruction) { | 630 conversions.forEach((HRangeConversion instruction) { |
| 630 instruction.block.rewrite(instruction, instruction.inputs[0]); | 631 instruction.block.rewrite(instruction, instruction.inputs[0]); |
| 631 instruction.block.remove(instruction); | 632 instruction.block.remove(instruction); |
| 632 }); | 633 }); |
| 633 } | 634 } |
| 634 | 635 |
| 635 void visitBasicBlock(HBasicBlock block) { | 636 void visitBasicBlock(HBasicBlock block) { |
| 636 | |
| 637 void visit(HInstruction instruction) { | 637 void visit(HInstruction instruction) { |
| 638 Range range = instruction.accept(this); | 638 Range range = instruction.accept(this); |
| 639 if (instruction.isInteger(compiler)) { | 639 if (instruction.isInteger(compiler)) { |
| 640 assert(range != null); | 640 assert(range != null); |
| 641 ranges[instruction] = range; | 641 ranges[instruction] = range; |
| 642 } | 642 } |
| 643 } | 643 } |
| 644 | 644 |
| 645 block.forEachPhi(visit); | 645 block.forEachPhi(visit); |
| 646 block.forEachInstruction(visit); | 646 block.forEachInstruction(visit); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 // We might have lost the length range due to a type conversion that | 725 // We might have lost the length range due to a type conversion that |
| 726 // asserts a non-integer type. In such a case, the program will never | 726 // asserts a non-integer type. In such a case, the program will never |
| 727 // get to this point anyway, so no need to try and refine ranges. | 727 // get to this point anyway, so no need to try and refine ranges. |
| 728 return indexRange; | 728 return indexRange; |
| 729 } | 729 } |
| 730 assert(check.length.isInteger(compiler)); | 730 assert(check.length.isInteger(compiler)); |
| 731 | 731 |
| 732 // Check if the index is strictly below the upper bound of the length | 732 // Check if the index is strictly below the upper bound of the length |
| 733 // range. | 733 // range. |
| 734 Value maxIndex = lengthRange.upper - info.intOne; | 734 Value maxIndex = lengthRange.upper - info.intOne; |
| 735 bool belowLength = maxIndex != const MaxIntValue() | 735 bool belowLength = maxIndex != const MaxIntValue() && |
| 736 && indexRange.upper.min(maxIndex) == indexRange.upper; | 736 indexRange.upper.min(maxIndex) == indexRange.upper; |
| 737 | 737 |
| 738 // Check if the index is strictly below the lower bound of the length | 738 // Check if the index is strictly below the lower bound of the length |
| 739 // range. | 739 // range. |
| 740 belowLength = belowLength | 740 belowLength = belowLength || |
| 741 || (indexRange.upper != lengthRange.lower | 741 (indexRange.upper != lengthRange.lower && |
| 742 && indexRange.upper.min(lengthRange.lower) == indexRange.upper); | 742 indexRange.upper.min(lengthRange.lower) == indexRange.upper); |
| 743 if (indexRange.isPositive && belowLength) { | 743 if (indexRange.isPositive && belowLength) { |
| 744 check.block.rewrite(check, check.index); | 744 check.block.rewrite(check, check.index); |
| 745 check.block.remove(check); | 745 check.block.remove(check); |
| 746 } else if (indexRange.isNegative || lengthRange < indexRange) { | 746 } else if (indexRange.isNegative || lengthRange < indexRange) { |
| 747 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; | 747 check.staticChecks = HBoundsCheck.ALWAYS_FALSE; |
| 748 // The check is always false, and whatever instruction it | 748 // The check is always false, and whatever instruction it |
| 749 // dominates is dead code. | 749 // dominates is dead code. |
| 750 return indexRange; | 750 return indexRange; |
| 751 } else if (indexRange.isPositive) { | 751 } else if (indexRange.isPositive) { |
| 752 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; | 752 check.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; |
| 753 } else if (belowLength) { | 753 } else if (belowLength) { |
| 754 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; | 754 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; |
| 755 } | 755 } |
| 756 | 756 |
| 757 if (indexRange.isPositive) { | 757 if (indexRange.isPositive) { |
| 758 // If the test passes, we know the lower bound of the length is | 758 // If the test passes, we know the lower bound of the length is |
| 759 // greater or equal than the lower bound of the index. | 759 // greater or equal than the lower bound of the index. |
| 760 Value low = lengthRange.lower.max(indexRange.lower); | 760 Value low = lengthRange.lower.max(indexRange.lower); |
| 761 if (low != const UnknownValue()) { | 761 if (low != const UnknownValue()) { |
| 762 HInstruction instruction = | 762 HInstruction instruction = createRangeConversion(next, check.length); |
| 763 createRangeConversion(next, check.length); | |
| 764 ranges[instruction] = info.newNormalizedRange(low, lengthRange.upper); | 763 ranges[instruction] = info.newNormalizedRange(low, lengthRange.upper); |
| 765 } | 764 } |
| 766 } | 765 } |
| 767 | 766 |
| 768 // Update the range of the index if using the maximum index | 767 // Update the range of the index if using the maximum index |
| 769 // narrows it. Use that new range for this instruction as well. | 768 // narrows it. Use that new range for this instruction as well. |
| 770 Range newIndexRange = indexRange.intersection( | 769 Range newIndexRange = indexRange |
| 771 info.newNormalizedRange(info.intZero, maxIndex)); | 770 .intersection(info.newNormalizedRange(info.intZero, maxIndex)); |
| 772 if (indexRange == newIndexRange) return indexRange; | 771 if (indexRange == newIndexRange) return indexRange; |
| 773 // Explicitly attach the range information to the index instruction, | 772 // Explicitly attach the range information to the index instruction, |
| 774 // which may be used by other instructions. Returning the new range will | 773 // which may be used by other instructions. Returning the new range will |
| 775 // attach it to this instruction. | 774 // attach it to this instruction. |
| 776 HInstruction instruction = createRangeConversion(next, check.index); | 775 HInstruction instruction = createRangeConversion(next, check.index); |
| 777 ranges[instruction] = newIndexRange; | 776 ranges[instruction] = newIndexRange; |
| 778 return newIndexRange; | 777 return newIndexRange; |
| 779 } | 778 } |
| 780 | 779 |
| 781 Range visitRelational(HRelational relational) { | 780 Range visitRelational(HRelational relational) { |
| 782 HInstruction right = relational.right; | 781 HInstruction right = relational.right; |
| 783 HInstruction left = relational.left; | 782 HInstruction left = relational.left; |
| 784 if (!left.isInteger(compiler)) return info.newUnboundRange(); | 783 if (!left.isInteger(compiler)) return info.newUnboundRange(); |
| 785 if (!right.isInteger(compiler)) return info.newUnboundRange(); | 784 if (!right.isInteger(compiler)) return info.newUnboundRange(); |
| 786 BinaryOperation operation = relational.operation(constantSystem); | 785 BinaryOperation operation = relational.operation(constantSystem); |
| 787 Range rightRange = ranges[relational.right]; | 786 Range rightRange = ranges[relational.right]; |
| 788 Range leftRange = ranges[relational.left]; | 787 Range leftRange = ranges[relational.left]; |
| 789 | 788 |
| 790 if (relational is HIdentity) { | 789 if (relational is HIdentity) { |
| 791 handleEqualityCheck(relational); | 790 handleEqualityCheck(relational); |
| 792 } else if (operation.apply(leftRange, rightRange)) { | 791 } else if (operation.apply(leftRange, rightRange)) { |
| 793 relational.block.rewrite( | 792 relational.block |
| 794 relational, graph.addConstantBool(true, compiler)); | 793 .rewrite(relational, graph.addConstantBool(true, compiler)); |
| 795 relational.block.remove(relational); | 794 relational.block.remove(relational); |
| 796 } else if (negateOperation(operation).apply(leftRange, rightRange)) { | 795 } else if (negateOperation(operation).apply(leftRange, rightRange)) { |
| 797 relational.block.rewrite( | 796 relational.block |
| 798 relational, graph.addConstantBool(false, compiler)); | 797 .rewrite(relational, graph.addConstantBool(false, compiler)); |
| 799 relational.block.remove(relational); | 798 relational.block.remove(relational); |
| 800 } | 799 } |
| 801 return info.newUnboundRange(); | 800 return info.newUnboundRange(); |
| 802 } | 801 } |
| 803 | 802 |
| 804 void handleEqualityCheck(HRelational node) { | 803 void handleEqualityCheck(HRelational node) { |
| 805 Range right = ranges[node.right]; | 804 Range right = ranges[node.right]; |
| 806 Range left = ranges[node.left]; | 805 Range left = ranges[node.left]; |
| 807 if (left.isSingleValue && right.isSingleValue && left == right) { | 806 if (left.isSingleValue && right.isSingleValue && left == right) { |
| 808 node.block.rewrite( | 807 node.block.rewrite(node, graph.addConstantBool(true, compiler)); |
| 809 node, graph.addConstantBool(true, compiler)); | |
| 810 node.block.remove(node); | 808 node.block.remove(node); |
| 811 } | 809 } |
| 812 } | 810 } |
| 813 | 811 |
| 814 Range handleInvokeModulo(HInvokeDynamicMethod invoke) { | 812 Range handleInvokeModulo(HInvokeDynamicMethod invoke) { |
| 815 HInstruction left = invoke.inputs[1]; | 813 HInstruction left = invoke.inputs[1]; |
| 816 HInstruction right = invoke.inputs[2]; | 814 HInstruction right = invoke.inputs[2]; |
| 817 Range divisor = ranges[right]; | 815 Range divisor = ranges[right]; |
| 818 if (divisor != null) { | 816 if (divisor != null) { |
| 819 // For Integer values we can be precise in the upper bound, | 817 // For Integer values we can be precise in the upper bound, |
| 820 // so special case those. | 818 // so special case those. |
| 821 if (left.isInteger(compiler) && right.isInteger(compiler)) { | 819 if (left.isInteger(compiler) && right.isInteger(compiler)) { |
| 822 if (divisor.isPositive) { | 820 if (divisor.isPositive) { |
| 823 return info.newNormalizedRange(info.intZero, divisor.upper - | 821 return info.newNormalizedRange( |
| 824 info.intOne); | 822 info.intZero, divisor.upper - info.intOne); |
| 825 } else if (divisor.isNegative) { | 823 } else if (divisor.isNegative) { |
| 826 return info.newNormalizedRange(info.intZero, info.newNegateValue( | 824 return info.newNormalizedRange( |
| 827 divisor.lower) - info.intOne); | 825 info.intZero, info.newNegateValue(divisor.lower) - info.intOne); |
| 828 } | 826 } |
| 829 } else if (left.isNumber(compiler) && right.isNumber(compiler)) { | 827 } else if (left.isNumber(compiler) && right.isNumber(compiler)) { |
| 830 if (divisor.isPositive) { | 828 if (divisor.isPositive) { |
| 831 return info.newNormalizedRange(info.intZero, divisor.upper); | 829 return info.newNormalizedRange(info.intZero, divisor.upper); |
| 832 } else if (divisor.isNegative) { | 830 } else if (divisor.isNegative) { |
| 833 return info.newNormalizedRange(info.intZero, info.newNegateValue( | 831 return info.newNormalizedRange( |
| 834 divisor.lower)); | 832 info.intZero, info.newNegateValue(divisor.lower)); |
| 835 } | 833 } |
| 836 } | 834 } |
| 837 } | 835 } |
| 838 return info.newUnboundRange(); | 836 return info.newUnboundRange(); |
| 839 } | 837 } |
| 840 | 838 |
| 841 Range visitInvokeDynamicMethod(HInvokeDynamicMethod invoke) { | 839 Range visitInvokeDynamicMethod(HInvokeDynamicMethod invoke) { |
| 842 if ((invoke.inputs.length == 3) && (invoke.selector.name == "%")) | 840 if ((invoke.inputs.length == 3) && (invoke.selector.name == "%")) |
| 843 return handleInvokeModulo(invoke); | 841 return handleInvokeModulo(invoke); |
| 844 return super.visitInvokeDynamicMethod(invoke); | 842 return super.visitInvokeDynamicMethod(invoke); |
| 845 } | 843 } |
| 846 | 844 |
| 847 Range handleBinaryOperation(HBinaryArithmetic instruction) { | 845 Range handleBinaryOperation(HBinaryArithmetic instruction) { |
| 848 if (!instruction.isInteger(compiler)) return info.newUnboundRange(); | 846 if (!instruction.isInteger(compiler)) return info.newUnboundRange(); |
| 849 return instruction.operation(constantSystem).apply( | 847 return instruction |
| 850 ranges[instruction.left], ranges[instruction.right]); | 848 .operation(constantSystem) |
| 849 .apply(ranges[instruction.left], ranges[instruction.right]); |
| 851 } | 850 } |
| 852 | 851 |
| 853 Range visitAdd(HAdd add) { | 852 Range visitAdd(HAdd add) { |
| 854 return handleBinaryOperation(add); | 853 return handleBinaryOperation(add); |
| 855 } | 854 } |
| 856 | 855 |
| 857 Range visitSubtract(HSubtract sub) { | 856 Range visitSubtract(HSubtract sub) { |
| 858 return handleBinaryOperation(sub); | 857 return handleBinaryOperation(sub); |
| 859 } | 858 } |
| 860 | 859 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 884 return info.newUnboundRange(); | 883 return info.newUnboundRange(); |
| 885 } | 884 } |
| 886 | 885 |
| 887 Range visitCheck(HCheck instruction) { | 886 Range visitCheck(HCheck instruction) { |
| 888 if (ranges[instruction.checkedInput] == null) { | 887 if (ranges[instruction.checkedInput] == null) { |
| 889 return visitInstruction(instruction); | 888 return visitInstruction(instruction); |
| 890 } | 889 } |
| 891 return ranges[instruction.checkedInput]; | 890 return ranges[instruction.checkedInput]; |
| 892 } | 891 } |
| 893 | 892 |
| 894 HInstruction createRangeConversion(HInstruction cursor, | 893 HInstruction createRangeConversion( |
| 895 HInstruction instruction) { | 894 HInstruction cursor, HInstruction instruction) { |
| 896 JavaScriptBackend backend = compiler.backend; | 895 JavaScriptBackend backend = compiler.backend; |
| 897 HRangeConversion newInstruction = | 896 HRangeConversion newInstruction = |
| 898 new HRangeConversion(instruction, backend.intType); | 897 new HRangeConversion(instruction, backend.intType); |
| 899 conversions.add(newInstruction); | 898 conversions.add(newInstruction); |
| 900 cursor.block.addBefore(cursor, newInstruction); | 899 cursor.block.addBefore(cursor, newInstruction); |
| 901 // Update the users of the instruction dominated by [cursor] to | 900 // Update the users of the instruction dominated by [cursor] to |
| 902 // use the new instruction, that has an narrower range. | 901 // use the new instruction, that has an narrower range. |
| 903 instruction.replaceAllUsersDominatedBy(cursor, newInstruction); | 902 instruction.replaceAllUsersDominatedBy(cursor, newInstruction); |
| 904 return newInstruction; | 903 return newInstruction; |
| 905 } | 904 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 925 return const GreaterEqualOperation(); | 924 return const GreaterEqualOperation(); |
| 926 } else if (operation == const GreaterOperation()) { | 925 } else if (operation == const GreaterOperation()) { |
| 927 return const LessOperation(); | 926 return const LessOperation(); |
| 928 } else if (operation == const GreaterEqualOperation()) { | 927 } else if (operation == const GreaterEqualOperation()) { |
| 929 return const LessEqualOperation(); | 928 return const LessEqualOperation(); |
| 930 } else { | 929 } else { |
| 931 return null; | 930 return null; |
| 932 } | 931 } |
| 933 } | 932 } |
| 934 | 933 |
| 935 Range computeConstrainedRange(BinaryOperation operation, | 934 Range computeConstrainedRange( |
| 936 Range leftRange, | 935 BinaryOperation operation, Range leftRange, Range rightRange) { |
| 937 Range rightRange) { | |
| 938 Range range; | 936 Range range; |
| 939 if (operation == const LessOperation()) { | 937 if (operation == const LessOperation()) { |
| 940 range = info.newNormalizedRange( | 938 range = info.newNormalizedRange( |
| 941 const MinIntValue(), rightRange.upper - info.intOne); | 939 const MinIntValue(), rightRange.upper - info.intOne); |
| 942 } else if (operation == const LessEqualOperation()) { | 940 } else if (operation == const LessEqualOperation()) { |
| 943 range = info.newNormalizedRange(const MinIntValue(), rightRange.upper); | 941 range = info.newNormalizedRange(const MinIntValue(), rightRange.upper); |
| 944 } else if (operation == const GreaterOperation()) { | 942 } else if (operation == const GreaterOperation()) { |
| 945 range = info.newNormalizedRange( | 943 range = info.newNormalizedRange( |
| 946 rightRange.lower + info.intOne, const MaxIntValue()); | 944 rightRange.lower + info.intOne, const MaxIntValue()); |
| 947 } else if (operation == const GreaterEqualOperation()) { | 945 } else if (operation == const GreaterEqualOperation()) { |
| 948 range = info.newNormalizedRange(rightRange.lower, const MaxIntValue()); | 946 range = info.newNormalizedRange(rightRange.lower, const MaxIntValue()); |
| 949 } else { | 947 } else { |
| 950 range = info.newUnboundRange(); | 948 range = info.newUnboundRange(); |
| 951 } | 949 } |
| 952 return range.intersection(leftRange); | 950 return range.intersection(leftRange); |
| 953 } | 951 } |
| 954 | 952 |
| 955 Range visitConditionalBranch(HConditionalBranch branch) { | 953 Range visitConditionalBranch(HConditionalBranch branch) { |
| 956 var condition = branch.condition; | 954 var condition = branch.condition; |
| 957 // TODO(ngeoffray): Handle complex conditions. | 955 // TODO(ngeoffray): Handle complex conditions. |
| 958 if (condition is !HRelational) return info.newUnboundRange(); | 956 if (condition is! HRelational) return info.newUnboundRange(); |
| 959 if (condition is HIdentity) return info.newUnboundRange(); | 957 if (condition is HIdentity) return info.newUnboundRange(); |
| 960 HInstruction right = condition.right; | 958 HInstruction right = condition.right; |
| 961 HInstruction left = condition.left; | 959 HInstruction left = condition.left; |
| 962 if (!left.isInteger(compiler)) return info.newUnboundRange(); | 960 if (!left.isInteger(compiler)) return info.newUnboundRange(); |
| 963 if (!right.isInteger(compiler)) return info.newUnboundRange(); | 961 if (!right.isInteger(compiler)) return info.newUnboundRange(); |
| 964 | 962 |
| 965 Range rightRange = ranges[right]; | 963 Range rightRange = ranges[right]; |
| 966 Range leftRange = ranges[left]; | 964 Range leftRange = ranges[left]; |
| 967 Operation operation = condition.operation(constantSystem); | 965 Operation operation = condition.operation(constantSystem); |
| 968 Operation mirrorOp = flipOperation(operation); | 966 Operation mirrorOp = flipOperation(operation); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1085 } | 1083 } |
| 1086 | 1084 |
| 1087 Range handleBinaryOperation(HBinaryArithmetic instruction) { | 1085 Range handleBinaryOperation(HBinaryArithmetic instruction) { |
| 1088 Range leftRange = visit(instruction.left); | 1086 Range leftRange = visit(instruction.left); |
| 1089 Range rightRange = visit(instruction.right); | 1087 Range rightRange = visit(instruction.right); |
| 1090 if (leftRange == null || rightRange == null) return null; | 1088 if (leftRange == null || rightRange == null) return null; |
| 1091 BinaryOperation operation = instruction.operation(info.constantSystem); | 1089 BinaryOperation operation = instruction.operation(info.constantSystem); |
| 1092 return operation.apply(leftRange, rightRange); | 1090 return operation.apply(leftRange, rightRange); |
| 1093 } | 1091 } |
| 1094 } | 1092 } |
| OLD | NEW |