[turbofan] Introduce WordRor machine operator.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Aug 2014 09:07:58 +0000 (09:07 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Aug 2014 09:07:58 +0000 (09:07 +0000)
Move recognition of rotate-right operations to the
MachineOperatorReducer, so we don't need to repeat that in the
InstructionSelector for every backend.

TEST=base-unittests,compiler-unittests,cctests
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/469213002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23121 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

26 files changed:
BUILD.gn
src/base/bits.h [new file with mode: 0644]
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/ia32/code-generator-ia32.cc
src/compiler/ia32/instruction-codes-ia32.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.cc
src/compiler/machine-node-factory.h
src/compiler/machine-operator-reducer.cc
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
test/base-unittests/DEPS
test/base-unittests/base-unittests.gyp
test/base-unittests/bits-unittest.cc [new file with mode: 0644]
test/cctest/compiler/test-run-machops.cc
test/compiler-unittests/compiler-unittests.gyp
test/compiler-unittests/machine-operator-reducer-unittest.cc [new file with mode: 0644]
test/compiler-unittests/node-matchers.cc
test/compiler-unittests/node-matchers.h
tools/gyp/v8.gyp

index efa4b717c9a13ba1f3aa3097386a977e9a43c116..2c924f6ee80692e759c769917c5475fdd38f2441 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1089,6 +1089,7 @@ source_set("v8_libbase") {
     "src/base/atomicops_internals_x86_gcc.cc",
     "src/base/atomicops_internals_x86_gcc.h",
     "src/base/atomicops_internals_x86_msvc.h",
+    "src/base/bits.h",
     "src/base/build_config.h",
     "src/base/cpu.cc",
     "src/base/cpu.h",
diff --git a/src/base/bits.h b/src/base/bits.h
new file mode 100644 (file)
index 0000000..e16eed1
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_BASE_BITS_H_
+#define V8_BASE_BITS_H_
+
+#include "include/v8stdint.h"
+
+namespace v8 {
+namespace base {
+namespace bits {
+
+inline uint32_t RotateRight32(uint32_t value, uint32_t shift) {
+  if (shift == 0) return value;
+  return (value >> shift) | (value << (32 - shift));
+}
+
+
+inline uint64_t RotateRight64(uint64_t value, uint64_t shift) {
+  if (shift == 0) return value;
+  return (value >> shift) | (value << (64 - shift));
+}
+
+}  // namespace bits
+}  // namespace base
+}  // namespace v8
+
+#endif  // V8_BASE_BITS_H_
index 22af55faeec9a6e04045d8999c15bec9ef8716f5..a1f9d4eb39f9b5d2a017210e9d96c5df3147a3a5 100644 (file)
@@ -126,48 +126,17 @@ static bool TryMatchROR(InstructionSelector* selector,
                         InstructionOperand** value_return,
                         InstructionOperand** shift_return) {
   ArmOperandGenerator g(selector);
-  if (node->opcode() != IrOpcode::kWord32Or) return false;
+  if (node->opcode() != IrOpcode::kWord32Ror) 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)) {
-    if (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) && mshlright.right().Is(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;
+  *value_return = g.UseRegister(m.left().node());
+  if (m.right().IsInRange(1, 31)) {
+    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
+    *shift_return = g.UseImmediate(m.right().node());
+  } else {
     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R);
-    *value_return = g.UseRegister(value);
-    *shift_return = g.UseRegister(shift);
-    return true;
+    *shift_return = g.UseRegister(m.right().node());
   }
-  return false;
+  return true;
 }
 
 
@@ -482,14 +451,6 @@ 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);
 }
 
@@ -562,6 +523,11 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitShift(this, node, TryMatchROR);
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   ArmOperandGenerator g(this);
   Int32BinopMatcher m(node);
index 43b1c7e91b2edcafee1b20aad083877635f87640..f21462e27f03ae3456c0c27441bfe597e7a628a6 100644 (file)
@@ -268,6 +268,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Sar32:
       ASSEMBLE_SHIFT(Asr, 32);
       break;
+    case kArm64Ror:
+      ASSEMBLE_SHIFT(Ror, 64);
+      break;
+    case kArm64Ror32:
+      ASSEMBLE_SHIFT(Ror, 32);
+      break;
     case kArm64CallCodeObject: {
       if (instr->InputAt(0)->IsImmediate()) {
         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
index 2d71c02ef03a02a7ae72ae0339e8c9d251389281..c13c4d429541a557fd4e7eb5fde609fd36540a6a 100644 (file)
@@ -46,6 +46,8 @@ namespace compiler {
   V(Arm64Shr32)                    \
   V(Arm64Sar)                      \
   V(Arm64Sar32)                    \
+  V(Arm64Ror)                      \
+  V(Arm64Ror32)                    \
   V(Arm64CallCodeObject)           \
   V(Arm64CallJSFunction)           \
   V(Arm64CallAddress)              \
index 111ca2d956a17e846b64006756e01d41825d6c66..0d7dbb669aefe070fac65d189fc8b44388d13fc5 100644 (file)
@@ -329,6 +329,16 @@ void InstructionSelector::VisitWord64Sar(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitRRO(this, kArm64Ror32, node, kShift32Imm);
+}
+
+
+void InstructionSelector::VisitWord64Ror(Node* node) {
+  VisitRRO(this, kArm64Ror, node, kShift64Imm);
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   VisitBinop(this, node, kArm64Add32, kArithimeticImm);
 }
index 9fef740810180eaf6dfa10d39c7cf9110525b56a..ad80e49e00fa651e900d03cbccc787c7f48e5cc7 100644 (file)
@@ -220,6 +220,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ sar_cl(i.OutputRegister());
       }
       break;
+    case kIA32Ror:
+      if (HasImmediateInput(instr, 1)) {
+        __ ror(i.OutputRegister(), i.InputInt5(1));
+      } else {
+        __ ror_cl(i.OutputRegister());
+      }
+      break;
     case kIA32Push:
       if (HasImmediateInput(instr, 0)) {
         __ push(i.InputImmediate(0));
index f175ebb559b4a9196fd9d3d677a2e9607980c90f..0b0944e4cda616c1a1908926e77ab5752636e2d0 100644 (file)
@@ -27,6 +27,7 @@ namespace compiler {
   V(IA32Shl)                       \
   V(IA32Shr)                       \
   V(IA32Sar)                       \
+  V(IA32Ror)                       \
   V(IA32Push)                      \
   V(IA32CallCodeObject)            \
   V(IA32CallAddress)               \
index a057a1e713675f1d417595b6bc80537a06f96b56..1e22aa638a8794765fed5ba1a4ca5647168faf7c 100644 (file)
@@ -271,6 +271,11 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitShift(this, node, kIA32Ror);
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   VisitBinop(this, node, kIA32Add);
 }
index 541e0452fa943273eb152769329863d4257ce614..35a7e5c3b6569449b273a58aee7a3e01b2dcb58d 100644 (file)
@@ -511,6 +511,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitWord32Shr(node);
     case IrOpcode::kWord32Sar:
       return VisitWord32Sar(node);
+    case IrOpcode::kWord32Ror:
+      return VisitWord32Ror(node);
     case IrOpcode::kWord32Equal:
       return VisitWord32Equal(node);
     case IrOpcode::kWord64And:
@@ -525,6 +527,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitWord64Shr(node);
     case IrOpcode::kWord64Sar:
       return VisitWord64Sar(node);
+    case IrOpcode::kWord64Ror:
+      return VisitWord64Ror(node);
     case IrOpcode::kWord64Equal:
       return VisitWord64Equal(node);
     case IrOpcode::kInt32Add:
@@ -724,6 +728,9 @@ void InstructionSelector::VisitWord64Shr(Node* node) { UNIMPLEMENTED(); }
 void InstructionSelector::VisitWord64Sar(Node* node) { UNIMPLEMENTED(); }
 
 
+void InstructionSelector::VisitWord64Ror(Node* node) { UNIMPLEMENTED(); }
+
+
 void InstructionSelector::VisitInt64Add(Node* node) { UNIMPLEMENTED(); }
 
 
index 721b1ff75dd2d283778030d5e72c170293e41daa..cc9d5d903596c472feb0841c756f224817f4600d 100644 (file)
@@ -119,11 +119,7 @@ class MachineNodeFactory {
     return NEW_NODE_2(MACHINE()->WordSar(), a, b);
   }
   Node* WordRor(Node* a, Node* b) {
-    if (MACHINE()->is32()) {
-      return Word32Ror(a, b);
-    } else {
-      return Word64Ror(a, b);
-    }
+    return NEW_NODE_2(MACHINE()->WordRor(), a, b);
   }
   Node* WordEqual(Node* a, Node* b) {
     return NEW_NODE_2(MACHINE()->WordEqual(), a, b);
@@ -165,8 +161,7 @@ class MachineNodeFactory {
     return NEW_NODE_2(MACHINE()->Word32Sar(), a, b);
   }
   Node* Word32Ror(Node* a, Node* b) {
-    return Word32Or(Word32Shl(a, Int32Sub(Int32Constant(32), b)),
-                    Word32Shr(a, b));
+    return NEW_NODE_2(MACHINE()->Word32Ror(), a, b);
   }
   Node* Word32Equal(Node* a, Node* b) {
     return NEW_NODE_2(MACHINE()->Word32Equal(), a, b);
@@ -196,8 +191,7 @@ class MachineNodeFactory {
     return NEW_NODE_2(MACHINE()->Word64Sar(), a, b);
   }
   Node* Word64Ror(Node* a, Node* b) {
-    return Word64Or(Word64Shl(a, Int64Sub(Int64Constant(64), b)),
-                    Word64Shr(a, b));
+    return NEW_NODE_2(MACHINE()->Word64Ror(), a, b);
   }
   Node* Word64Equal(Node* a, Node* b) {
     return NEW_NODE_2(MACHINE()->Word64Equal(), a, b);
index 4a4057646dde8bc0f60c8866207f52512ea06387..8466cbbf47537f22b8b750fb5ea8dd38b41962d8 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/compiler/machine-operator-reducer.h"
 
+#include "src/base/bits.h"
 #include "src/compiler/common-node-cache.h"
 #include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
@@ -67,6 +68,56 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
         return ReplaceInt32(m.left().Value() | m.right().Value());
       }
       if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
+      if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
+        Int32BinopMatcher mleft(m.left().node());
+        Int32BinopMatcher mright(m.right().node());
+        if (mleft.left().node() == mright.left().node()) {
+          // (x << y) | (x >> (32 - y)) => x ror y
+          if (mright.right().IsInt32Sub()) {
+            Int32BinopMatcher mrightright(mright.right().node());
+            if (mrightright.left().Is(32) &&
+                mrightright.right().node() == mleft.right().node()) {
+              graph_->ChangeOperator(node, machine_.Word32Ror());
+              node->ReplaceInput(0, mleft.left().node());
+              node->ReplaceInput(1, mleft.right().node());
+              return Changed(node);
+            }
+          }
+          // (x << K) | (x >> (32 - K)) => x ror K
+          if (mleft.right().IsInRange(0, 31) &&
+              mright.right().Is(32 - mleft.right().Value())) {
+            graph_->ChangeOperator(node, machine_.Word32Ror());
+            node->ReplaceInput(0, mleft.left().node());
+            node->ReplaceInput(1, mleft.right().node());
+            return Changed(node);
+          }
+        }
+      }
+      if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
+        // (x >> (32 - y)) | (x << y)  => x ror y
+        Int32BinopMatcher mleft(m.left().node());
+        Int32BinopMatcher mright(m.right().node());
+        if (mleft.left().node() == mright.left().node()) {
+          if (mleft.right().IsInt32Sub()) {
+            Int32BinopMatcher mleftright(mleft.right().node());
+            if (mleftright.left().Is(32) &&
+                mleftright.right().node() == mright.right().node()) {
+              graph_->ChangeOperator(node, machine_.Word32Ror());
+              node->ReplaceInput(0, mright.left().node());
+              node->ReplaceInput(1, mright.right().node());
+              return Changed(node);
+            }
+          }
+          // (x >> (32 - K)) | (x << K) => x ror K
+          if (mright.right().IsInRange(0, 31) &&
+              mleft.right().Is(32 - mright.right().Value())) {
+            graph_->ChangeOperator(node, machine_.Word32Ror());
+            node->ReplaceInput(0, mright.left().node());
+            node->ReplaceInput(1, mright.right().node());
+            return Changed(node);
+          }
+        }
+      }
       break;
     }
     case IrOpcode::kWord32Xor: {
@@ -102,6 +153,15 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       }
       break;
     }
+    case IrOpcode::kWord32Ror: {
+      Int32BinopMatcher m(node);
+      if (m.right().Is(0)) return Replace(m.left().node());  // x ror 0 => x
+      if (m.IsFoldable()) {                                  // K ror K => K
+        return ReplaceInt32(
+            base::bits::RotateRight32(m.left().Value(), m.right().Value()));
+      }
+      break;
+    }
     case IrOpcode::kWord32Equal: {
       Int32BinopMatcher m(node);
       if (m.IsFoldable()) {  // K == K => K
index 93ccedc2c80401c0d106d044a67b236ff6506a96..25bbf2955bab792dd56d040cd62036f063ea8b42 100644 (file)
@@ -76,6 +76,7 @@ class MachineOperatorBuilder {
   Operator* WordShl() { WORD_SIZE(Shl); }
   Operator* WordShr() { WORD_SIZE(Shr); }
   Operator* WordSar() { WORD_SIZE(Sar); }
+  Operator* WordRor() { WORD_SIZE(Ror); }
   Operator* WordEqual() { WORD_SIZE(Equal); }
 
   Operator* Word32And() { BINOP_AC(Word32And); }
@@ -84,6 +85,7 @@ class MachineOperatorBuilder {
   Operator* Word32Shl() { BINOP(Word32Shl); }
   Operator* Word32Shr() { BINOP(Word32Shr); }
   Operator* Word32Sar() { BINOP(Word32Sar); }
+  Operator* Word32Ror() { BINOP(Word32Ror); }
   Operator* Word32Equal() { BINOP_C(Word32Equal); }
 
   Operator* Word64And() { BINOP_AC(Word64And); }
@@ -92,6 +94,7 @@ class MachineOperatorBuilder {
   Operator* Word64Shl() { BINOP(Word64Shl); }
   Operator* Word64Shr() { BINOP(Word64Shr); }
   Operator* Word64Sar() { BINOP(Word64Sar); }
+  Operator* Word64Ror() { BINOP(Word64Ror); }
   Operator* Word64Equal() { BINOP_C(Word64Equal); }
 
   Operator* Int32Add() { BINOP_AC(Int32Add); }
index 1371bfd16bd6988e24db1af87e40cc5915161974..df150592f776f89bc841c4c2aa0f1de456287a19 100644 (file)
   V(Word32Shl)             \
   V(Word32Shr)             \
   V(Word32Sar)             \
+  V(Word32Ror)             \
   V(Word32Equal)           \
   V(Word64And)             \
   V(Word64Or)              \
   V(Word64Shl)             \
   V(Word64Shr)             \
   V(Word64Sar)             \
+  V(Word64Ror)             \
   V(Word64Equal)           \
   V(Int32Add)              \
   V(Int32AddWithOverflow)  \
index f407fa5387cc0e47fed1dc2409004024eee8ac76..c501b5cd20adba6ae28200f19d20e628592d29c8 100644 (file)
@@ -370,6 +370,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kX64Sar:
       ASSEMBLE_SHIFT(sarq, 6);
       break;
+    case kX64Ror32:
+      ASSEMBLE_SHIFT(rorl, 5);
+      break;
+    case kX64Ror:
+      ASSEMBLE_SHIFT(rorq, 6);
+      break;
     case kX64Push: {
       RegisterOrOperand input = i.InputRegisterOrOperand(0);
       if (input.type == kRegister) {
index 8ba33ab10d1013330eb6210bd7d6cf3acea143f5..10d9ad0dcb07c9ff942bebbf8258ae4ef5987ab5 100644 (file)
@@ -42,6 +42,8 @@ namespace compiler {
   V(X64Shr32)                      \
   V(X64Sar)                        \
   V(X64Sar32)                      \
+  V(X64Ror)                        \
+  V(X64Ror32)                      \
   V(X64Push)                       \
   V(X64PushI)                      \
   V(X64CallCodeObject)             \
index 965e612e2d636d5dac56509db67744442e7c4603..5f185b13d8b137fdb3481ab1dafa7fa05783825b 100644 (file)
@@ -348,6 +348,16 @@ void InstructionSelector::VisitWord64Sar(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitWord32Shift(this, node, kX64Ror32);
+}
+
+
+void InstructionSelector::VisitWord64Ror(Node* node) {
+  VisitWord64Shift(this, node, kX64Ror);
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   VisitBinop(this, node, kX64Add32);
 }
index 90b080063f6c8ad0f1c0f1f8314fd35843c1f364..5c0cadf9f1ccaf25cff4eba6e8344b215082fca6 100644 (file)
@@ -5,4 +5,5 @@ include_rules = [
   "-src",
   "+src/base",
   "+testing/gtest",
+  "+testing/gtest-support.h",
 ]
index 339269db1bc798f96eddd5f29d0ef7ebd5a6b253..2a2321f64a04ab70618528fa279b74261e1492ac 100644 (file)
@@ -20,6 +20,7 @@
         '../..',
       ],
       'sources': [  ### gcmole(all) ###
+        'bits-unittest.cc',
         'cpu-unittest.cc',
         'platform/condition-variable-unittest.cc',
         'platform/mutex-unittest.cc',
diff --git a/test/base-unittests/bits-unittest.cc b/test/base-unittests/bits-unittest.cc
new file mode 100644 (file)
index 0000000..689fb41
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/base/macros.h"
+#include "testing/gtest-support.h"
+
+namespace v8 {
+namespace base {
+namespace bits {
+
+TEST(BitsTest, RotateRight32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(0u, RotateRight32(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight32(1, 0));
+  EXPECT_EQ(1u, RotateRight32(2, 1));
+  EXPECT_EQ(0x80000000u, RotateRight32(1, 1));
+}
+
+
+TEST(BitsTest, RotateRight64) {
+  TRACED_FORRANGE(uint64_t, shift, 0, 63) {
+    EXPECT_EQ(0u, RotateRight64(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight64(1, 0));
+  EXPECT_EQ(1u, RotateRight64(2, 1));
+  EXPECT_EQ(V8_UINT64_C(0x8000000000000000), RotateRight64(1, 1));
+}
+
+}  // namespace bits
+}  // namespace base
+}  // namespace v8
index edac9750434a484017d3920b16cfe2fa0757b562..fdda63a1c36dd61496e54f0d3cfe885bc5dffffe 100644 (file)
@@ -5,12 +5,14 @@
 #include <functional>
 #include <limits>
 
+#include "src/base/bits.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
 #include "test/cctest/compiler/value-helper.h"
 
 #if V8_TURBOFAN_TARGET
 
+using namespace v8::base;
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
@@ -2282,6 +2284,31 @@ TEST(RunWord32SarP) {
 }
 
 
+TEST(RunWord32RorP) {
+  {
+    FOR_UINT32_SHIFTS(shift) {
+      RawMachineAssemblerTester<int32_t> m(kMachineWord32);
+      m.Return(m.Word32Ror(m.Parameter(0), m.Int32Constant(shift)));
+      FOR_UINT32_INPUTS(j) {
+        int32_t expected = bits::RotateRight32(*j, shift);
+        CHECK_EQ(expected, m.Call(*j));
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m;
+    Int32BinopTester bt(&m);
+    bt.AddReturn(m.Word32Ror(bt.param0, bt.param1));
+    FOR_UINT32_INPUTS(i) {
+      FOR_UINT32_SHIFTS(shift) {
+        int32_t expected = bits::RotateRight32(*i, shift);
+        CHECK_EQ(expected, bt.call(*i, shift));
+      }
+    }
+  }
+}
+
+
 TEST(RunWord32NotP) {
   RawMachineAssemblerTester<int32_t> m(kMachineWord32);
   m.Return(m.Word32Not(m.Parameter(0)));
@@ -2439,16 +2466,16 @@ TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
   Operator* ops[] = {
-      m.machine()->Word32And(),      m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
-      m.machine()->Word32Equal(),    m.machine()->Int32Add(),
-      m.machine()->Int32Sub(),       m.machine()->Int32Mul(),
-      m.machine()->Int32Div(),       m.machine()->Int32UDiv(),
-      m.machine()->Int32Mod(),       m.machine()->Int32UMod(),
-      m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
-      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
-      NULL};
+      m.machine()->Word32And(),             m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),             m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),             m.machine()->Word32Sar(),
+      m.machine()->Word32Ror(),             m.machine()->Word32Equal(),
+      m.machine()->Int32Add(),              m.machine()->Int32Sub(),
+      m.machine()->Int32Mul(),              m.machine()->Int32Div(),
+      m.machine()->Int32UDiv(),             m.machine()->Int32Mod(),
+      m.machine()->Int32UMod(),             m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(),  m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual(), NULL};
 
   for (int i = 0; ops[i] != NULL; i++) {
     RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
@@ -3689,53 +3716,6 @@ TEST(RunTestIntPtrArithmetic) {
 }
 
 
-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) {
   static const int kInputSize = 1000;
   RawMachineAssemblerTester<void> m;
index f257e545164a83c050ab32d34b1ee58a164b91d1..f2c4facfda0740b397da44b3101432fe8a24d2e6 100644 (file)
@@ -23,6 +23,7 @@
         'change-lowering-unittest.cc',
         'compiler-unittests.cc',
         'instruction-selector-unittest.cc',
+        'machine-operator-reducer-unittest.cc',
         'node-matchers.cc',
         'node-matchers.h',
       ],
diff --git a/test/compiler-unittests/machine-operator-reducer-unittest.cc b/test/compiler-unittests/machine-operator-reducer-unittest.cc
new file mode 100644 (file)
index 0000000..0edab12
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator-reducer.h"
+#include "test/compiler-unittests/compiler-unittests.h"
+#include "test/compiler-unittests/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MachineOperatorReducerTest : public CompilerTest {
+ public:
+  explicit MachineOperatorReducerTest(int num_parameters = 2)
+      : graph_(zone()), common_(zone()), machine_(zone()) {
+    graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
+  }
+  virtual ~MachineOperatorReducerTest() {}
+
+ protected:
+  Node* Parameter(int32_t index) {
+    return graph()->NewNode(common()->Parameter(index), graph()->start());
+  }
+  Node* Int32Constant(int32_t value) {
+    return graph()->NewNode(common()->Int32Constant(value));
+  }
+
+  Reduction Reduce(Node* node) {
+    MachineOperatorReducer reducer(graph());
+    return reducer.Reduce(node);
+  }
+
+  Graph* graph() { return &graph_; }
+  CommonOperatorBuilder* common() { return &common_; }
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  Graph graph_;
+  CommonOperatorBuilder common_;
+  MachineOperatorBuilder machine_;
+};
+
+
+namespace {
+
+static const uint32_t kConstants[] = {
+    0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+    0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
+    0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
+    0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
+    0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000,
+    0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff,
+    0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
+    0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
+
+}  // namespace
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) {
+  Node* value = Parameter(0);
+  Node* shift = Parameter(1);
+  Node* shl = graph()->NewNode(machine()->Word32Shl(), value, shift);
+  Node* shr = graph()->NewNode(
+      machine()->Word32Shr(), value,
+      graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift));
+
+  // (x << y) | (x >> (32 - y)) => x ror y
+  Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
+  Reduction reduction1 = Reduce(node1);
+  EXPECT_TRUE(reduction1.Changed());
+  EXPECT_EQ(reduction1.replacement(), node1);
+  EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, shift));
+
+  // (x >> (32 - y)) | (x << y) => x ror y
+  Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
+  Reduction reduction2 = Reduce(node2);
+  EXPECT_TRUE(reduction2.Changed());
+  EXPECT_EQ(reduction2.replacement(), node2);
+  EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, shift));
+}
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) {
+  Node* value = Parameter(0);
+  TRACED_FORRANGE(int32_t, k, 0, 31) {
+    Node* shl =
+        graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(k));
+    Node* shr =
+        graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k));
+
+    // (x << K) | (x >> ((32 - K) - y)) => x ror K
+    Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
+    Reduction reduction1 = Reduce(node1);
+    EXPECT_TRUE(reduction1.Changed());
+    EXPECT_EQ(reduction1.replacement(), node1);
+    EXPECT_THAT(reduction1.replacement(),
+                IsWord32Ror(value, IsInt32Constant(k)));
+
+    // (x >> (32 - K)) | (x << K) => x ror K
+    Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
+    Reduction reduction2 = Reduce(node2);
+    EXPECT_TRUE(reduction2.Changed());
+    EXPECT_EQ(reduction2.replacement(), node2);
+    EXPECT_THAT(reduction2.replacement(),
+                IsWord32Ror(value, IsInt32Constant(k)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithZeroShift) {
+  Node* value = Parameter(0);
+  Node* node =
+      graph()->NewNode(machine()->Word32Ror(), value, Int32Constant(0));
+  Reduction reduction = Reduce(node);
+  EXPECT_TRUE(reduction.Changed());
+  EXPECT_EQ(reduction.replacement(), value);
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
+  TRACED_FOREACH(int32_t, x, kConstants) {
+    TRACED_FORRANGE(int32_t, y, 0, 31) {
+      Node* node = graph()->NewNode(machine()->Word32Ror(), Int32Constant(x),
+                                    Int32Constant(y));
+      Reduction reduction = Reduce(node);
+      EXPECT_TRUE(reduction.Changed());
+      EXPECT_THAT(reduction.replacement(),
+                  IsInt32Constant(base::bits::RotateRight32(x, y)));
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index d580834113d3a987c661b0c0aa9247a6ba75e241..5d8fba99b267a57b66bbf64b68b067d446866e5f 100644 (file)
@@ -432,6 +432,7 @@ Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
   }
 IS_BINOP_MATCHER(Word32And)
 IS_BINOP_MATCHER(Word32Sar)
+IS_BINOP_MATCHER(Word32Ror)
 IS_BINOP_MATCHER(Word32Equal)
 IS_BINOP_MATCHER(Word64And)
 IS_BINOP_MATCHER(Word64Sar)
index 09da07a7f5845aca4caba1f0750d43e25cdd1be6..f51e3af5205526cb09fd4b4daa33ccb30a0cbba7 100644 (file)
@@ -49,6 +49,8 @@ Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
                              const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
index d907725230cf7869105252f4652f01f16e5b9274..492aee83042fdc346aa0de113e064a9dfa293210 100644 (file)
         '../../src/base/atomicops_internals_x86_gcc.cc',
         '../../src/base/atomicops_internals_x86_gcc.h',
         '../../src/base/atomicops_internals_x86_msvc.h',
+        '../../src/base/bits.h',
         '../../src/base/build_config.h',
         '../../src/base/cpu.cc',
         '../../src/base/cpu.h',