Index: pkg/compiler/lib/src/ssa/codegen.dart |
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart |
index c882259fbdd51f9eb75271f782de0f219773e067..cd9d7c099fe3ba4e2bb35c46b0fbb9546353d57d 100644 |
--- a/pkg/compiler/lib/src/ssa/codegen.dart |
+++ b/pkg/compiler/lib/src/ssa/codegen.dart |
@@ -2,6 +2,7 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
+import 'dart:math' as math; |
import '../common.dart'; |
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
import '../common/tasks.dart' show CompilerTask; |
@@ -210,8 +211,59 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { |
return false; |
} |
+ // Returns the number of bits occupied by the value computed by [instruction]. |
+ // Returns `32` if the value is negative or does not fit in a smaller number |
+ // of bits. |
+ int bitWidth(HInstruction instruction) { |
+ const int MAX = 32; |
+ int constant(HInstruction insn) { |
+ if (insn is HConstant && insn.isConstantInteger()) { |
+ IntConstantValue constant = insn.constant; |
+ return constant.primitiveValue; |
+ } |
+ return null; |
+ } |
+ |
+ if (instruction.isConstantInteger()) { |
+ int value = constant(instruction); |
+ if (value < 0) return MAX; |
+ if (value > ((1 << 31) - 1)) return MAX; |
+ return value.bitLength; |
+ } |
+ if (instruction is HBitAnd) { |
+ return math.min(bitWidth(instruction.left), bitWidth(instruction.right)); |
+ } |
+ if (instruction is HBitOr || instruction is HBitXor) { |
+ HBinaryBitOp bitOp = instruction; |
+ int leftWidth = bitWidth(bitOp.left); |
+ if (leftWidth == MAX) return MAX; |
+ return math.max(leftWidth, bitWidth(bitOp.right)); |
+ } |
+ if (instruction is HShiftLeft) { |
+ int shiftCount = constant(instruction.right); |
+ if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX; |
+ int leftWidth = bitWidth(instruction.left); |
+ int width = leftWidth + shiftCount; |
+ return math.min(width, MAX); |
+ } |
+ if (instruction is HShiftRight) { |
+ int shiftCount = constant(instruction.right); |
+ if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX; |
+ int leftWidth = bitWidth(instruction.left); |
+ if (leftWidth >= MAX) return MAX; |
+ return math.max(leftWidth - shiftCount, 0); |
+ } |
+ if (instruction is HAdd) { |
+ return math.min( |
+ 1 + math.max(bitWidth(instruction.left), bitWidth(instruction.right)), |
+ MAX); |
+ } |
+ return MAX; |
+ } |
+ |
bool requiresUintConversion(instruction) { |
if (instruction.isUInt31(compiler)) return false; |
+ if (bitWidth(instruction) <= 31) return false; |
// If the result of a bit-operation is only used by other bit |
// operations, we do not have to convert to an unsigned integer. |
return hasNonBitOpUser(instruction, new Set<HPhi>()); |