Index: runtime/vm/intermediate_language.cc |
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc |
index 0c64c347fe51721707a272bef7e638cfb00ed102..e09e6c8505bf7edbddc69c3df590ff9e8c78a9cb 100644 |
--- a/runtime/vm/intermediate_language.cc |
+++ b/runtime/vm/intermediate_language.cc |
@@ -607,6 +607,7 @@ BranchInstr::BranchInstr(ComparisonInstr* comparison, bool is_checked) |
is_checked_(is_checked), |
constrained_type_(NULL), |
constant_target_(NULL) { |
+ ASSERT(comparison->env() == NULL); |
for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) { |
comparison->InputAt(i)->set_instruction(this); |
} |
@@ -628,18 +629,19 @@ void BranchInstr::ReplaceWith(ComparisonInstr* other, |
} |
-void BranchInstr::SetComparison(ComparisonInstr* comp) { |
- for (intptr_t i = comp->InputCount() - 1; i >= 0; --i) { |
- Value* input = comp->InputAt(i); |
+void BranchInstr::SetComparison(ComparisonInstr* new_comparison) { |
+ for (intptr_t i = new_comparison->InputCount() - 1; i >= 0; --i) { |
+ Value* input = new_comparison->InputAt(i); |
input->definition()->AddInputUse(input); |
input->set_instruction(this); |
} |
// There should be no need to copy or unuse an environment. |
ASSERT(comparison()->env() == NULL); |
+ ASSERT(new_comparison->env() == NULL); |
// Remove the current comparison's input uses. |
comparison()->UnuseAllInputs(); |
- ASSERT(!comp->HasUses()); |
- comparison_ = comp; |
+ ASSERT(!new_comparison->HasUses()); |
+ comparison_ = new_comparison; |
} |
@@ -1233,6 +1235,25 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
} |
+// Recognize the bpattern (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()) { |
+ return false; |
+ } |
+ |
+ const Object& value = right->BoundConstant(); |
+ if (!value.IsSmi() || (Smi::Cast(value).Value() != 0)) { |
+ return false; |
+ } |
+ |
+ Definition* left_defn = left->definition(); |
+ return left_defn->IsBinarySmiOp() && |
+ (left_defn->AsBinarySmiOp()->op_kind() == Token::kBIT_AND) && |
+ left_defn->HasOnlyUse(left); |
+} |
+ |
+ |
Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
// Only handle strict-compares. |
if (comparison()->IsStrictCompare()) { |
@@ -1261,6 +1282,7 @@ Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
RemoveEnvironment(); |
InheritDeoptTarget(comp); |
+ comp->RemoveEnvironment(); |
comp->RemoveFromGraph(); |
SetComparison(comp); |
if (FLAG_trace_optimization) { |
@@ -1272,6 +1294,25 @@ Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
comp->ClearSSATempIndex(); |
comp->ClearTempIndex(); |
} |
+ } else if (comparison()->IsSmiEquality()) { |
+ BinarySmiOpInstr* bit_and = NULL; |
+ if (RecognizeTestPattern(comparison()->left(), comparison()->right())) { |
+ bit_and = comparison()->left()->definition()->AsBinarySmiOp(); |
+ } else if (RecognizeTestPattern(comparison()->right(), |
+ comparison()->left())) { |
+ bit_and = comparison()->right()->definition()->AsBinarySmiOp(); |
+ } |
+ |
+ if (bit_and != NULL) { |
+ TestSmiInstr* test = new TestSmiInstr(comparison()->kind(), |
+ bit_and->left()->Copy(), |
+ bit_and->right()->Copy()); |
+ ASSERT(!CanDeoptimize()); |
+ InheritDeoptTarget(bit_and); |
+ RemoveEnvironment(); |
+ SetComparison(test); |
+ bit_and->RemoveFromGraph(); |
+ } |
} |
return this; |
} |