"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",
--- /dev/null
+// 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_
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;
}
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);
}
}
+void InstructionSelector::VisitWord32Ror(Node* node) {
+ VisitShift(this, node, TryMatchROR);
+}
+
+
void InstructionSelector::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
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));
V(Arm64Shr32) \
V(Arm64Sar) \
V(Arm64Sar32) \
+ V(Arm64Ror) \
+ V(Arm64Ror32) \
V(Arm64CallCodeObject) \
V(Arm64CallJSFunction) \
V(Arm64CallAddress) \
}
+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);
}
__ 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));
V(IA32Shl) \
V(IA32Shr) \
V(IA32Sar) \
+ V(IA32Ror) \
V(IA32Push) \
V(IA32CallCodeObject) \
V(IA32CallAddress) \
}
+void InstructionSelector::VisitWord32Ror(Node* node) {
+ VisitShift(this, node, kIA32Ror);
+}
+
+
void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop(this, node, kIA32Add);
}
return VisitWord32Shr(node);
case IrOpcode::kWord32Sar:
return VisitWord32Sar(node);
+ case IrOpcode::kWord32Ror:
+ return VisitWord32Ror(node);
case IrOpcode::kWord32Equal:
return VisitWord32Equal(node);
case IrOpcode::kWord64And:
return VisitWord64Shr(node);
case IrOpcode::kWord64Sar:
return VisitWord64Sar(node);
+ case IrOpcode::kWord64Ror:
+ return VisitWord64Ror(node);
case IrOpcode::kWord64Equal:
return VisitWord64Equal(node);
case IrOpcode::kInt32Add:
void InstructionSelector::VisitWord64Sar(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitWord64Ror(Node* node) { UNIMPLEMENTED(); }
+
+
void InstructionSelector::VisitInt64Add(Node* node) { UNIMPLEMENTED(); }
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);
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);
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);
#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"
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: {
}
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
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); }
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); }
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); }
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) \
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) {
V(X64Shr32) \
V(X64Sar) \
V(X64Sar32) \
+ V(X64Ror) \
+ V(X64Ror32) \
V(X64Push) \
V(X64PushI) \
V(X64CallCodeObject) \
}
+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);
}
"-src",
"+src/base",
"+testing/gtest",
+ "+testing/gtest-support.h",
]
'../..',
],
'sources': [ ### gcmole(all) ###
+ 'bits-unittest.cc',
'cpu-unittest.cc',
'platform/condition-variable-unittest.cc',
'platform/mutex-unittest.cc',
--- /dev/null
+// 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
#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;
}
+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)));
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);
}
-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;
'change-lowering-unittest.cc',
'compiler-unittests.cc',
'instruction-selector-unittest.cc',
+ 'machine-operator-reducer-unittest.cc',
'node-matchers.cc',
'node-matchers.h',
],
--- /dev/null
+// 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
}
IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Sar)
+IS_BINOP_MATCHER(Word32Ror)
IS_BINOP_MATCHER(Word32Equal)
IS_BINOP_MATCHER(Word64And)
IS_BINOP_MATCHER(Word64Sar)
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,
'../../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',