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

Unified Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 1393763004: dart2js cps_ir: BuiltinOperation improvements. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_backend/codegen/codegen.dart
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 14563e1b51a10219b58dd7c10d7990921f0fc4f7..92852b7e7c04db1ca1b8857971a57c5320b79d5f 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -858,12 +858,18 @@ class CodeGenerator extends tree_ir.StatementVisitor
return new js.Binary('-', args[0], args[1]);
case BuiltinOperator.NumMultiply:
return new js.Binary('*', args[0], args[1]);
+ case BuiltinOperator.NumDivide:
+ return new js.Binary('/', args[0], args[1]);
+ case BuiltinOperator.NumRemainder:
+ return new js.Binary('%', args[0], args[1]);
+ case BuiltinOperator.NumTruncatingDivideToSigned32:
+ return js.js('(# / #) | 0', args);
case BuiltinOperator.NumAnd:
- return js.js('(# & #) >>> 0', args);
+ return normalizeBitOp(js.js('# & #', args), node);
case BuiltinOperator.NumOr:
- return js.js('(# | #) >>> 0', args);
+ return normalizeBitOp(js.js('# | #', args), node);
case BuiltinOperator.NumXor:
- return js.js('(# ^ #) >>> 0', args);
+ return normalizeBitOp(js.js('# ^ #', args), node);
case BuiltinOperator.NumLt:
return new js.Binary('<', args[0], args[1]);
case BuiltinOperator.NumLe:
@@ -873,7 +879,10 @@ class CodeGenerator extends tree_ir.StatementVisitor
case BuiltinOperator.NumGe:
return new js.Binary('>=', args[0], args[1]);
case BuiltinOperator.NumShl:
- return js.js('(# << #) >>> 0', args);
+ return normalizeBitOp(js.js('# << #', args), node);
+ case BuiltinOperator.NumShr:
+ // No normalization required since output is always uint32.
+ return js.js('# >>> #', args);
case BuiltinOperator.StringConcatenate:
if (args.isEmpty) return js.string('');
return args.reduce((e1,e2) => new js.Binary('+', e1, e2));
@@ -911,6 +920,74 @@ class CodeGenerator extends tree_ir.StatementVisitor
}
}
+ /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit
+ /// range.
+ js.Expression normalizeBitOp(js.Expression op,
+ tree_ir.ApplyBuiltinOperator node) {
+ const MAX_UINT31 = 0x7fffffff;
+ const MAX_UINT32 = 0xffffffff;
+
+ int constantValue(tree_ir.Expression e) {
+ if (e is tree_ir.Constant) {
+ ConstantValue value = e.value;
+ if (!value.isInt) return null;
+ IntConstantValue intConstant = value;
+ if (intConstant.primitiveValue < 0) return null;
+ if (intConstant.primitiveValue > MAX_UINT32) return null;
+ return intConstant.primitiveValue;
+ }
+ return null;
+ }
+
+ /// Returns a value of the form 0b0001xxxx to represent the highest bit set
+ /// in the result. This represents the range [0, 0b00011111], up to 32
+ /// bits. `null` represents a result possibly outside the uint32 range.
+ int maxBitOf(tree_ir.Expression e) {
+ if (e is tree_ir.Constant) {
+ return constantValue(e);
+ }
+ if (e is tree_ir.ApplyBuiltinOperator) {
+ if (e.operator == BuiltinOperator.NumAnd) {
+ int left = maxBitOf(e.arguments[0]);
+ int right = maxBitOf(e.arguments[1]);
+ if (left == null && right == null) return MAX_UINT32;
+ if (left == null) return right;
+ if (right == null) return left;
+ return (left < right) ? left : right;
+ }
+ if (e.operator == BuiltinOperator.NumOr ||
+ e.operator == BuiltinOperator.NumXor) {
+ int left = maxBitOf(e.arguments[0]);
+ int right = maxBitOf(e.arguments[1]);
+ if (left == null || right == null) return MAX_UINT32;
+ return left | right;
+ }
+ if (e.operator == BuiltinOperator.NumShr) {
+ int right = constantValue(e.arguments[1]);
+ // NumShr is JavaScript '>>>' so always generates a uint32 result.
+ if (right == null || right <= 0 || right > 31) return MAX_UINT32;
+ int left = maxBitOf(e.arguments[0]);
+ if (left == null) return MAX_UINT32;
+ return left >> right;
+ }
+ if (e.operator == BuiltinOperator.NumShl) {
+ int right = constantValue(e.arguments[1]);
+ if (right == null || right <= 0 || right > 31) return MAX_UINT32;
+ int left = maxBitOf(e.arguments[0]);
+ if (left == null) return MAX_UINT32;
+ if (left.bitLength + right > 31) return MAX_UINT32;
+ return left << right;
+ }
+ }
+ return null;
+ }
+
+ int maxBit = maxBitOf(node);
+ if (maxBit != null && maxBit <= MAX_UINT31) return op;
+ return js.js('# >>> 0', [op]);
+ }
+
+
/// The JS name of a built-in method.
static final Map<BuiltinMethod, String> builtinMethodName =
const <BuiltinMethod, String>{
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/type_propagation.dart ('k') | tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698