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

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

Issue 1479193002: dart2js cps: Add more constraint rules to bounds-check elimination. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Merge 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/octagon.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';
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 void makeGreaterThanOrEqual(SignedVariable v1, SignedVariable v2) { 161 void makeGreaterThanOrEqual(SignedVariable v1, SignedVariable v2) {
162 // v1 >= v2 <==> v2 - v1 <= 0 162 // v1 >= v2 <==> v2 - v1 <= 0
163 applyConstraint(v2, v1.negated, 0); 163 applyConstraint(v2, v1.negated, 0);
164 } 164 }
165 165
166 void makeGreaterThan(SignedVariable v1, SignedVariable v2) { 166 void makeGreaterThan(SignedVariable v1, SignedVariable v2) {
167 // v1 > v2 <==> v2 - v1 <= -1 167 // v1 > v2 <==> v2 - v1 <= -1
168 applyConstraint(v2, v1.negated, -1); 168 applyConstraint(v2, v1.negated, -1);
169 } 169 }
170 170
171 void makeLessThanOrEqualToConstant(SignedVariable v1, int k) {
172 // v1 + v1 <= 2k
173 applyConstraint(v1, v1, 2 * k);
174 }
175
176 void makeGreaterThanOrEqualToConstant(SignedVariable v1, int k) {
177 // -v1 - v1 <= -2k
178 applyConstraint(v1.negated, v1.negated, -2 * k);
179 }
180
171 void makeConstant(SignedVariable v1, int k) { 181 void makeConstant(SignedVariable v1, int k) {
172 // We model this using the constraints: 182 // We model this using the constraints:
173 // v1 + v1 <= 2k 183 // v1 + v1 <= 2k
174 // -v1 - v1 <= -2k 184 // -v1 - v1 <= -2k
175 applyConstraint(v1, v1, 2 * k); 185 applyConstraint(v1, v1, 2 * k);
176 applyConstraint(v1.negated, v1.negated, -2 * k); 186 applyConstraint(v1.negated, v1.negated, -2 * k);
177 } 187 }
178 188
179 /// Make `v1 = v2 + k`. 189 /// Make `v1 = v2 + k`.
180 void makeExactSum(SignedVariable v1, SignedVariable v2, int k) { 190 void makeExactSum(SignedVariable v1, SignedVariable v2, int k) {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 // TODO(asgerf): It might be faster to inline the constant in the 332 // TODO(asgerf): It might be faster to inline the constant in the
323 // constraints that reference it. 333 // constraints that reference it.
324 if (node.value.isInt) { 334 if (node.value.isInt) {
325 IntConstantValue constant = node.value; 335 IntConstantValue constant = node.value;
326 makeConstant(getValue(node), constant.primitiveValue); 336 makeConstant(getValue(node), constant.primitiveValue);
327 } 337 }
328 } 338 }
329 339
330 @override 340 @override
331 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { 341 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
332 if (node.operator != BuiltinOperator.NumAdd && 342 if (!isInt(node)) return;
333 node.operator != BuiltinOperator.NumSubtract) { 343 if (node.arguments.length == 1) {
334 return; 344 applyUnaryOperator(node);
335 } 345 } else if (node.arguments.length == 2) {
336 if (!isInt(node.arguments[0].definition) || 346 applyBinaryOperator(node);
337 !isInt(node.arguments[1].definition)) {
338 return;
339 }
340 if (!isInt(node)) {
341 // TODO(asgerf): The result of this operation should always be an integer,
342 // but currently type propagation does not always prove this.
343 return;
344 }
345 // We have `v1 = v2 +/- v3`, but the octagon cannot represent constraints
346 // involving more than two variables. Check if one operand is a constant.
347 int getConstantArgument(int n) {
348 Primitive prim = node.arguments[n].definition;
349 if (prim is Constant && prim.value.isInt) {
350 IntConstantValue constant = prim.value;
351 return constant.primitiveValue;
352 }
353 return null;
354 }
355 int constant = getConstantArgument(0);
356 int operandIndex = 1;
357 if (constant == null) {
358 constant = getConstantArgument(1);
359 operandIndex = 0;
360 }
361 if (constant == null) {
362 // Neither argument was a constant.
363 // Classical octagon-based analyzers would compute upper and lower bounds
364 // for the two operands and add constraints for the result based on
365 // those. For performance reasons we omit that.
366 // TODO(asgerf): It seems expensive, but we should evaluate it.
367 return;
368 }
369 SignedVariable v1 = getValue(node);
370 SignedVariable v2 = getValue(node.arguments[operandIndex].definition);
371
372 if (node.operator == BuiltinOperator.NumAdd) {
373 // v1 = v2 + const
374 makeFloatingPointSum(v1, v2, constant);
375 } else if (operandIndex == 0) {
376 // v1 = v2 - const
377 makeFloatingPointSum(v1, v2, -constant);
378 } else {
379 // v1 = const - v2 <==> v1 = (-v2) + const
380 makeFloatingPointSum(v1, v2.negated, constant);
381 } 347 }
382 } 348 }
383 349
350 void applyBinaryOperator(ApplyBuiltinOperator node) {
351 Primitive left = node.arguments[0].definition;
352 Primitive right = node.arguments[1].definition;
353 if (!isInt(left) || !isInt(right)) {
354 return;
355 }
356 SignedVariable leftVar = getValue(left);
357 SignedVariable rightVar = getValue(right);
358 SignedVariable result = getValue(node);
359 switch (node.operator) {
360 case BuiltinOperator.NumAdd:
361 int leftConst = getIntConstant(left);
362 if (leftConst != null) {
363 makeFloatingPointSum(result, rightVar, leftConst);
364 }
365 int rightConst = getIntConstant(right);
366 if (rightConst != null) {
367 makeFloatingPointSum(result, leftVar, rightConst);
368 }
369 // Attempt to compute the sign of the result.
370 // TODO(asgerf): Compute upper/lower bounds instead of using 0.
371 if (testConstraint(leftVar, rightVar, 0)) {
372 makeLessThanOrEqualToConstant(result, 0);
373 }
374 if (testConstraint(leftVar.negated, rightVar.negated, 0)) {
375 makeGreaterThanOrEqualToConstant(result, 0);
376 }
377 // Classical octagon-based analyzers would compute upper and lower
378 // bounds for the two operands and add constraints for the result based
379 // on those. For performance reasons we only compute the sign
380 // TODO(asgerf): It seems expensive, but we should evaluate it.
381 break;
382
383 case BuiltinOperator.NumSubtract:
384 int leftConst = getIntConstant(left);
385 if (leftConst != null) {
386 // result = leftConst - right = (-right) + leftConst
387 makeFloatingPointSum(result, rightVar.negated, leftConst);
388 }
389 int rightConst = getIntConstant(right);
390 if (rightConst != null) {
391 // result = left - rightConst = left + (-rightConst)
392 makeFloatingPointSum(result, leftVar, -rightConst);
393 }
394 // Attempt to compute the sign of the result.
395 if (isDefinitelyGreaterThanOrEqualTo(leftVar, rightVar)) {
396 makeGreaterThanOrEqualToConstant(result, 0);
397 }
398 if (isDefinitelyLessThanOrEqualTo(leftVar, rightVar)) {
399 makeLessThanOrEqualToConstant(result, 0);
400 }
401 break;
402
403 case BuiltinOperator.NumTruncatingDivideToSigned32:
404 if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
405 // If we divide by a positive number, the result is closer to zero.
406 // If we divide by a negative number, the result is negative, and
407 // thus less than the original (non-negative) number.
408 // TODO(asgerf): The divisor is currently always positive, because
409 // type propagation checks that, but we could do better.
410 makeLessThanOrEqual(result, leftVar);
411 }
412 break;
413
414 case BuiltinOperator.NumShr:
415 if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
416 makeLessThanOrEqual(result, leftVar);
417 }
418 int shiftAmount = getIntConstant(right);
419 if (shiftAmount != null) {
420 // TODO(asgerf): Compute upper bound on [leftVar] and use that
421 // instead of MAX_UINT32.
422 makeLessThanOrEqualToConstant(result, MAX_UINT32 >> shiftAmount);
423 }
424 break;
425
426 case BuiltinOperator.NumRemainder:
427 // TODO(asgerf): This check overlaps with checks performed in a type
428 // propagation transformation, and we can do it more precisely here.
429 // Should we do the rewrite here?
430 if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0) &&
431 isDefinitelyGreaterThanOrEqualToConstant(rightVar, 1)) {
432 makeLessThanOrEqual(result, leftVar);
433 makeLessThan(result, rightVar);
434 }
435 break;
436
437 case BuiltinOperator.NumAnd:
438 // We use the faster UInt32 check instead of constraint based checks
439 // here, because the common case is that one operand is a constant.
440 if (isUInt32(left)) {
441 makeLessThanOrEqual(result, leftVar);
442 }
443 if (isUInt32(right)) {
444 makeLessThanOrEqual(result, rightVar);
445 }
446 break;
447
448 default:
449 }
450 }
451
452 void applyUnaryOperator(ApplyBuiltinOperator node) {
453 Primitive argument = node.arguments[0].definition;
454 if (!isInt(argument)) return;
455 if (node.operator == BuiltinOperator.NumNegate) {
456 valueOf[node] = getValue(argument).negated;
457 }
458 }
459
460 int getIntConstant(Primitive prim) {
461 if (prim is Constant && prim.value.isInt) {
462 IntConstantValue constant = prim.value;
463 return constant.primitiveValue;
464 }
465 return null;
466 }
467
384 @override 468 @override
385 void visitGetLength(GetLength node) { 469 void visitGetLength(GetLength node) {
386 valueOf[node] = getLength(node.object.definition, currentEffectNumber); 470 valueOf[node] = getLength(node.object.definition, currentEffectNumber);
387 } 471 }
388 472
389 void analyzeLoopEntry(InvokeContinuation node) { 473 void analyzeLoopEntry(InvokeContinuation node) {
390 foundLoop = true; 474 foundLoop = true;
391 Continuation cont = node.continuation.definition; 475 Continuation cont = node.continuation.definition;
392 if (isStrongLoopPass) { 476 if (isStrongLoopPass) {
393 for (int i = 0; i < node.arguments.length; ++i) { 477 for (int i = 0; i < node.arguments.length; ++i) {
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 } 673 }
590 return node.body; 674 return node.body;
591 } 675 }
592 } 676 }
593 677
594 /// Lattice representing the known (weak) monotonicity of a loop variable. 678 /// Lattice representing the known (weak) monotonicity of a loop variable.
595 /// 679 ///
596 /// The lattice bottom is represented by `null` and represents the case where 680 /// The lattice bottom is represented by `null` and represents the case where
597 /// the loop variable never changes value during the loop. 681 /// the loop variable never changes value during the loop.
598 enum Monotonicity { NotMonotone, Increasing, Decreasing, } 682 enum Monotonicity { NotMonotone, Increasing, Decreasing, }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/octagon.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698