| Index: runtime/vm/intermediate_language.h | 
| diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h | 
| index 57b98b75071a22271a6713d9e30180bba30b6b22..57f302180caf8005890828b728ddbfd026cc4fef 100644 | 
| --- a/runtime/vm/intermediate_language.h | 
| +++ b/runtime/vm/intermediate_language.h | 
| @@ -910,6 +910,9 @@ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) | 
| } | 
|  | 
| private: | 
| +  friend class BranchInstr;  // For RawSetInputAt. | 
| +  friend class IfThenElseInstr;  // For RawSetInputAt. | 
| + | 
| virtual void RawSetInputAt(intptr_t i, Value* value) = 0; | 
|  | 
| enum { | 
| @@ -2354,10 +2357,10 @@ class IndirectGotoInstr : public TemplateInstruction<1, NoThrow> { | 
| }; | 
|  | 
|  | 
| -class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { | 
| +class ComparisonInstr : public Definition { | 
| public: | 
| -  Value* left() const { return inputs_[0]; } | 
| -  Value* right() const { return inputs_[1]; } | 
| +  Value* left() const { return InputAt(0); } | 
| +  Value* right() const { return InputAt(1); } | 
|  | 
| virtual TokenPosition token_pos() const { return token_pos_; } | 
| Token::Kind kind() const { return kind_; } | 
| @@ -2396,17 +2399,11 @@ class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { | 
| protected: | 
| ComparisonInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| -                  Value* left, | 
| -                  Value* right, | 
| intptr_t deopt_id = Thread::kNoDeoptId) | 
| -      : TemplateDefinition(deopt_id), | 
| +      : Definition(deopt_id), | 
| token_pos_(token_pos), | 
| kind_(kind), | 
| operation_cid_(kIllegalCid) { | 
| -    SetInputAt(0, left); | 
| -    if (right != NULL) { | 
| -      SetInputAt(1, right); | 
| -    } | 
| } | 
|  | 
| private: | 
| @@ -2418,6 +2415,47 @@ class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { | 
| }; | 
|  | 
|  | 
| +class PureComparison : public ComparisonInstr { | 
| + public: | 
| +  virtual bool AllowsCSE() const { return true; } | 
| +  virtual EffectSet Dependencies() const { return EffectSet::None(); } | 
| + | 
| +  virtual EffectSet Effects() const { return EffectSet::None(); } | 
| + | 
| + protected: | 
| +  PureComparison(TokenPosition token_pos, Token::Kind kind, intptr_t deopt_id) | 
| +      : ComparisonInstr(token_pos, kind, deopt_id) { } | 
| +}; | 
| + | 
| + | 
| +template<intptr_t N, | 
| +         typename ThrowsTrait, | 
| +         template<typename Impure, typename Pure> class CSETrait = NoCSE> | 
| +class TemplateComparison : public CSETrait< | 
| +    ComparisonInstr, PureComparison>::Base { | 
| + public: | 
| +  TemplateComparison(TokenPosition token_pos, | 
| +                     Token::Kind kind, | 
| +                     intptr_t deopt_id = Thread::kNoDeoptId) | 
| +      : CSETrait<ComparisonInstr, PureComparison>::Base( | 
| +            token_pos, kind, deopt_id), | 
| +        inputs_() { } | 
| + | 
| +  virtual intptr_t InputCount() const { return N; } | 
| +  virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } | 
| + | 
| +  virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; } | 
| + | 
| + protected: | 
| +  EmbeddedArray<Value*, N> inputs_; | 
| + | 
| + private: | 
| +  virtual void RawSetInputAt(intptr_t i, Value* value) { | 
| +    inputs_[i] = value; | 
| +  } | 
| +}; | 
| + | 
| + | 
| class BranchInstr : public Instruction { | 
| public: | 
| explicit BranchInstr(ComparisonInstr* comparison) | 
| @@ -2976,7 +3014,7 @@ class PolymorphicInstanceCallInstr : public TemplateDefinition<0, Throws> { | 
| }; | 
|  | 
|  | 
| -class StrictCompareInstr : public ComparisonInstr { | 
| +class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> { | 
| public: | 
| StrictCompareInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| @@ -3018,14 +3056,16 @@ class StrictCompareInstr : public ComparisonInstr { | 
|  | 
| // Comparison instruction that is equivalent to the (left & right) == 0 | 
| // comparison pattern. | 
| -class TestSmiInstr : public ComparisonInstr { | 
| +class TestSmiInstr : public TemplateComparison<2, NoThrow, Pure> { | 
| public: | 
| TestSmiInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| Value* left, | 
| Value* right) | 
| -      : ComparisonInstr(token_pos, kind, left, right) { | 
| +      : TemplateComparison(token_pos, kind) { | 
| ASSERT(kind == Token::kEQ || kind == Token::kNE); | 
| +    SetInputAt(0, left); | 
| +    SetInputAt(1, right); | 
| } | 
|  | 
| DECLARE_INSTRUCTION(TestSmi); | 
| @@ -3053,24 +3093,21 @@ class TestSmiInstr : public ComparisonInstr { | 
|  | 
| // Checks the input value cid against cids stored in a table and returns either | 
| // a result or deoptimizes. | 
| -// TODO(srdjan): Modify ComparisonInstr to allow 1 or 2 arguments, since | 
| -// TestCidInstr needs only one argument | 
| -class TestCidsInstr : public ComparisonInstr { | 
| +class TestCidsInstr : public TemplateComparison<1, NoThrow, Pure> { | 
| public: | 
| TestCidsInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| Value* value, | 
| const ZoneGrowableArray<intptr_t>& cid_results, | 
| intptr_t deopt_id) | 
| -      : ComparisonInstr(token_pos, kind, value, NULL, deopt_id), | 
| +      : TemplateComparison(token_pos, kind, deopt_id), | 
| cid_results_(cid_results), | 
| licm_hoisted_(false) { | 
| ASSERT((kind == Token::kIS) || (kind == Token::kISNOT)); | 
| +    SetInputAt(0, value); | 
| set_operation_cid(kObjectCid); | 
| } | 
|  | 
| -  virtual intptr_t InputCount() const { return 1; } | 
| - | 
| const ZoneGrowableArray<intptr_t>& cid_results() const { | 
| return cid_results_; | 
| } | 
| @@ -3110,7 +3147,7 @@ class TestCidsInstr : public ComparisonInstr { | 
| }; | 
|  | 
|  | 
| -class EqualityCompareInstr : public ComparisonInstr { | 
| +class EqualityCompareInstr : public TemplateComparison<2, NoThrow, Pure> { | 
| public: | 
| EqualityCompareInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| @@ -3118,8 +3155,10 @@ class EqualityCompareInstr : public ComparisonInstr { | 
| Value* right, | 
| intptr_t cid, | 
| intptr_t deopt_id) | 
| -      : ComparisonInstr(token_pos, kind, left, right, deopt_id) { | 
| +      : TemplateComparison(token_pos, kind, deopt_id) { | 
| ASSERT(Token::IsEqualityOperator(kind)); | 
| +    SetInputAt(0, left); | 
| +    SetInputAt(1, right); | 
| set_operation_cid(cid); | 
| } | 
|  | 
| @@ -3151,7 +3190,7 @@ class EqualityCompareInstr : public ComparisonInstr { | 
| }; | 
|  | 
|  | 
| -class RelationalOpInstr : public ComparisonInstr { | 
| +class RelationalOpInstr : public TemplateComparison<2, NoThrow, Pure> { | 
| public: | 
| RelationalOpInstr(TokenPosition token_pos, | 
| Token::Kind kind, | 
| @@ -3159,8 +3198,10 @@ class RelationalOpInstr : public ComparisonInstr { | 
| Value* right, | 
| intptr_t cid, | 
| intptr_t deopt_id) | 
| -      : ComparisonInstr(token_pos, kind, left, right, deopt_id) { | 
| +      : TemplateComparison(token_pos, kind, deopt_id) { | 
| ASSERT(Token::IsRelationalOperator(kind)); | 
| +    SetInputAt(0, left); | 
| +    SetInputAt(1, right); | 
| set_operation_cid(cid); | 
| } | 
|  | 
| @@ -5343,24 +5384,21 @@ class BinaryDoubleOpInstr : public TemplateDefinition<2, NoThrow, Pure> { | 
| }; | 
|  | 
|  | 
| -class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { | 
| +class DoubleTestOpInstr : public TemplateComparison<1, NoThrow, Pure> { | 
| public: | 
| DoubleTestOpInstr(MethodRecognizer::Kind op_kind, | 
| -                    Value* d, | 
| +                    Value* value, | 
| intptr_t deopt_id, | 
| TokenPosition token_pos) | 
| -      : TemplateDefinition(deopt_id), | 
| -        op_kind_(op_kind), | 
| -        token_pos_(token_pos) { | 
| -    SetInputAt(0, d); | 
| +      : TemplateComparison(token_pos, Token::kEQ, deopt_id), | 
| +        op_kind_(op_kind) { | 
| +    SetInputAt(0, value); | 
| } | 
|  | 
| -  Value* value() const { return inputs_[0]; } | 
| +  Value* value() const { return InputAt(0); } | 
|  | 
| MethodRecognizer::Kind op_kind() const { return op_kind_; } | 
|  | 
| -  virtual TokenPosition token_pos() const { return token_pos_; } | 
| - | 
| virtual bool CanDeoptimize() const { return false; } | 
|  | 
| virtual Representation RequiredInputRepresentation(intptr_t idx) const { | 
| @@ -5368,12 +5406,6 @@ class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { | 
| return kUnboxedDouble; | 
| } | 
|  | 
| -  virtual intptr_t DeoptimizationTarget() const { | 
| -    // Direct access since this instruction cannot deoptimize, and the deopt-id | 
| -    // was inherited from another instruction that could deoptimize. | 
| -    return GetDeoptId(); | 
| -  } | 
| - | 
| PRINT_OPERANDS_TO_SUPPORT | 
|  | 
| DECLARE_INSTRUCTION(DoubleTestOp) | 
| @@ -5382,12 +5414,20 @@ class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { | 
| virtual Definition* Canonicalize(FlowGraph* flow_graph); | 
|  | 
| virtual bool AttributesEqual(Instruction* other) const { | 
| -    return op_kind_ == other->AsDoubleTestOp()->op_kind(); | 
| +    return op_kind_ == other->AsDoubleTestOp()->op_kind() | 
| +        && ComparisonInstr::AttributesEqual(other); | 
| } | 
|  | 
| +  virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right); | 
| + | 
| +  virtual void EmitBranchCode(FlowGraphCompiler* compiler, | 
| +                              BranchInstr* branch); | 
| + | 
| +  virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler, | 
| +                                       BranchLabels labels); | 
| + | 
| private: | 
| const MethodRecognizer::Kind op_kind_; | 
| -  const TokenPosition token_pos_; | 
|  | 
| DISALLOW_COPY_AND_ASSIGN(DoubleTestOpInstr); | 
| }; | 
|  |