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

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

Issue 1920293005: Improve code for shifts and bitwise operations. (Closed) Base URL: https://github.com/dart-lang/dev_compiler@master
Patch Set: Created 4 years, 7 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') | test/codegen/expect/notnull.js » ('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 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max;
6 7
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
8 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
10 import 'package:analyzer/dart/element/element.dart'; 11 import 'package:analyzer/dart/element/element.dart';
11 import 'package:analyzer/dart/element/type.dart'; 12 import 'package:analyzer/dart/element/type.dart';
12 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; 13 import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
13 //TODO(leafp): Remove deprecated dependency 14 //TODO(leafp): Remove deprecated dependency
14 //ignore: DEPRECATED_MEMBER_USE 15 //ignore: DEPRECATED_MEMBER_USE
15 import 'package:analyzer/src/generated/element.dart' 16 import 'package:analyzer/src/generated/element.dart'
(...skipping 2829 matching lines...) Expand 10 before | Expand all | Expand 10 after
2845 case TokenType.AMPERSAND: 2846 case TokenType.AMPERSAND:
2846 return bitwise('# & #'); 2847 return bitwise('# & #');
2847 2848
2848 case TokenType.BAR: 2849 case TokenType.BAR:
2849 return bitwise('# | #'); 2850 return bitwise('# | #');
2850 2851
2851 case TokenType.CARET: 2852 case TokenType.CARET:
2852 return bitwise('# ^ #'); 2853 return bitwise('# ^ #');
2853 2854
2854 case TokenType.GT_GT: 2855 case TokenType.GT_GT:
2855 // TODO(sra): Detect when JS shift does the right thing. 2856 int shiftCount = _asIntInRange(right, 0, 31);
2857 if (_is31BitUnsigned(left) && shiftCount != null) {
2858 return binary('# >> #');
2859 }
2860 if (_isDefinitelyNonNegative(left) && shiftCount != null) {
2861 return binary('# >>> #');
2862 }
2863 // TODO(sra): If the context selects out only bits that can't be
2864 // affected by the sign position we can use any JavaScript shift.
2865 // E.g. `(x >> 6) & 3`.
2856 return _emitSend(left, op.lexeme, [right]); 2866 return _emitSend(left, op.lexeme, [right]);
2857 2867
2858 case TokenType.LT_LT: 2868 case TokenType.LT_LT:
2859 // TODO(sra): Detect when JS shift does the right thing. 2869 if (_is31BitUnsigned(node)) {
2870 // Result is 31 bit unsigned which implies the shift count was small
2871 // enough not to pollute the sign bit.
2872 return binary('# << #');
2873 }
2874 if (_asIntInRange(right, 0, 31) != null) {
2875 return _coerceBitOperationResultToUnsigned(node, binary('# << #'));
2876 }
2860 return _emitSend(left, op.lexeme, [right]); 2877 return _emitSend(left, op.lexeme, [right]);
2861 2878
2862 default: 2879 default:
2863 // TODO(vsm): When do Dart ops not map to JS? 2880 // TODO(vsm): When do Dart ops not map to JS?
2864 return binary('# $op #'); 2881 return binary('# $op #');
2865 } 2882 }
2866 } 2883 }
2867 2884
2868 return _emitSend(left, op.lexeme, [right]); 2885 return _emitSend(left, op.lexeme, [right]);
2869 } 2886 }
2870 2887
2871 /// Bit operations are coerced to values on [0, 2^32). The coercion changes 2888 /// Bit operations are coerced to values on [0, 2^32). The coercion changes
2872 /// the interpretation of the 32-bit value from signed to unsigned. Most 2889 /// the interpretation of the 32-bit value from signed to unsigned. Most
2873 /// JavaScript operations interpret their operands as signed and generate 2890 /// JavaScript operations interpret their operands as signed and generate
2874 /// signed results. 2891 /// signed results.
2875 JS.Expression _coerceBitOperationResultToUnsigned( 2892 JS.Expression _coerceBitOperationResultToUnsigned(
2876 Expression node, JS.Expression operation) { 2893 Expression node, JS.Expression operation) {
2894 // Don't coerce if the parent will coerce.
2895 AstNode parent = _parentOperation(node);
2896 if (_nodeIsBitwiseOperation(parent)) return operation;
2897
2898 // Don't do a no-op coerce if the most significant bit is zero.
2899 if (_is31BitUnsigned(node)) return operation;
2900
2901 // TODO(sra): If the consumer of the expression is '==' or '!=' to a
2902 // constant that fits in 31 bits, adding a coercion does not change the
2903 // result of the comparision, e.g. `a & ~b == 0`.
2877 return js.call('# >>> 0', operation); 2904 return js.call('# >>> 0', operation);
2878 } 2905 }
2879 2906
2907 AstNode _parentOperation(AstNode node) {
2908 node = node.parent;
2909 while (node is ParenthesizedExpression) node = node.parent;
2910 return node;
2911 }
2912
2913 bool _nodeIsBitwiseOperation(AstNode node) {
2914 if (node is BinaryExpression) {
2915 switch (node.operator.type) {
2916 case TokenType.AMPERSAND:
2917 case TokenType.BAR:
2918 case TokenType.CARET:
2919 return true;
2920 }
2921 return false;
2922 }
2923 if (node is PrefixExpression) {
2924 return node.operator.type == TokenType.TILDE;
2925 }
2926 return false;
2927 }
2928
2929 Expression _skipParentheses(Expression expr) {
2930 while (expr is ParenthesizedExpression) {
2931 ParenthesizedExpression parenExpr = expr;
2932 expr = parenExpr.expression;
2933 }
2934 return expr;
2935 }
2936
2937 int _asIntInRange(Expression expr, int low, int high) {
2938 expr = _skipParentheses(expr);
2939 if (expr is IntegerLiteral) {
2940 if (expr.value >= low && expr.value <= high) return expr.value;
2941 }
2942 return null;
2943 }
2944
2945 bool _isDefinitelyNonNegative(Expression expr) {
2946 expr = _skipParentheses(expr);
2947 if (expr is IntegerLiteral) {
2948 return expr.value >= 0;
2949 }
2950 if (_nodeIsBitwiseOperation(expr)) return true;
2951 // TODO(sra): Lengths of known list types etc.
2952 return false;
2953 }
2954
2955 /// Determines if the result of evaluating [expr] will be an non-negative
2956 /// value that fits in 31 bits.
2957 bool _is31BitUnsigned(Expression expr) {
2958 const int MAX = 32; // Includes larger and negative values.
2959 /// Determines how many bits are required to hold result of evaluation
2960 /// [expr]. [depth] is used to bound exploration of huge expressions.
2961 int bitWidth(Expression expr, int depth) {
2962 if (expr is IntegerLiteral) {
2963 return expr.value >= 0 ? expr.value.bitLength : MAX;
2964 }
2965 if (++depth > 5) return MAX;
2966 if (expr is BinaryExpression) {
2967 var left = _skipParentheses(expr.leftOperand);
2968 var right = _skipParentheses(expr.rightOperand);
2969 switch (expr.operator.type) {
2970 case TokenType.AMPERSAND:
2971 return min(bitWidth(left, depth), bitWidth(right, depth));
2972
2973 case TokenType.BAR:
2974 case TokenType.CARET:
2975 return max(bitWidth(left, depth), bitWidth(right, depth));
2976
2977 case TokenType.GT_GT:
2978 int shiftValue = _asIntInRange(right, 0, 31);
2979 if (shiftValue != null) {
2980 int leftWidth = bitWidth(left, depth);
2981 return leftWidth == MAX ? MAX : max(0, leftWidth - shiftValue);
2982 }
2983 return MAX;
2984
2985 case TokenType.LT_LT:
2986 int leftWidth = bitWidth(left, depth);
2987 int shiftValue = _asIntInRange(right, 0, 31);
2988 if (shiftValue != null) {
2989 return min(MAX, leftWidth + shiftValue);
2990 }
2991 int rightWidth = bitWidth(right, depth);
2992 if (rightWidth <= 5) {
2993 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to
2994 // (1 << 3) - 1 == 7 bits.
2995 return min(MAX, leftWidth + ((1 << rightWidth) - 1));
2996 }
2997 return MAX;
2998 default:
2999 return MAX;
3000 }
3001 }
3002 return MAX;
3003 }
3004 return bitWidth(expr, 0) < 32;
3005 }
3006
2880 /// If the type [t] is [int] or [double], or a type parameter 3007 /// If the type [t] is [int] or [double], or a type parameter
2881 /// bounded by [int], [double] or [num] returns [num]. 3008 /// bounded by [int], [double] or [num] returns [num].
2882 /// Otherwise returns [t]. 3009 /// Otherwise returns [t].
2883 DartType _canonicalizeNumTypes(DartType t) { 3010 DartType _canonicalizeNumTypes(DartType t) {
2884 var numType = types.numType; 3011 var numType = types.numType;
2885 if (rules.isSubtypeOf(t, numType)) return numType; 3012 if (rules.isSubtypeOf(t, numType)) return numType;
2886 return t; 3013 return t;
2887 } 3014 }
2888 3015
2889 bool _canUsePrimitiveEquality(Expression left, Expression right) { 3016 bool _canUsePrimitiveEquality(Expression left, Expression right) {
(...skipping 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after
3949 } 4076 }
3950 4077
3951 bool isLibraryPrefix(Expression node) => 4078 bool isLibraryPrefix(Expression node) =>
3952 node is SimpleIdentifier && node.staticElement is PrefixElement; 4079 node is SimpleIdentifier && node.staticElement is PrefixElement;
3953 4080
3954 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4081 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
3955 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4082 c.computeLibraryElement(c.sourceFactory.forUri(uri));
3956 4083
3957 bool _isDartRuntime(LibraryElement l) => 4084 bool _isDartRuntime(LibraryElement l) =>
3958 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4085 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | test/codegen/expect/notnull.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698