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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 1950583002: Further bitop optimizations (Closed) Base URL: https://github.com/dart-lang/dev_compiler@master
Patch Set: rebase Created 4 years, 6 months 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 | « lib/runtime/dart_sdk.js ('k') | no next file » | 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 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 7
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
(...skipping 3328 matching lines...) Expand 10 before | Expand all | Expand 10 after
3339 return bitwise('# ^ #'); 3339 return bitwise('# ^ #');
3340 3340
3341 case TokenType.GT_GT: 3341 case TokenType.GT_GT:
3342 int shiftCount = _asIntInRange(right, 0, 31); 3342 int shiftCount = _asIntInRange(right, 0, 31);
3343 if (_is31BitUnsigned(left) && shiftCount != null) { 3343 if (_is31BitUnsigned(left) && shiftCount != null) {
3344 return binary('# >> #'); 3344 return binary('# >> #');
3345 } 3345 }
3346 if (_isDefinitelyNonNegative(left) && shiftCount != null) { 3346 if (_isDefinitelyNonNegative(left) && shiftCount != null) {
3347 return binary('# >>> #'); 3347 return binary('# >>> #');
3348 } 3348 }
3349 // TODO(sra): If the context selects out only bits that can't be 3349 // If the context selects out only bits that can't be affected by the
3350 // affected by the sign position we can use any JavaScript shift. 3350 // sign position we can use any JavaScript shift, `(x >> 6) & 3`.
3351 // E.g. `(x >> 6) & 3`. 3351 if (shiftCount != null &&
3352 _parentMasksToWidth(node, 31 - shiftCount)) {
3353 return binary('# >> #');
3354 }
3352 return _emitSend(left, op.lexeme, [right]); 3355 return _emitSend(left, op.lexeme, [right]);
3353 3356
3354 case TokenType.LT_LT: 3357 case TokenType.LT_LT:
3355 if (_is31BitUnsigned(node)) { 3358 if (_is31BitUnsigned(node)) {
3356 // Result is 31 bit unsigned which implies the shift count was small 3359 // Result is 31 bit unsigned which implies the shift count was small
3357 // enough not to pollute the sign bit. 3360 // enough not to pollute the sign bit.
3358 return binary('# << #'); 3361 return binary('# << #');
3359 } 3362 }
3360 if (_asIntInRange(right, 0, 31) != null) { 3363 if (_asIntInRange(right, 0, 31) != null) {
3361 return _coerceBitOperationResultToUnsigned(node, binary('# << #')); 3364 return _coerceBitOperationResultToUnsigned(node, binary('# << #'));
3362 } 3365 }
3363 return _emitSend(left, op.lexeme, [right]); 3366 return _emitSend(left, op.lexeme, [right]);
3364 3367
3365 default: 3368 default:
3366 // TODO(vsm): When do Dart ops not map to JS? 3369 // TODO(vsm): When do Dart ops not map to JS?
3367 return binary('# $op #'); 3370 return binary('# $op #');
3368 } 3371 }
3369 } 3372 }
3370 3373
3371 return _emitSend(left, op.lexeme, [right]); 3374 return _emitSend(left, op.lexeme, [right]);
3372 } 3375 }
3373 3376
3374 /// Bit operations are coerced to values on [0, 2^32). The coercion changes 3377 /// Bit operations are coerced to values on [0, 2^32). The coercion changes
3375 /// the interpretation of the 32-bit value from signed to unsigned. Most 3378 /// the interpretation of the 32-bit value from signed to unsigned. Most
3376 /// JavaScript operations interpret their operands as signed and generate 3379 /// JavaScript operations interpret their operands as signed and generate
3377 /// signed results. 3380 /// signed results.
3378 JS.Expression _coerceBitOperationResultToUnsigned( 3381 JS.Expression _coerceBitOperationResultToUnsigned(
3379 Expression node, JS.Expression operation) { 3382 Expression node, JS.Expression uncoerced) {
3380 // Don't coerce if the parent will coerce. 3383 // Don't coerce if the parent will coerce.
3381 AstNode parent = _parentOperation(node); 3384 AstNode parent = _parentOperation(node);
3382 if (_nodeIsBitwiseOperation(parent)) return operation; 3385 if (_nodeIsBitwiseOperation(parent)) return uncoerced;
3383 3386
3384 // Don't do a no-op coerce if the most significant bit is zero. 3387 // Don't do a no-op coerce if the most significant bit is zero.
3385 if (_is31BitUnsigned(node)) return operation; 3388 if (_is31BitUnsigned(node)) return uncoerced;
3386 3389
3387 // TODO(sra): If the consumer of the expression is '==' or '!=' to a 3390 // If the consumer of the expression is '==' or '!=' with a constant that
3388 // constant that fits in 31 bits, adding a coercion does not change the 3391 // fits in 31 bits, adding a coercion does not change the result of the
3389 // result of the comparision, e.g. `a & ~b == 0`. 3392 // comparision, e.g. `a & ~b == 0`.
3390 return js.call('# >>> 0', operation); 3393 if (parent is BinaryExpression) {
3394 var tokenType = parent.operator.type;
3395 Expression left = parent.leftOperand;
3396 Expression right = parent.rightOperand;
3397 if (tokenType == TokenType.EQ_EQ || tokenType == TokenType.BANG_EQ) {
3398 const int MAX = 0x7fffffff;
3399 if (_asIntInRange(right, 0, MAX) != null) return uncoerced;
3400 if (_asIntInRange(left, 0, MAX) != null) return uncoerced;
3401 } else if (tokenType == TokenType.GT_GT) {
3402 if (_isDefinitelyNonNegative(left) &&
3403 _asIntInRange(right, 0, 31) != null) {
3404 // Parent will generate `# >>> n`.
3405 return uncoerced;
3406 }
3407 }
3408 }
3409 return js.call('# >>> 0', uncoerced);
3391 } 3410 }
3392 3411
3393 AstNode _parentOperation(AstNode node) { 3412 AstNode _parentOperation(AstNode node) {
3394 node = node.parent; 3413 node = node.parent;
3395 while (node is ParenthesizedExpression) node = node.parent; 3414 while (node is ParenthesizedExpression) node = node.parent;
3396 return node; 3415 return node;
3397 } 3416 }
3398 3417
3399 bool _nodeIsBitwiseOperation(AstNode node) { 3418 bool _nodeIsBitwiseOperation(AstNode node) {
3400 if (node is BinaryExpression) { 3419 if (node is BinaryExpression) {
3401 switch (node.operator.type) { 3420 switch (node.operator.type) {
3402 case TokenType.AMPERSAND: 3421 case TokenType.AMPERSAND:
3403 case TokenType.BAR: 3422 case TokenType.BAR:
3404 case TokenType.CARET: 3423 case TokenType.CARET:
3405 return true; 3424 return true;
3406 } 3425 }
3407 return false; 3426 return false;
3408 } 3427 }
3409 if (node is PrefixExpression) { 3428 if (node is PrefixExpression) {
3410 return node.operator.type == TokenType.TILDE; 3429 return node.operator.type == TokenType.TILDE;
3411 } 3430 }
3412 return false; 3431 return false;
3413 } 3432 }
3414 3433
3415 Expression _skipParentheses(Expression expr) {
3416 while (expr is ParenthesizedExpression) {
3417 ParenthesizedExpression parenExpr = expr;
3418 expr = parenExpr.expression;
3419 }
3420 return expr;
3421 }
3422
3423 int _asIntInRange(Expression expr, int low, int high) { 3434 int _asIntInRange(Expression expr, int low, int high) {
3424 expr = _skipParentheses(expr); 3435 expr = expr.unParenthesized;
3425 if (expr is IntegerLiteral) { 3436 if (expr is IntegerLiteral) {
3426 if (expr.value >= low && expr.value <= high) return expr.value; 3437 if (expr.value >= low && expr.value <= high) return expr.value;
3438 return null;
3439 }
3440 int finishIdentifier(SimpleIdentifier identifier) {
3441 Element staticElement = identifier.staticElement;
3442 if (staticElement is PropertyAccessorElement && staticElement.isGetter) {
3443 PropertyInducingElement variable = staticElement.variable;
3444 int value = variable?.constantValue?.toIntValue();
3445 if (value != null && value >= low && value <= high) return value;
3446 }
3447 return null;
3448 }
3449 if (expr is SimpleIdentifier) {
3450 return finishIdentifier(expr);
3451 } else if (expr is PrefixedIdentifier && !expr.isDeferred) {
3452 return finishIdentifier(expr.identifier);
3427 } 3453 }
3428 return null; 3454 return null;
3429 } 3455 }
3430 3456
3431 bool _isDefinitelyNonNegative(Expression expr) { 3457 bool _isDefinitelyNonNegative(Expression expr) {
3432 expr = _skipParentheses(expr); 3458 expr = expr.unParenthesized;
3433 if (expr is IntegerLiteral) { 3459 if (expr is IntegerLiteral) {
3434 return expr.value >= 0; 3460 return expr.value >= 0;
3435 } 3461 }
3436 if (_nodeIsBitwiseOperation(expr)) return true; 3462 if (_nodeIsBitwiseOperation(expr)) return true;
3437 // TODO(sra): Lengths of known list types etc. 3463 // TODO(sra): Lengths of known list types etc.
3438 return false; 3464 return false;
3439 } 3465 }
3440 3466
3467 /// Does the parent of [node] mask the result to [width] bits or fewer?
3468 bool _parentMasksToWidth(AstNode node, int width) {
3469 AstNode parent = _parentOperation(node);
3470 if (parent == null) return false;
3471 if (_nodeIsBitwiseOperation(parent)) {
3472 if (parent is BinaryExpression &&
3473 parent.operator.type == TokenType.AMPERSAND) {
3474 Expression left = parent.leftOperand;
3475 Expression right = parent.rightOperand;
3476 final int MAX = (1 << width) - 1;
3477 if (_asIntInRange(right, 0, MAX) != null) return true;
3478 if (_asIntInRange(left, 0, MAX) != null) return true;
3479 }
3480 return _parentMasksToWidth(parent, width);
3481 }
3482 return false;
3483 }
3484
3441 /// Determines if the result of evaluating [expr] will be an non-negative 3485 /// Determines if the result of evaluating [expr] will be an non-negative
3442 /// value that fits in 31 bits. 3486 /// value that fits in 31 bits.
3443 bool _is31BitUnsigned(Expression expr) { 3487 bool _is31BitUnsigned(Expression expr) {
3444 const int MAX = 32; // Includes larger and negative values. 3488 const int MAX = 32; // Includes larger and negative values.
3445 /// Determines how many bits are required to hold result of evaluation 3489 /// Determines how many bits are required to hold result of evaluation
3446 /// [expr]. [depth] is used to bound exploration of huge expressions. 3490 /// [expr]. [depth] is used to bound exploration of huge expressions.
3447 int bitWidth(Expression expr, int depth) { 3491 int bitWidth(Expression expr, int depth) {
3448 if (expr is IntegerLiteral) { 3492 if (expr is IntegerLiteral) {
3449 return expr.value >= 0 ? expr.value.bitLength : MAX; 3493 return expr.value >= 0 ? expr.value.bitLength : MAX;
3450 } 3494 }
3451 if (++depth > 5) return MAX; 3495 if (++depth > 5) return MAX;
3452 if (expr is BinaryExpression) { 3496 if (expr is BinaryExpression) {
3453 var left = _skipParentheses(expr.leftOperand); 3497 var left = expr.leftOperand.unParenthesized;
3454 var right = _skipParentheses(expr.rightOperand); 3498 var right = expr.rightOperand.unParenthesized;
3455 switch (expr.operator.type) { 3499 switch (expr.operator.type) {
3456 case TokenType.AMPERSAND: 3500 case TokenType.AMPERSAND:
3457 return min(bitWidth(left, depth), bitWidth(right, depth)); 3501 return min(bitWidth(left, depth), bitWidth(right, depth));
3458 3502
3459 case TokenType.BAR: 3503 case TokenType.BAR:
3460 case TokenType.CARET: 3504 case TokenType.CARET:
3461 return max(bitWidth(left, depth), bitWidth(right, depth)); 3505 return max(bitWidth(left, depth), bitWidth(right, depth));
3462 3506
3463 case TokenType.GT_GT: 3507 case TokenType.GT_GT:
3464 int shiftValue = _asIntInRange(right, 0, 31); 3508 int shiftValue = _asIntInRange(right, 0, 31);
(...skipping 13 matching lines...) Expand all
3478 if (rightWidth <= 5) { 3522 if (rightWidth <= 5) {
3479 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to 3523 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to
3480 // (1 << 3) - 1 == 7 bits. 3524 // (1 << 3) - 1 == 7 bits.
3481 return min(MAX, leftWidth + ((1 << rightWidth) - 1)); 3525 return min(MAX, leftWidth + ((1 << rightWidth) - 1));
3482 } 3526 }
3483 return MAX; 3527 return MAX;
3484 default: 3528 default:
3485 return MAX; 3529 return MAX;
3486 } 3530 }
3487 } 3531 }
3532 int value = _asIntInRange(expr, 0, 0x7fffffff);
3533 if (value != null) return value.bitLength;
3488 return MAX; 3534 return MAX;
3489 } 3535 }
3490 return bitWidth(expr, 0) < 32; 3536 return bitWidth(expr, 0) < 32;
3491 } 3537 }
3492 3538
3493 /// If the type [t] is [int] or [double], or a type parameter 3539 /// If the type [t] is [int] or [double], or a type parameter
3494 /// bounded by [int], [double] or [num] returns [num]. 3540 /// bounded by [int], [double] or [num] returns [num].
3495 /// Otherwise returns [t]. 3541 /// Otherwise returns [t].
3496 DartType _canonicalizeNumTypes(DartType t) { 3542 DartType _canonicalizeNumTypes(DartType t) {
3497 var numType = types.numType; 3543 var numType = types.numType;
(...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after
4730 } 4776 }
4731 4777
4732 bool isLibraryPrefix(Expression node) => 4778 bool isLibraryPrefix(Expression node) =>
4733 node is SimpleIdentifier && node.staticElement is PrefixElement; 4779 node is SimpleIdentifier && node.staticElement is PrefixElement;
4734 4780
4735 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4781 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4736 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4782 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4737 4783
4738 bool _isDartRuntime(LibraryElement l) => 4784 bool _isDartRuntime(LibraryElement l) =>
4739 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4785 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698