Revision: 22732
Author:   [email protected]
Date:     Thu Jul 31 07:44:29 2014 UTC
Log:      [arm] Add support for ROR. Refactor operand2 handling.

This was the last missing bit for full "flexible second operand" /
operand2 support on ARM.

TEST=cctest/test-instruction-selector-arm,cctest/test-run-machops
[email protected]

Review URL: https://codereview.chromium.org/434553002
http://code.google.com/p/v8/source/detail?r=22732

Modified:
 /branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc
 /branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h
 /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc
 /branches/bleeding_edge/test/cctest/compiler/codegen-tester.h
/branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc
 /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc
 /branches/bleeding_edge/test/cctest/compiler/value-helper.h

=======================================
--- /branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc Thu Jul 31 07:44:29 2014 UTC
@@ -79,6 +79,10 @@
return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
       case kMode_Operand2_R_LSR_R:
return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
+      case kMode_Operand2_R_ROR_I:
+ return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
+      case kMode_Operand2_R_ROR_R:
+ return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
     }
     UNREACHABLE();
     return Operand::Zero();
@@ -96,6 +100,8 @@
       case kMode_Operand2_R_LSL_R:
       case kMode_Operand2_R_LSR_I:
       case kMode_Operand2_R_LSR_R:
+      case kMode_Operand2_R_ROR_I:
+      case kMode_Operand2_R_ROR_R:
         break;
       case kMode_Offset_RI:
         *first_index += 2;
=======================================
--- /branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h Thu Jul 31 07:44:29 2014 UTC
@@ -73,9 +73,11 @@
   V(Operand2_R_ASR_I) /* %r0 ASR K */   \
   V(Operand2_R_LSL_I) /* %r0 LSL K */   \
   V(Operand2_R_LSR_I) /* %r0 LSR K */   \
+  V(Operand2_R_ROR_I) /* %r0 ROR K */   \
   V(Operand2_R_ASR_R) /* %r0 ASR %r1 */ \
   V(Operand2_R_LSL_R) /* %r0 LSL %r1 */ \
-  V(Operand2_R_LSR_R) /* %r0 LSR %r1 */
+  V(Operand2_R_LSR_R) /* %r0 LSR %r1 */ \
+  V(Operand2_R_ROR_R) /* %r0 ROR %r1 */

 }  // namespace compiler
 }  // namespace internal
=======================================
--- /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc Thu Jul 31 07:44:29 2014 UTC
@@ -121,75 +121,122 @@
 }


-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;
+  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;
+}

-  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());
-    }
+
+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 @@
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);
 }


@@ -309,6 +371,30 @@
          g.UseRegister(base), g.UseRegister(index), val);
   }
 }
+
+
+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) {
@@ -317,14 +403,14 @@
   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::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);
 }

@@ -376,20 +470,24 @@
     VisitBinop(this, node, kArmEor, kArmEor);
   }
 }
+
+
+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 @@
       }
     }
   }
-  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 @@
                              bool commutative, bool requires_output) {
   ArmOperandGenerator g(selector);
   Int32BinopMatcher m(node);
+  InstructionOperand* inputs[5];
+  size_t input_count = 0;
+  InstructionOperand* outputs[1];
+  size_t output_count = 0;

-  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()) {
+  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();
 }


=======================================
--- /branches/bleeding_edge/test/cctest/compiler/codegen-tester.h Wed Jul 30 15:34:09 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/codegen-tester.h Thu Jul 31 07:44:29 2014 UTC
@@ -101,6 +101,25 @@
       : MachineAssemblerTester<RawMachineAssembler>(
ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3,
             p4) {}
+
+  template <typename Ci, typename Fn>
+  void Run(const Ci& ci, const Fn& fn) {
+    typename Ci::const_iterator i;
+    for (i = ci.begin(); i != ci.end(); ++i) {
+      CHECK_EQ(fn(*i), this->Call(*i));
+    }
+  }
+
+  template <typename Ci, typename Cj, typename Fn>
+  void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
+    typename Ci::const_iterator i;
+    typename Cj::const_iterator j;
+    for (i = ci.begin(); i != ci.end(); ++i) {
+      for (j = cj.begin(); j != cj.end(); ++j) {
+        CHECK_EQ(fn(*i, *j), this->Call(*i, *j));
+      }
+    }
+  }
 };


@@ -162,6 +181,17 @@
       T->Return(val);
     }
   }
+
+  template <typename Ci, typename Cj, typename Fn>
+  void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
+    typename Ci::const_iterator i;
+    typename Cj::const_iterator j;
+    for (i = ci.begin(); i != ci.end(); ++i) {
+      for (j = cj.begin(); j != cj.end(); ++j) {
+        CHECK_EQ(fn(*i, *j), this->call(*i, *j));
+      }
+    }
+  }

  protected:
   CType p0;
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc Thu Jul 31 07:44:29 2014 UTC
@@ -5,6 +5,7 @@
 #include <list>

 #include "test/cctest/compiler/instruction-selector-tester.h"
+#include "test/cctest/compiler/value-helper.h"

 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -128,6 +129,66 @@
     }
   }
 }
+
+
+TEST(InstructionSelectorDPIAndRotateRightP) {
+  DPIs dpis;
+  for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
+    DPI dpi = *i;
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(1);
+      Node* shift = m.Parameter(2);
+      Node* ror = m.Word32Or(
+          m.Word32Shr(value, shift),
+          m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)));
+      m.Return(m.NewNode(dpi.op, m.Parameter(0), ror));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    }
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(1);
+      Node* shift = m.Parameter(2);
+      Node* ror =
+ m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)),
+                     m.Word32Shr(value, shift));
+      m.Return(m.NewNode(dpi.op, m.Parameter(0), ror));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    }
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(1);
+      Node* shift = m.Parameter(2);
+      Node* ror = m.Word32Or(
+          m.Word32Shr(value, shift),
+          m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)));
+      m.Return(m.NewNode(dpi.op, ror, m.Parameter(0)));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    }
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(1);
+      Node* shift = m.Parameter(2);
+      Node* ror =
+ m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)),
+                     m.Word32Shr(value, shift));
+      m.Return(m.NewNode(dpi.op, ror, m.Parameter(0)));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    }
+  }
+}


 TEST(InstructionSelectorDPIAndShiftImm) {
@@ -222,6 +283,100 @@
     CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
   }
 }
+
+
+TEST(InstructionSelectorShiftP) {
+  Shifts shifts;
+  for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
+    Shift shift = *i;
+    InstructionSelectorTester m;
+    m.Return(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+    CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
+    CHECK_EQ(2, m.code[0]->InputCount());
+  }
+}
+
+
+TEST(InstructionSelectorShiftImm) {
+  Shifts shifts;
+  for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
+    Shift shift = *i;
+    for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) {
+      InstructionSelectorTester m;
+      m.Return(m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+      CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+      CHECK_EQ(2, m.code[0]->InputCount());
+      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+    }
+  }
+}
+
+
+TEST(InstructionSelectorRotateRightP) {
+  {
+    InstructionSelectorTester m;
+    Node* value = m.Parameter(0);
+    Node* shift = m.Parameter(1);
+    m.Return(
+        m.Word32Or(m.Word32Shr(value, shift),
+ m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(2, m.code[0]->InputCount());
+  }
+  {
+    InstructionSelectorTester m;
+    Node* value = m.Parameter(0);
+    Node* shift = m.Parameter(1);
+    m.Return(
+ m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)),
+                   m.Word32Shr(value, shift)));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(2, m.code[0]->InputCount());
+  }
+}
+
+
+TEST(InstructionSelectorRotateRightImm) {
+  FOR_INPUTS(uint32_t, ror, i) {
+    uint32_t shift = *i;
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(0);
+      m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)),
+ m.Word32Shl(value, m.Int32Constant(32 - shift))));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(2, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1)));
+    }
+    {
+      InstructionSelectorTester m;
+      Node* value = m.Parameter(0);
+      m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)),
+                          m.Word32Shr(value, m.Int32Constant(shift))));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmMov, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(2, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1)));
+    }
+  }
+}


 TEST(InstructionSelectorInt32MulP) {
@@ -917,6 +1072,185 @@
     }
   }
 }
+
+
+TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightP) {
+  {
+    InstructionSelectorTester m;
+    MLabel blocka, blockb;
+    Node* input = m.Parameter(0);
+    Node* value = m.Parameter(1);
+    Node* shift = m.Parameter(2);
+    Node* ror =
+        m.Word32Or(m.Word32Shr(value, shift),
+ m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)));
+    m.Branch(m.Word32Equal(input, ror), &blocka, &blockb);
+    m.Bind(&blocka);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&blockb);
+    m.Return(m.Int32Constant(0));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+    CHECK_EQ(kEqual, m.code[0]->flags_condition());
+  }
+  {
+    InstructionSelectorTester m;
+    MLabel blocka, blockb;
+    Node* input = m.Parameter(0);
+    Node* value = m.Parameter(1);
+    Node* shift = m.Parameter(2);
+    Node* ror =
+ m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)),
+                   m.Word32Shr(value, shift));
+    m.Branch(m.Word32Equal(input, ror), &blocka, &blockb);
+    m.Bind(&blocka);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&blockb);
+    m.Return(m.Int32Constant(0));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+    CHECK_EQ(kEqual, m.code[0]->flags_condition());
+  }
+  {
+    InstructionSelectorTester m;
+    MLabel blocka, blockb;
+    Node* input = m.Parameter(0);
+    Node* value = m.Parameter(1);
+    Node* shift = m.Parameter(2);
+    Node* ror =
+        m.Word32Or(m.Word32Shr(value, shift),
+ m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)));
+    m.Branch(m.Word32Equal(ror, input), &blocka, &blockb);
+    m.Bind(&blocka);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&blockb);
+    m.Return(m.Int32Constant(0));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+    CHECK_EQ(kEqual, m.code[0]->flags_condition());
+  }
+  {
+    InstructionSelectorTester m;
+    MLabel blocka, blockb;
+    Node* input = m.Parameter(0);
+    Node* value = m.Parameter(1);
+    Node* shift = m.Parameter(2);
+    Node* ror =
+ m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)),
+                   m.Word32Shr(value, shift));
+    m.Branch(m.Word32Equal(ror, input), &blocka, &blockb);
+    m.Bind(&blocka);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&blockb);
+    m.Return(m.Int32Constant(0));
+    m.SelectInstructions();
+    CHECK_EQ(1, m.code.size());
+    CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+    CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode());
+    CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+    CHECK_EQ(kEqual, m.code[0]->flags_condition());
+  }
+}
+
+
+TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightImm) {
+  FOR_INPUTS(uint32_t, ror, i) {
+    uint32_t shift = *i;
+    {
+      InstructionSelectorTester m;
+      MLabel blocka, blockb;
+      Node* input = m.Parameter(0);
+      Node* value = m.Parameter(1);
+      Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)),
+ m.Word32Shl(value, m.Int32Constant(32 - shift)));
+      m.Branch(m.Word32Equal(input, ror), &blocka, &blockb);
+      m.Bind(&blocka);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&blockb);
+      m.Return(m.Int32Constant(0));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+      CHECK_EQ(kEqual, m.code[0]->flags_condition());
+      CHECK_LE(3, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2)));
+    }
+    {
+      InstructionSelectorTester m;
+      MLabel blocka, blockb;
+      Node* input = m.Parameter(0);
+      Node* value = m.Parameter(1);
+ Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)),
+                             m.Word32Shr(value, m.Int32Constant(shift)));
+      m.Branch(m.Word32Equal(input, ror), &blocka, &blockb);
+      m.Bind(&blocka);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&blockb);
+      m.Return(m.Int32Constant(0));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+      CHECK_EQ(kEqual, m.code[0]->flags_condition());
+      CHECK_LE(3, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2)));
+    }
+    {
+      InstructionSelectorTester m;
+      MLabel blocka, blockb;
+      Node* input = m.Parameter(0);
+      Node* value = m.Parameter(1);
+      Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)),
+ m.Word32Shl(value, m.Int32Constant(32 - shift)));
+      m.Branch(m.Word32Equal(ror, input), &blocka, &blockb);
+      m.Bind(&blocka);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&blockb);
+      m.Return(m.Int32Constant(0));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+      CHECK_EQ(kEqual, m.code[0]->flags_condition());
+      CHECK_LE(3, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2)));
+    }
+    {
+      InstructionSelectorTester m;
+      MLabel blocka, blockb;
+      Node* input = m.Parameter(0);
+      Node* value = m.Parameter(1);
+ Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)),
+                             m.Word32Shr(value, m.Int32Constant(shift)));
+      m.Branch(m.Word32Equal(ror, input), &blocka, &blockb);
+      m.Bind(&blocka);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&blockb);
+      m.Return(m.Int32Constant(0));
+      m.SelectInstructions();
+      CHECK_EQ(1, m.code.size());
+      CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode());
+      CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
+      CHECK_EQ(kEqual, m.code[0]->flags_condition());
+      CHECK_LE(3, m.code[0]->InputCount());
+      CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2)));
+    }
+  }
+}


 TEST(InstructionSelectorBranchWithDPIP) {
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc Wed Jul 30 16:21:36 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc Thu Jul 31 07:44:29 2014 UTC
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.

+#include <functional>
 #include <limits>
-#include "src/v8.h"

 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
@@ -3678,6 +3678,53 @@
     CHECK_EQ(kInputSize - i - 1, outputs[i]);
   }
 }
+
+
+static inline uint32_t rotr32(uint32_t i, uint32_t j) {
+  return (i >> j) | (i << (32 - j));
+}
+
+
+TEST(RunTestInt32RotateRightP) {
+  {
+    RawMachineAssemblerTester<int32_t> m;
+    Int32BinopTester bt(&m);
+    bt.AddReturn(m.Word32Or(
+        m.Word32Shr(bt.param0, bt.param1),
+ m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)))); + bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32);
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m;
+    Int32BinopTester bt(&m);
+    bt.AddReturn(m.Word32Or(
+        m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)),
+        m.Word32Shr(bt.param0, bt.param1)));
+ bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32);
+  }
+}
+
+
+TEST(RunTestInt32RotateRightImm) {
+  FOR_INPUTS(uint32_t, ror, i) {
+    {
+      RawMachineAssemblerTester<int32_t> m(kMachineWord32);
+      Node* value = m.Parameter(0);
+      m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(*i)),
+                          m.Word32Shl(value, m.Int32Constant(32 - *i))));
+      m.Run(ValueHelper::uint32_vector(),
+            std::bind2nd(std::ptr_fun(&rotr32), *i));
+    }
+    {
+      RawMachineAssemblerTester<int32_t> m(kMachineWord32);
+      Node* value = m.Parameter(0);
+      m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - *i)),
+                          m.Word32Shr(value, m.Int32Constant(*i))));
+      m.Run(ValueHelper::uint32_vector(),
+            std::bind2nd(std::ptr_fun(&rotr32), *i));
+    }
+  }
+}


 TEST(RunSpillLotsOfThings) {
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/value-helper.h Wed Jul 30 14:40:57 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/value-helper.h Thu Jul 31 07:44:29 2014 UTC
@@ -104,6 +104,13 @@
                                     V8_INFINITY * 0.0,  nan};
     return std::vector<double>(&values[0], &values[ARRAY_SIZE(values)]);
   }
+
+  static const std::vector<uint32_t> ror_vector() {
+    static const uint32_t kValues[31] = {
+        1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+ return std::vector<uint32_t>(&kValues[0], &kValues[ARRAY_SIZE(kValues)]);
+  }
 };

 // Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... }
@@ -116,8 +123,9 @@
 #define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
 #define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
 #define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8

 #endif  // V8_CCTEST_COMPILER_VALUE_HELPER_H_

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to