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 |