Commit 0eecf982 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[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
R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22732 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ec91e4ef
......@@ -79,6 +79,10 @@ class ArmOperandConverter : public InstructionOperandConverter {
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 @@ class ArmOperandConverter : public InstructionOperandConverter {
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;
......
......@@ -73,9 +73,11 @@ namespace compiler {
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
......
......@@ -121,75 +121,122 @@ static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
}
static Instruction* EmitBinop(InstructionSelector* selector,
InstructionCode opcode, size_t output_count,
InstructionOperand** outputs, Node* left,
Node* right, size_t label_count,
InstructionOperand** labels) {
static bool TryMatchROR(InstructionSelector* selector,
InstructionCode* opcode_return, Node* node,
InstructionOperand** value_return,
InstructionOperand** shift_return) {
ArmOperandGenerator g(selector);
InstructionOperand* inputs[5];
size_t input_count = 0;
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());
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_LSR_R);
inputs[input_count++] = g.UseRegister(mright.right().node());
*opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R);
*shift_return = g.UseRegister(m.right().node());
}
return true;
}
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 |= AddressingModeField::encode(kMode_Operand2_R);
inputs[input_count++] = g.UseRegister(right);
*opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R);
*shift_return = g.UseRegister(m.right().node());
}
return true;
}
// Append the optional labels.
while (label_count-- != 0) {
inputs[input_count++] = *labels++;
}
ASSERT_NE(0, input_count);
ASSERT_GE(ARRAY_SIZE(inputs), input_count);
ASSERT_NE(kMode_None, AddressingModeField::decode(opcode));
return selector->Emit(opcode, output_count, outputs, input_count, inputs);
static inline bool TryMatchLSR(InstructionSelector* selector,
InstructionCode* opcode_return, Node* node,
InstructionOperand** value_return,
InstructionOperand** shift_return) {
ArmOperandGenerator g(selector);
if (node->opcode() != IrOpcode::kWord32Shr) return false;
Int32BinopMatcher m(node);
*value_return = g.UseRegister(m.left().node());
if (m.right().IsInRange(1, 32)) {
*opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
*shift_return = g.UseImmediate(m.right().node());
} else {
*opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R);
*shift_return = g.UseRegister(m.right().node());
}
return true;
}
static Instruction* EmitBinop(InstructionSelector* selector,
InstructionCode opcode, Node* node, Node* left,
Node* right) {
static inline bool TryMatchImmediateOrShift(InstructionSelector* selector,
InstructionCode* opcode_return,
Node* node,
size_t* input_count_return,
InstructionOperand** inputs) {
ArmOperandGenerator g(selector);
InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
const size_t output_count = ARRAY_SIZE(outputs);
return EmitBinop(selector, opcode, output_count, outputs, left, right, 0,
NULL);
if (g.CanBeImmediate(node, *opcode_return)) {
*opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
inputs[0] = g.UseImmediate(node);
*input_count_return = 1;
return true;
}
if (TryMatchASR(selector, opcode_return, node, &inputs[0], &inputs[1]) ||
TryMatchLSL(selector, opcode_return, node, &inputs[0], &inputs[1]) ||
TryMatchLSR(selector, opcode_return, node, &inputs[0], &inputs[1]) ||
TryMatchROR(selector, opcode_return, node, &inputs[0], &inputs[1])) {
*input_count_return = 2;
return true;
}
return false;
}
......@@ -198,17 +245,32 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, InstructionCode reverse_opcode) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand* inputs[3];
size_t input_count = 0;
Node* left = m.left().node();
Node* right = m.right().node();
if (g.CanBeImmediate(m.left().node(), reverse_opcode) ||
m.left().IsWord32Sar() || m.left().IsWord32Shl() ||
m.left().IsWord32Shr()) {
if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
&input_count, &inputs[1])) {
inputs[0] = g.UseRegister(m.left().node());
input_count++;
} else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
m.left().node(), &input_count,
&inputs[1])) {
inputs[0] = g.UseRegister(m.right().node());
opcode = reverse_opcode;
std::swap(left, right);
input_count++;
} else {
opcode |= AddressingModeField::encode(kMode_Operand2_R);
inputs[input_count++] = g.UseRegister(m.left().node());
inputs[input_count++] = g.UseRegister(m.right().node());
}
EmitBinop(selector, opcode, node, left, right);
ASSERT_NE(0, input_count);
ASSERT_GE(ARRAY_SIZE(inputs), input_count);
ASSERT_NE(kMode_None, AddressingModeField::decode(opcode));
InstructionOperand* outputs[1] = {g.DefineAsRegister(node)};
const size_t output_count = ARRAY_SIZE(outputs);
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
......@@ -311,20 +373,44 @@ void InstructionSelector::VisitStore(Node* node) {
}
static inline void EmitBic(InstructionSelector* selector, Node* node,
Node* left, Node* right) {
ArmOperandGenerator g(selector);
InstructionCode opcode = kArmBic;
InstructionOperand* inputs[3];
size_t input_count = 0;
InstructionOperand* outputs[1] = {g.DefineAsRegister(node)};
const size_t output_count = ARRAY_SIZE(outputs);
inputs[input_count++] = g.UseRegister(left);
if (!TryMatchImmediateOrShift(selector, &opcode, right, &input_count,
&inputs[input_count])) {
opcode |= AddressingModeField::encode(kMode_Operand2_R);
inputs[input_count++] = g.UseRegister(right);
}
ASSERT_NE(0, input_count);
ASSERT_GE(ARRAY_SIZE(inputs), input_count);
ASSERT_NE(kMode_None, AddressingModeField::decode(opcode));
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
void InstructionSelector::VisitWord32And(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().Is(-1)) {
EmitBinop(this, kArmBic, node, m.right().node(), mleft.left().node());
EmitBic(this, node, m.right().node(), mleft.left().node());
return;
}
}
if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
Int32BinopMatcher mright(m.right().node());
if (mright.right().Is(-1)) {
EmitBinop(this, kArmBic, node, m.left().node(), mright.left().node());
EmitBic(this, node, m.left().node(), mright.left().node());
return;
}
}
......@@ -362,6 +448,14 @@ void InstructionSelector::VisitWord32And(Node* node) {
void InstructionSelector::VisitWord32Or(Node* node) {
ArmOperandGenerator g(this);
InstructionCode opcode = kArmMov;
InstructionOperand* value_operand;
InstructionOperand* shift_operand;
if (TryMatchROR(this, &opcode, node, &value_operand, &shift_operand)) {
Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
return;
}
VisitBinop(this, node, kArmOrr, kArmOrr);
}
......@@ -378,18 +472,22 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
}
template <typename TryMatchShift>
static inline void VisitShift(InstructionSelector* selector, Node* node,
TryMatchShift try_match_shift) {
ArmOperandGenerator g(selector);
InstructionCode opcode = kArmMov;
InstructionOperand* value_operand = NULL;
InstructionOperand* shift_operand = NULL;
CHECK(
try_match_shift(selector, &opcode, node, &value_operand, &shift_operand));
selector->Emit(opcode, g.DefineAsRegister(node), value_operand,
shift_operand);
}
void InstructionSelector::VisitWord32Shl(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.right().IsInRange(0, 31)) {
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()));
} else {
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_R),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
VisitShift(this, node, TryMatchLSL);
}
......@@ -413,30 +511,12 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
}
}
}
if (m.right().IsInRange(1, 32)) {
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()));
return;
}
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_R),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
VisitShift(this, node, TryMatchLSR);
}
void InstructionSelector::VisitWord32Sar(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.right().IsInRange(1, 32)) {
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()));
} else {
Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_R),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
VisitShift(this, node, TryMatchASR);
}
......@@ -711,31 +791,44 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
bool commutative, bool requires_output) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
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();
}
......
......@@ -101,6 +101,25 @@ class RawMachineAssemblerTester
: 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));
}
}
}
};
......@@ -163,6 +182,17 @@ class BinopTester {
}
}
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;
CType p1;
......
......@@ -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;
......@@ -130,6 +131,66 @@ TEST(InstructionSelectorDPIAndShiftP) {
}
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) {
DPIs dpis;
Shifts shifts;
......@@ -224,6 +285,100 @@ TEST(InstructionSelectorWord32XorWithMinus1P) {
}
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) {
InstructionSelectorTester m;
m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
......@@ -919,6 +1074,185 @@ TEST(InstructionSelectorBranchWithWord32EqualAndShiftImm) {
}
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) {
DPIs dpis;
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
......
......@@ -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"
......@@ -3680,6 +3680,53 @@ 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;
......
......@@ -104,6 +104,13 @@ class ValueHelper {
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 @@ class ValueHelper {
#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_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment