[turbofan] Introduce WordRor machine operator.

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
This commit is contained in:
bmeurer@chromium.org 2014-08-14 09:07:58 +00:00
parent d9e671b5e4
commit ae7d781d8b
26 changed files with 384 additions and 113 deletions

View File

@ -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",

29
src/base/bits.h Normal file
View File

@ -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_

View 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);

View 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));

View File

@ -46,6 +46,8 @@ namespace compiler {
V(Arm64Shr32) \
V(Arm64Sar) \
V(Arm64Sar32) \
V(Arm64Ror) \
V(Arm64Ror32) \
V(Arm64CallCodeObject) \
V(Arm64CallJSFunction) \
V(Arm64CallAddress) \

View 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);
}

View 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));

View File

@ -27,6 +27,7 @@ namespace compiler {
V(IA32Shl) \
V(IA32Shr) \
V(IA32Sar) \
V(IA32Ror) \
V(IA32Push) \
V(IA32CallCodeObject) \
V(IA32CallAddress) \

View 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);
}

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

View 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);

View 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

View 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); }

View File

@ -165,6 +165,7 @@
V(Word32Shl) \
V(Word32Shr) \
V(Word32Sar) \
V(Word32Ror) \
V(Word32Equal) \
V(Word64And) \
V(Word64Or) \
@ -172,6 +173,7 @@
V(Word64Shl) \
V(Word64Shr) \
V(Word64Sar) \
V(Word64Ror) \
V(Word64Equal) \
V(Int32Add) \
V(Int32AddWithOverflow) \

View 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) {

View File

@ -42,6 +42,8 @@ namespace compiler {
V(X64Shr32) \
V(X64Sar) \
V(X64Sar32) \
V(X64Ror) \
V(X64Ror32) \
V(X64Push) \
V(X64PushI) \
V(X64CallCodeObject) \

View 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);
}

View File

@ -5,4 +5,5 @@ include_rules = [
"-src",
"+src/base",
"+testing/gtest",
"+testing/gtest-support.h",
]

View File

@ -20,6 +20,7 @@
'../..',
],
'sources': [ ### gcmole(all) ###
'bits-unittest.cc',
'cpu-unittest.cc',
'platform/condition-variable-unittest.cc',
'platform/mutex-unittest.cc',

View File

@ -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

View 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;

View 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',
],

View File

@ -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

View 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)

View 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,

View File

@ -1085,6 +1085,7 @@
'../../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',