| Index: runtime/vm/intermediate_language.cc
|
| diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
|
| index 865976f991f88bf3061fbdda71a0fc38630899d7..77eb90dc0222a6b7af2d265f679e2dc07baa9185 100644
|
| --- a/runtime/vm/intermediate_language.cc
|
| +++ b/runtime/vm/intermediate_language.cc
|
| @@ -1589,6 +1589,41 @@ static bool IsRepresentable(const Integer& value, Representation rep) {
|
| }
|
|
|
|
|
| +RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const {
|
| + Integer& result = Integer::Handle();
|
| +
|
| + switch (op_kind()) {
|
| + case Token::kNEGATE:
|
| + result = value.ArithmeticOp(Token::kMUL, Smi::Handle(Smi::New(-1)));
|
| + break;
|
| +
|
| + case Token::kBIT_NOT:
|
| + if (value.IsSmi()) {
|
| + result = Integer::New(~Smi::Cast(value).Value());
|
| + } else if (value.IsMint()) {
|
| + result = Integer::New(~Mint::Cast(value).value());
|
| + }
|
| + break;
|
| +
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + if (!result.IsNull()) {
|
| + if (!IsRepresentable(result, representation())) {
|
| + // If this operation is not truncating it would deoptimize on overflow.
|
| + // Check that we match this behavior and don't produce a value that is
|
| + // larger than something this operation can produce. We could have
|
| + // specialized instructions that use this value under this assumption.
|
| + return Integer::null();
|
| + }
|
| + result ^= result.CheckAndCanonicalize(NULL);
|
| + }
|
| +
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left,
|
| const Integer& right) const {
|
| Integer& result = Integer::Handle();
|
| @@ -2309,22 +2344,48 @@ static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare,
|
| }
|
|
|
|
|
| -// Recognize the pattern (a & b) == 0 where left is a bitwise and operation
|
| -// and right is a constant 0.
|
| -static bool RecognizeTestPattern(Value* left, Value* right) {
|
| - if (!right->BindsToConstant()) {
|
| +static bool BindsToGivenConstant(Value* v, intptr_t expected) {
|
| + return v->BindsToConstant() &&
|
| + v->BoundConstant().IsSmi() &&
|
| + (Smi::Cast(v->BoundConstant()).Value() == expected);
|
| +}
|
| +
|
| +
|
| +// Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n.
|
| +static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) {
|
| + if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) {
|
| + return false;
|
| + }
|
| +
|
| + const intptr_t value = Smi::Cast(right->BoundConstant()).Value();
|
| + if ((value != 0) && !Utils::IsPowerOfTwo(value)) {
|
| return false;
|
| }
|
|
|
| - const Object& value = right->BoundConstant();
|
| - if (!value.IsSmi() || (Smi::Cast(value).Value() != 0)) {
|
| +
|
| + BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp();
|
| + if ((mask_op == NULL) ||
|
| + (mask_op->op_kind() != Token::kBIT_AND) ||
|
| + !mask_op->HasOnlyUse(left)) {
|
| return false;
|
| }
|
|
|
| - Definition* left_defn = left->definition();
|
| - return left_defn->IsBinarySmiOp() &&
|
| - (left_defn->AsBinarySmiOp()->op_kind() == Token::kBIT_AND) &&
|
| - left_defn->HasOnlyUse(left);
|
| + if (value == 0) {
|
| + // Recognized (a & b) == 0 pattern.
|
| + *negate = false;
|
| + return true;
|
| + }
|
| +
|
| + // Recognize
|
| + if (BindsToGivenConstant(mask_op->left(), value) ||
|
| + BindsToGivenConstant(mask_op->right(), value)) {
|
| + // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0
|
| + // so we need to negate original comparison.
|
| + *negate = true;
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| }
|
|
|
|
|
| @@ -2372,10 +2433,14 @@ Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) {
|
| } else if (comparison()->IsEqualityCompare() &&
|
| comparison()->operation_cid() == kSmiCid) {
|
| BinarySmiOpInstr* bit_and = NULL;
|
| - if (RecognizeTestPattern(comparison()->left(), comparison()->right())) {
|
| + bool negate = false;
|
| + if (RecognizeTestPattern(comparison()->left(),
|
| + comparison()->right(),
|
| + &negate)) {
|
| bit_and = comparison()->left()->definition()->AsBinarySmiOp();
|
| } else if (RecognizeTestPattern(comparison()->right(),
|
| - comparison()->left())) {
|
| + comparison()->left(),
|
| + &negate)) {
|
| bit_and = comparison()->right()->definition()->AsBinarySmiOp();
|
| }
|
| if (bit_and != NULL) {
|
| @@ -2384,7 +2449,8 @@ Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) {
|
| }
|
| TestSmiInstr* test = new TestSmiInstr(
|
| comparison()->token_pos(),
|
| - comparison()->kind(),
|
| + negate ? Token::NegateComparison(comparison()->kind())
|
| + : comparison()->kind(),
|
| bit_and->left()->Copy(isolate),
|
| bit_and->right()->Copy(isolate));
|
| ASSERT(!CanDeoptimize());
|
|
|