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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/bounds_checker.dart

Issue 1512303002: dart2js cps: Add instruction for bounds checks. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update gvn_test output Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_fragment.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library dart2js.cps_ir.bounds_checker; 5 library dart2js.cps_ir.bounds_checker;
6 6
7 import 'cps_ir_nodes.dart'; 7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart' show Pass; 8 import 'optimizers.dart' show Pass;
9 import 'octagon.dart'; 9 import 'octagon.dart';
10 import '../constants/values.dart'; 10 import '../constants/values.dart';
11 import 'cps_fragment.dart'; 11 import 'cps_fragment.dart';
12 import 'type_mask_system.dart'; 12 import 'type_mask_system.dart';
13 import '../types/types.dart';
13 import '../world.dart'; 14 import '../world.dart';
14 import '../elements/elements.dart'; 15 import '../elements/elements.dart';
15 import 'loop_effects.dart'; 16 import 'loop_effects.dart';
16 17
17
18
19 /// Eliminates bounds checks when they can be proven safe. 18 /// Eliminates bounds checks when they can be proven safe.
20 /// 19 ///
21 /// In general, this pass will try to eliminate any branch with arithmetic 20 /// In general, this pass will try to eliminate any branch with arithmetic
22 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc. 21 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc.
23 /// 22 ///
24 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon 23 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon
25 /// analyzers, we do not use a closed matrix representation, but just maintain 24 /// analyzers, we do not use a closed matrix representation, but just maintain
26 /// a bucket of constraints. Constraints can therefore be added and removed 25 /// a bucket of constraints. Constraints can therefore be added and removed
27 /// on-the-fly without significant overhead. 26 /// on-the-fly without significant overhead.
28 /// 27 ///
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 if (isUInt32(number)) { 106 if (isUInt32(number)) {
108 min = 0; 107 min = 0;
109 max = MAX_UINT32; 108 max = MAX_UINT32;
110 } else if (isNonNegativeInt(number)) { 109 } else if (isNonNegativeInt(number)) {
111 min = 0; 110 min = 0;
112 } 111 }
113 return valueOf.putIfAbsent(number, () => octagon.makeVariable(min, max)); 112 return valueOf.putIfAbsent(number, () => octagon.makeVariable(min, max));
114 } 113 }
115 114
116 /// Get a constraint variable representing the length of [indexableObject] at 115 /// Get a constraint variable representing the length of [indexableObject] at
117 /// program locations with the given [effectCounter]. 116 /// program locations with the given [effectNumber].
118 SignedVariable getLength(Primitive indexableObject, int effectCounter) { 117 SignedVariable getLength(Primitive indexableObject, int effectNumber) {
119 indexableObject = indexableObject.effectiveDefinition; 118 indexableObject = indexableObject.effectiveDefinition;
120 if (indexableObject.type != null && 119 TypeMask type = indexableObject.type.nonNullable();
121 types.isDefinitelyFixedLengthIndexable(indexableObject.type)) { 120 if (types.isDefinitelyFixedLengthIndexable(type)) {
122 // Always use the same effect counter if the length is immutable. 121 // Always use the same effect number if the length is immutable.
123 effectCounter = 0; 122 effectNumber = 0;
124 } 123 }
125 return lengthOf 124 return lengthOf
126 .putIfAbsent(indexableObject, () => <int, SignedVariable>{}) 125 .putIfAbsent(indexableObject, () => <int, SignedVariable>{})
127 .putIfAbsent(effectCounter, () => octagon.makeVariable(0, MAX_UINT32)); 126 .putIfAbsent(effectNumber, () {
127 int length = types.getContainerLength(type);
128 if (length != null) {
129 return octagon.makeVariable(length, length);
130 } else {
131 return octagon.makeVariable(0, MAX_UINT32);
132 }
133 });
128 } 134 }
129 135
130 // ------------- CONSTRAINT HELPERS ----------------- 136 // ------------- CONSTRAINT HELPERS -----------------
131 137
132 /// Puts the given constraint "in scope" by adding it to the octagon, and 138 /// Puts the given constraint "in scope" by adding it to the octagon, and
133 /// pushing a stack action that will remove it again. 139 /// pushing a stack action that will remove it again.
134 void applyConstraint(SignedVariable v1, SignedVariable v2, int k) { 140 void applyConstraint(SignedVariable v1, SignedVariable v2, int k) {
135 Constraint constraint = new Constraint(v1, v2, k); 141 Constraint constraint = new Constraint(v1, v2, k);
136 octagon.pushConstraint(constraint); 142 octagon.pushConstraint(constraint);
137 pushAction(() => octagon.popConstraint(constraint)); 143 pushAction(() => octagon.popConstraint(constraint));
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 } else if (isDefinitelyGreaterThanOrEqualTo(v1, v2)) { 237 } else if (isDefinitelyGreaterThanOrEqualTo(v1, v2)) {
232 makeGreaterThan(v1, v2); 238 makeGreaterThan(v1, v2);
233 } 239 }
234 } 240 }
235 241
236 /// Return true if we can prove that `v1 <= v2`. 242 /// Return true if we can prove that `v1 <= v2`.
237 bool isDefinitelyLessThanOrEqualTo(SignedVariable v1, SignedVariable v2) { 243 bool isDefinitelyLessThanOrEqualTo(SignedVariable v1, SignedVariable v2) {
238 return testConstraint(v1, v2.negated, 0); 244 return testConstraint(v1, v2.negated, 0);
239 } 245 }
240 246
247 /// Return true if we can prove that `v1 < v2`.
248 bool isDefinitelyLessThan(SignedVariable v1, SignedVariable v2) {
249 return testConstraint(v1, v2.negated, -1);
250 }
251
241 /// Return true if we can prove that `v1 >= v2`. 252 /// Return true if we can prove that `v1 >= v2`.
242 bool isDefinitelyGreaterThanOrEqualTo(SignedVariable v1, SignedVariable v2) { 253 bool isDefinitelyGreaterThanOrEqualTo(SignedVariable v1, SignedVariable v2) {
243 return testConstraint(v2, v1.negated, 0); 254 return testConstraint(v2, v1.negated, 0);
244 } 255 }
245 256
246 bool isDefinitelyLessThanOrEqualToConstant(SignedVariable v1, int value) { 257 bool isDefinitelyLessThanOrEqualToConstant(SignedVariable v1, int value) {
247 // v1 <= value <==> v1 + v1 <= 2 * value 258 // v1 <= value <==> v1 + v1 <= 2 * value
248 return testConstraint(v1, v1, 2 * value); 259 return testConstraint(v1, v1, 2 * value);
249 } 260 }
250 261
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 470
460 int getIntConstant(Primitive prim) { 471 int getIntConstant(Primitive prim) {
461 if (prim is Constant && prim.value.isInt) { 472 if (prim is Constant && prim.value.isInt) {
462 IntConstantValue constant = prim.value; 473 IntConstantValue constant = prim.value;
463 return constant.primitiveValue; 474 return constant.primitiveValue;
464 } 475 }
465 return null; 476 return null;
466 } 477 }
467 478
468 @override 479 @override
480 void visitRefinement(Refinement node) {
481 // In general we should get the container length of the refined type and
482 // add a constraint if we know the length after the refinement.
483 // However, our current type system removes container information when a
484 // type becomes part of a union, so this cannot happen.
485 }
486
487 @override
469 void visitGetLength(GetLength node) { 488 void visitGetLength(GetLength node) {
470 valueOf[node] = getLength(node.object.definition, currentEffectNumber); 489 valueOf[node] = getLength(node.object.definition, currentEffectNumber);
471 } 490 }
472 491
492 @override
493 void visitBoundsCheck(BoundsCheck node) {
494 if (node.checks == BoundsCheck.NONE) return;
495 assert(node.index != null); // Because there is at least one check.
496 Primitive object = node.object.definition;
497 SignedVariable length = node.length == null
498 ? null
499 : getValue(node.length.definition);
500 SignedVariable index = getValue(node.index.definition);
501 if (node.hasUpperBoundCheck) {
502 if (isDefinitelyLessThan(index, length)) {
503 node.checks &= ~BoundsCheck.UPPER_BOUND;
504 } else {
505 makeLessThan(index, length);
506 }
507 }
508 if (node.hasLowerBoundCheck) {
509 if (isDefinitelyGreaterThanOrEqualToConstant(index, 0)) {
510 node.checks &= ~BoundsCheck.LOWER_BOUND;
511 } else {
512 makeGreaterThanOrEqualToConstant(index, 0);
513 }
514 }
515 if (node.hasEmptinessCheck) {
516 if (isDefinitelyGreaterThanOrEqualToConstant(length, 1)) {
517 node.checks &= ~BoundsCheck.EMPTINESS;
518 } else {
519 makeGreaterThanOrEqualToConstant(length, 1);
520 }
521 }
522 if (!node.lengthUsedInCheck && node.length != null) {
523 node..length.unlink()..length = null;
524 }
525 if (node.checks == BoundsCheck.NONE) {
526 // We can't remove the bounds check node because it may still be used to
527 // restrict code motion. But the index is no longer needed.
528 node..index.unlink()..index = null;
529 }
530 }
531
473 void analyzeLoopEntry(InvokeContinuation node) { 532 void analyzeLoopEntry(InvokeContinuation node) {
474 foundLoop = true; 533 foundLoop = true;
475 Continuation cont = node.continuation.definition; 534 Continuation cont = node.continuation.definition;
476 if (isStrongLoopPass) { 535 if (isStrongLoopPass) {
477 for (int i = 0; i < node.arguments.length; ++i) { 536 for (int i = 0; i < node.arguments.length; ++i) {
478 Parameter param = cont.parameters[i]; 537 Parameter param = cont.parameters[i];
479 if (!isInt(param)) continue; 538 if (!isInt(param)) continue;
480 Primitive initialValue = node.arguments[i].definition; 539 Primitive initialValue = node.arguments[i].definition;
481 SignedVariable initialVariable = getValue(initialValue); 540 SignedVariable initialVariable = getValue(initialValue);
482 Monotonicity mono = monotonicity[param]; 541 Monotonicity mono = monotonicity[param];
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 } 732 }
674 return node.body; 733 return node.body;
675 } 734 }
676 } 735 }
677 736
678 /// Lattice representing the known (weak) monotonicity of a loop variable. 737 /// Lattice representing the known (weak) monotonicity of a loop variable.
679 /// 738 ///
680 /// The lattice bottom is represented by `null` and represents the case where 739 /// The lattice bottom is represented by `null` and represents the case where
681 /// the loop variable never changes value during the loop. 740 /// the loop variable never changes value during the loop.
682 enum Monotonicity { NotMonotone, Increasing, Decreasing, } 741 enum Monotonicity { NotMonotone, Increasing, Decreasing, }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_fragment.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698