| Index: src/compiler/arm/instruction-selector-arm.cc | 
| diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc | 
| index 95e3333669d8e8592dff60169af3f115b67958ec..03b0565487017a836ab5495016d06971ba1184f9 100644 | 
| --- a/src/compiler/arm/instruction-selector-arm.cc | 
| +++ b/src/compiler/arm/instruction-selector-arm.cc | 
| @@ -121,75 +121,122 @@ static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode, | 
| } | 
|  | 
|  | 
| -static Instruction* EmitBinop(InstructionSelector* selector, | 
| -                              InstructionCode opcode, size_t output_count, | 
| -                              InstructionOperand** outputs, Node* left, | 
| -                              Node* right, size_t label_count, | 
| -                              InstructionOperand** labels) { | 
| +static bool TryMatchROR(InstructionSelector* selector, | 
| +                        InstructionCode* opcode_return, Node* node, | 
| +                        InstructionOperand** value_return, | 
| +                        InstructionOperand** shift_return) { | 
| ArmOperandGenerator g(selector); | 
| -  InstructionOperand* inputs[5]; | 
| -  size_t input_count = 0; | 
| - | 
| -  inputs[input_count++] = g.UseRegister(left); | 
| -  if (g.CanBeImmediate(right, opcode)) { | 
| -    opcode |= AddressingModeField::encode(kMode_Operand2_I); | 
| -    inputs[input_count++] = g.UseImmediate(right); | 
| -  } else if (right->opcode() == IrOpcode::kWord32Sar) { | 
| -    Int32BinopMatcher mright(right); | 
| -    inputs[input_count++] = g.UseRegister(mright.left().node()); | 
| -    if (mright.right().IsInRange(1, 32)) { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); | 
| -      inputs[input_count++] = g.UseImmediate(mright.right().node()); | 
| -    } else { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); | 
| -      inputs[input_count++] = g.UseRegister(mright.right().node()); | 
| -    } | 
| -  } else if (right->opcode() == IrOpcode::kWord32Shl) { | 
| -    Int32BinopMatcher mright(right); | 
| -    inputs[input_count++] = g.UseRegister(mright.left().node()); | 
| -    if (mright.right().IsInRange(0, 31)) { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); | 
| -      inputs[input_count++] = g.UseImmediate(mright.right().node()); | 
| -    } else { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); | 
| -      inputs[input_count++] = g.UseRegister(mright.right().node()); | 
| -    } | 
| -  } else if (right->opcode() == IrOpcode::kWord32Shr) { | 
| -    Int32BinopMatcher mright(right); | 
| -    inputs[input_count++] = g.UseRegister(mright.left().node()); | 
| -    if (mright.right().IsInRange(1, 32)) { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); | 
| -      inputs[input_count++] = g.UseImmediate(mright.right().node()); | 
| -    } else { | 
| -      opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); | 
| -      inputs[input_count++] = g.UseRegister(mright.right().node()); | 
| -    } | 
| +  if (node->opcode() != IrOpcode::kWord32Or) return false; | 
| +  Int32BinopMatcher m(node); | 
| +  Node* shl = m.left().node(); | 
| +  Node* shr = m.right().node(); | 
| +  if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) { | 
| +    std::swap(shl, shr); | 
| +  } else if (!m.left().IsWord32Shl() || !m.right().IsWord32Shr()) { | 
| +    return false; | 
| +  } | 
| +  Int32BinopMatcher mshr(shr); | 
| +  Int32BinopMatcher mshl(shl); | 
| +  Node* value = mshr.left().node(); | 
| +  if (value != mshl.left().node()) return false; | 
| +  Node* shift = mshr.right().node(); | 
| +  Int32Matcher mshift(shift); | 
| +  if (mshift.IsInRange(1, 31) && mshl.right().Is(32 - mshift.Value())) { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); | 
| +    *value_return = g.UseRegister(value); | 
| +    *shift_return = g.UseImmediate(shift); | 
| +    return true; | 
| +  } | 
| +  if (mshl.right().IsInt32Sub()) { | 
| +    Int32BinopMatcher mshlright(mshl.right().node()); | 
| +    if (!mshlright.left().Is(32)) return false; | 
| +    if (mshlright.right().node() != shift) return false; | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R); | 
| +    *value_return = g.UseRegister(value); | 
| +    *shift_return = g.UseRegister(shift); | 
| +    return true; | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| + | 
| +static inline bool TryMatchASR(InstructionSelector* selector, | 
| +                               InstructionCode* opcode_return, Node* node, | 
| +                               InstructionOperand** value_return, | 
| +                               InstructionOperand** shift_return) { | 
| +  ArmOperandGenerator g(selector); | 
| +  if (node->opcode() != IrOpcode::kWord32Sar) return false; | 
| +  Int32BinopMatcher m(node); | 
| +  *value_return = g.UseRegister(m.left().node()); | 
| +  if (m.right().IsInRange(1, 32)) { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); | 
| +    *shift_return = g.UseImmediate(m.right().node()); | 
| } else { | 
| -    opcode |= AddressingModeField::encode(kMode_Operand2_R); | 
| -    inputs[input_count++] = g.UseRegister(right); | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); | 
| +    *shift_return = g.UseRegister(m.right().node()); | 
| } | 
| +  return true; | 
| +} | 
| + | 
|  | 
| -  // Append the optional labels. | 
| -  while (label_count-- != 0) { | 
| -    inputs[input_count++] = *labels++; | 
| +static inline bool TryMatchLSL(InstructionSelector* selector, | 
| +                               InstructionCode* opcode_return, Node* node, | 
| +                               InstructionOperand** value_return, | 
| +                               InstructionOperand** shift_return) { | 
| +  ArmOperandGenerator g(selector); | 
| +  if (node->opcode() != IrOpcode::kWord32Shl) return false; | 
| +  Int32BinopMatcher m(node); | 
| +  *value_return = g.UseRegister(m.left().node()); | 
| +  if (m.right().IsInRange(0, 31)) { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); | 
| +    *shift_return = g.UseImmediate(m.right().node()); | 
| +  } else { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); | 
| +    *shift_return = g.UseRegister(m.right().node()); | 
| } | 
| +  return true; | 
| +} | 
|  | 
| -  ASSERT_NE(0, input_count); | 
| -  ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 
| -  ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); | 
|  | 
| -  return selector->Emit(opcode, output_count, outputs, input_count, inputs); | 
| +static inline bool TryMatchLSR(InstructionSelector* selector, | 
| +                               InstructionCode* opcode_return, Node* node, | 
| +                               InstructionOperand** value_return, | 
| +                               InstructionOperand** shift_return) { | 
| +  ArmOperandGenerator g(selector); | 
| +  if (node->opcode() != IrOpcode::kWord32Shr) return false; | 
| +  Int32BinopMatcher m(node); | 
| +  *value_return = g.UseRegister(m.left().node()); | 
| +  if (m.right().IsInRange(1, 32)) { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); | 
| +    *shift_return = g.UseImmediate(m.right().node()); | 
| +  } else { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); | 
| +    *shift_return = g.UseRegister(m.right().node()); | 
| +  } | 
| +  return true; | 
| } | 
|  | 
|  | 
| -static Instruction* EmitBinop(InstructionSelector* selector, | 
| -                              InstructionCode opcode, Node* node, Node* left, | 
| -                              Node* right) { | 
| +static inline bool TryMatchImmediateOrShift(InstructionSelector* selector, | 
| +                                            InstructionCode* opcode_return, | 
| +                                            Node* node, | 
| +                                            size_t* input_count_return, | 
| +                                            InstructionOperand** inputs) { | 
| ArmOperandGenerator g(selector); | 
| -  InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; | 
| -  const size_t output_count = ARRAY_SIZE(outputs); | 
| -  return EmitBinop(selector, opcode, output_count, outputs, left, right, 0, | 
| -                   NULL); | 
| +  if (g.CanBeImmediate(node, *opcode_return)) { | 
| +    *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); | 
| +    inputs[0] = g.UseImmediate(node); | 
| +    *input_count_return = 1; | 
| +    return true; | 
| +  } | 
| +  if (TryMatchASR(selector, opcode_return, node, &inputs[0], &inputs[1]) || | 
| +      TryMatchLSL(selector, opcode_return, node, &inputs[0], &inputs[1]) || | 
| +      TryMatchLSR(selector, opcode_return, node, &inputs[0], &inputs[1]) || | 
| +      TryMatchROR(selector, opcode_return, node, &inputs[0], &inputs[1])) { | 
| +    *input_count_return = 2; | 
| +    return true; | 
| +  } | 
| +  return false; | 
| } | 
|  | 
|  | 
| @@ -198,17 +245,32 @@ static void VisitBinop(InstructionSelector* selector, Node* node, | 
| InstructionCode opcode, InstructionCode reverse_opcode) { | 
| ArmOperandGenerator g(selector); | 
| Int32BinopMatcher m(node); | 
| +  InstructionOperand* inputs[3]; | 
| +  size_t input_count = 0; | 
|  | 
| -  Node* left = m.left().node(); | 
| -  Node* right = m.right().node(); | 
| -  if (g.CanBeImmediate(m.left().node(), reverse_opcode) || | 
| -      m.left().IsWord32Sar() || m.left().IsWord32Shl() || | 
| -      m.left().IsWord32Shr()) { | 
| +  if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 
| +                               &input_count, &inputs[1])) { | 
| +    inputs[0] = g.UseRegister(m.left().node()); | 
| +    input_count++; | 
| +  } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, | 
| +                                      m.left().node(), &input_count, | 
| +                                      &inputs[1])) { | 
| +    inputs[0] = g.UseRegister(m.right().node()); | 
| opcode = reverse_opcode; | 
| -    std::swap(left, right); | 
| +    input_count++; | 
| +  } else { | 
| +    opcode |= AddressingModeField::encode(kMode_Operand2_R); | 
| +    inputs[input_count++] = g.UseRegister(m.left().node()); | 
| +    inputs[input_count++] = g.UseRegister(m.right().node()); | 
| } | 
|  | 
| -  EmitBinop(selector, opcode, node, left, right); | 
| +  ASSERT_NE(0, input_count); | 
| +  ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 
| +  ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); | 
| + | 
| +  InstructionOperand* outputs[1] = {g.DefineAsRegister(node)}; | 
| +  const size_t output_count = ARRAY_SIZE(outputs); | 
| +  selector->Emit(opcode, output_count, outputs, input_count, inputs); | 
| } | 
|  | 
|  | 
| @@ -311,20 +373,44 @@ void InstructionSelector::VisitStore(Node* node) { | 
| } | 
|  | 
|  | 
| +static inline void EmitBic(InstructionSelector* selector, Node* node, | 
| +                           Node* left, Node* right) { | 
| +  ArmOperandGenerator g(selector); | 
| +  InstructionCode opcode = kArmBic; | 
| +  InstructionOperand* inputs[3]; | 
| +  size_t input_count = 0; | 
| +  InstructionOperand* outputs[1] = {g.DefineAsRegister(node)}; | 
| +  const size_t output_count = ARRAY_SIZE(outputs); | 
| + | 
| +  inputs[input_count++] = g.UseRegister(left); | 
| +  if (!TryMatchImmediateOrShift(selector, &opcode, right, &input_count, | 
| +                                &inputs[input_count])) { | 
| +    opcode |= AddressingModeField::encode(kMode_Operand2_R); | 
| +    inputs[input_count++] = g.UseRegister(right); | 
| +  } | 
| + | 
| +  ASSERT_NE(0, input_count); | 
| +  ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 
| +  ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); | 
| + | 
| +  selector->Emit(opcode, output_count, outputs, input_count, inputs); | 
| +} | 
| + | 
| + | 
| void InstructionSelector::VisitWord32And(Node* node) { | 
| ArmOperandGenerator g(this); | 
| Int32BinopMatcher m(node); | 
| if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { | 
| Int32BinopMatcher mleft(m.left().node()); | 
| if (mleft.right().Is(-1)) { | 
| -      EmitBinop(this, kArmBic, node, m.right().node(), mleft.left().node()); | 
| +      EmitBic(this, node, m.right().node(), mleft.left().node()); | 
| return; | 
| } | 
| } | 
| if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { | 
| Int32BinopMatcher mright(m.right().node()); | 
| if (mright.right().Is(-1)) { | 
| -      EmitBinop(this, kArmBic, node, m.left().node(), mright.left().node()); | 
| +      EmitBic(this, node, m.left().node(), mright.left().node()); | 
| return; | 
| } | 
| } | 
| @@ -362,6 +448,14 @@ void InstructionSelector::VisitWord32And(Node* node) { | 
|  | 
|  | 
| void InstructionSelector::VisitWord32Or(Node* node) { | 
| +  ArmOperandGenerator g(this); | 
| +  InstructionCode opcode = kArmMov; | 
| +  InstructionOperand* value_operand; | 
| +  InstructionOperand* shift_operand; | 
| +  if (TryMatchROR(this, &opcode, node, &value_operand, &shift_operand)) { | 
| +    Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); | 
| +    return; | 
| +  } | 
| VisitBinop(this, node, kArmOrr, kArmOrr); | 
| } | 
|  | 
| @@ -378,18 +472,22 @@ void InstructionSelector::VisitWord32Xor(Node* node) { | 
| } | 
|  | 
|  | 
| +template <typename TryMatchShift> | 
| +static inline void VisitShift(InstructionSelector* selector, Node* node, | 
| +                              TryMatchShift try_match_shift) { | 
| +  ArmOperandGenerator g(selector); | 
| +  InstructionCode opcode = kArmMov; | 
| +  InstructionOperand* value_operand = NULL; | 
| +  InstructionOperand* shift_operand = NULL; | 
| +  CHECK( | 
| +      try_match_shift(selector, &opcode, node, &value_operand, &shift_operand)); | 
| +  selector->Emit(opcode, g.DefineAsRegister(node), value_operand, | 
| +                 shift_operand); | 
| +} | 
| + | 
| + | 
| void InstructionSelector::VisitWord32Shl(Node* node) { | 
| -  ArmOperandGenerator g(this); | 
| -  Int32BinopMatcher m(node); | 
| -  if (m.right().IsInRange(0, 31)) { | 
| -    Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_I), | 
| -         g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -         g.UseImmediate(m.right().node())); | 
| -  } else { | 
| -    Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_R), | 
| -         g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -         g.UseRegister(m.right().node())); | 
| -  } | 
| +  VisitShift(this, node, TryMatchLSL); | 
| } | 
|  | 
|  | 
| @@ -413,30 +511,12 @@ void InstructionSelector::VisitWord32Shr(Node* node) { | 
| } | 
| } | 
| } | 
| -  if (m.right().IsInRange(1, 32)) { | 
| -    Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_I), | 
| -         g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -         g.UseImmediate(m.right().node())); | 
| -    return; | 
| -  } | 
| -  Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_R), | 
| -       g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -       g.UseRegister(m.right().node())); | 
| +  VisitShift(this, node, TryMatchLSR); | 
| } | 
|  | 
|  | 
| void InstructionSelector::VisitWord32Sar(Node* node) { | 
| -  ArmOperandGenerator g(this); | 
| -  Int32BinopMatcher m(node); | 
| -  if (m.right().IsInRange(1, 32)) { | 
| -    Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_I), | 
| -         g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -         g.UseImmediate(m.right().node())); | 
| -  } else { | 
| -    Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_R), | 
| -         g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 
| -         g.UseRegister(m.right().node())); | 
| -  } | 
| +  VisitShift(this, node, TryMatchASR); | 
| } | 
|  | 
|  | 
| @@ -711,31 +791,44 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, | 
| bool commutative, bool requires_output) { | 
| ArmOperandGenerator g(selector); | 
| Int32BinopMatcher m(node); | 
| - | 
| -  Node* left = m.left().node(); | 
| -  Node* right = m.right().node(); | 
| -  if (g.CanBeImmediate(m.left().node(), opcode) || m.left().IsWord32Sar() || | 
| -      m.left().IsWord32Shl() || m.left().IsWord32Shr()) { | 
| +  InstructionOperand* inputs[5]; | 
| +  size_t input_count = 0; | 
| +  InstructionOperand* outputs[1]; | 
| +  size_t output_count = 0; | 
| + | 
| +  if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 
| +                               &input_count, &inputs[1])) { | 
| +    inputs[0] = g.UseRegister(m.left().node()); | 
| +    input_count++; | 
| +  } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), | 
| +                                      &input_count, &inputs[1])) { | 
| if (!commutative) cont->Commute(); | 
| -    std::swap(left, right); | 
| +    inputs[0] = g.UseRegister(m.right().node()); | 
| +    input_count++; | 
| +  } else { | 
| +    opcode |= AddressingModeField::encode(kMode_Operand2_R); | 
| +    inputs[input_count++] = g.UseRegister(m.left().node()); | 
| +    inputs[input_count++] = g.UseRegister(m.right().node()); | 
| } | 
|  | 
| -  opcode = cont->Encode(opcode); | 
| if (cont->IsBranch()) { | 
| -    InstructionOperand* outputs[1]; | 
| -    size_t output_count = 0; | 
| if (requires_output) { | 
| outputs[output_count++] = g.DefineAsRegister(node); | 
| } | 
| -    InstructionOperand* labels[] = {g.Label(cont->true_block()), | 
| -                                    g.Label(cont->false_block())}; | 
| -    const size_t label_count = ARRAY_SIZE(labels); | 
| -    EmitBinop(selector, opcode, output_count, outputs, left, right, label_count, | 
| -              labels)->MarkAsControl(); | 
| +    inputs[input_count++] = g.Label(cont->true_block()); | 
| +    inputs[input_count++] = g.Label(cont->false_block()); | 
| } else { | 
| ASSERT(cont->IsSet()); | 
| -    EmitBinop(selector, opcode, cont->result(), left, right); | 
| +    outputs[output_count++] = g.DefineAsRegister(cont->result()); | 
| } | 
| + | 
| +  ASSERT_NE(0, input_count); | 
| +  ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 
| +  ASSERT_GE(ARRAY_SIZE(outputs), output_count); | 
| + | 
| +  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, | 
| +                                      outputs, input_count, inputs); | 
| +  if (cont->IsBranch()) instr->MarkAsControl(); | 
| } | 
|  | 
|  | 
|  |