diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc index 781252b75a..956fbbde8c 100644 --- a/src/compiler/arm/code-generator-arm.cc +++ b/src/compiler/arm/code-generator-arm.cc @@ -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; diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h index b222bb369b..1d5b5c7f33 100644 --- a/src/compiler/arm/instruction-codes-arm.h +++ b/src/compiler/arm/instruction-codes-arm.h @@ -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 diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index 95e3333669..03b0565487 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -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; - - inputs[input_count++] = g.UseRegister(left); - if (g.CanBeImmediate(right, opcode)) { - opcode |= AddressingModeField::encode(kMode_Operand2_I); - inputs[input_count++] = g.UseImmediate(right); - } else if (right->opcode() == IrOpcode::kWord32Sar) { - Int32BinopMatcher mright(right); - inputs[input_count++] = g.UseRegister(mright.left().node()); - if (mright.right().IsInRange(1, 32)) { - opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); - inputs[input_count++] = g.UseImmediate(mright.right().node()); - } else { - opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); - inputs[input_count++] = g.UseRegister(mright.right().node()); - } - } else if (right->opcode() == IrOpcode::kWord32Shl) { - Int32BinopMatcher mright(right); - inputs[input_count++] = g.UseRegister(mright.left().node()); - if (mright.right().IsInRange(0, 31)) { - opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); - inputs[input_count++] = g.UseImmediate(mright.right().node()); - } else { - opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); - inputs[input_count++] = g.UseRegister(mright.right().node()); - } - } else if (right->opcode() == IrOpcode::kWord32Shr) { - Int32BinopMatcher mright(right); - inputs[input_count++] = g.UseRegister(mright.left().node()); - if (mright.right().IsInRange(1, 32)) { - opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); - inputs[input_count++] = g.UseImmediate(mright.right().node()); - } else { - opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); - inputs[input_count++] = g.UseRegister(mright.right().node()); - } - } else { - opcode |= AddressingModeField::encode(kMode_Operand2_R); - inputs[input_count++] = g.UseRegister(right); + 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; } - - // Append the optional labels. - while (label_count-- != 0) { - inputs[input_count++] = *labels++; + 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; } - - 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); + 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; } -static Instruction* EmitBinop(InstructionSelector* selector, - InstructionCode opcode, Node* node, Node* left, - Node* right) { +static inline bool TryMatchASR(InstructionSelector* selector, + InstructionCode* opcode_return, Node* node, + InstructionOperand** value_return, + InstructionOperand** shift_return) { 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 (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_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_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); + *shift_return = g.UseRegister(m.right().node()); + } + return true; +} + + +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 inline bool TryMatchImmediateOrShift(InstructionSelector* selector, + InstructionCode* opcode_return, + Node* node, + size_t* input_count_return, + InstructionOperand** inputs) { + ArmOperandGenerator g(selector); + 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 +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(); } diff --git a/test/cctest/compiler/codegen-tester.h b/test/cctest/compiler/codegen-tester.h index 42c8fcd166..0fd3040b68 100644 --- a/test/cctest/compiler/codegen-tester.h +++ b/test/cctest/compiler/codegen-tester.h @@ -101,6 +101,25 @@ class RawMachineAssemblerTester : MachineAssemblerTester( ReturnValueTraits::Representation(), p0, p1, p2, p3, p4) {} + + template + 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 + 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 + 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; diff --git a/test/cctest/compiler/test-instruction-selector-arm.cc b/test/cctest/compiler/test-instruction-selector-arm.cc index 4dcf21728e..f2d8524778 100644 --- a/test/cctest/compiler/test-instruction-selector-arm.cc +++ b/test/cctest/compiler/test-instruction-selector-arm.cc @@ -5,6 +5,7 @@ #include #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) { diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index 331b08247c..a4f915653f 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc @@ -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 #include -#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 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 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 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 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 m; diff --git a/test/cctest/compiler/value-helper.h b/test/cctest/compiler/value-helper.h index 51ccc59556..5bfd7884d0 100644 --- a/test/cctest/compiler/value-helper.h +++ b/test/cctest/compiler/value-helper.h @@ -104,6 +104,13 @@ class ValueHelper { V8_INFINITY * 0.0, nan}; return std::vector(&values[0], &values[ARRAY_SIZE(values)]); } + + static const std::vector 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(&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_