template <typename TryMatchShift>
static inline void VisitShift(InstructionSelector* selector, Node* node,
- TryMatchShift try_match_shift) {
+ TryMatchShift try_match_shift,
+ FlagsContinuation* cont) {
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);
+ InstructionOperand* inputs[4];
+ size_t input_count = 2;
+ InstructionOperand* outputs[2];
+ size_t output_count = 0;
+
+ CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
+
+ if (cont->IsBranch()) {
+ inputs[input_count++] = g.Label(cont->true_block());
+ inputs[input_count++] = g.Label(cont->false_block());
+ }
+
+ outputs[output_count++] = g.DefineAsRegister(node);
+ if (cont->IsSet()) {
+ outputs[output_count++] = g.DefineAsRegister(cont->result());
+ }
+
+ DCHECK_NE(0, input_count);
+ DCHECK_NE(0, output_count);
+ DCHECK_GE(ARRAY_SIZE(inputs), input_count);
+ DCHECK_GE(ARRAY_SIZE(outputs), output_count);
+ DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
+
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
+}
+
+
+template <typename TryMatchShift>
+static inline void VisitShift(InstructionSelector* selector, Node* node,
+ TryMatchShift try_match_shift) {
+ FlagsContinuation cont;
+ VisitShift(selector, node, try_match_shift, &cont);
}
return VisitBinop(this, node, kArmOrr, kArmOrr, cont);
case IrOpcode::kWord32Xor:
return VisitWordCompare(this, node, kArmTeq, cont, true);
+ case IrOpcode::kWord32Sar:
+ return VisitShift(this, node, TryMatchASR, cont);
+ case IrOpcode::kWord32Shl:
+ return VisitShift(this, node, TryMatchLSL, cont);
+ case IrOpcode::kWord32Shr:
+ return VisitShift(this, node, TryMatchLSR, cont);
+ case IrOpcode::kWord32Ror:
+ return VisitShift(this, node, TryMatchROR, cont);
default:
break;
}
}
+TEST(RunWord32ShlInComparison) {
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Word32Shl(bt.param0, bt.param1), m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == (*i << shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Int32Constant(0), m.Word32Shl(bt.param0, bt.param1)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == (*i << shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Int32Constant(0),
+ m.Word32Shl(m.Parameter(0), m.Int32Constant(shift))));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == (*i << shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift)),
+ m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == (*i << shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+}
+
+
TEST(RunWord32ShrP) {
{
FOR_UINT32_SHIFTS(shift) {
}
+TEST(RunWord32ShrInComparison) {
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Word32Shr(bt.param0, bt.param1), m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == (*i >> shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Int32Constant(0), m.Word32Shr(bt.param0, bt.param1)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == (*i >> shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Int32Constant(0),
+ m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == (*i >> shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)),
+ m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == (*i >> shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+}
+
+
TEST(RunWord32SarP) {
{
FOR_INT32_SHIFTS(shift) {
}
+TEST(RunWord32SarInComparison) {
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Int32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Word32Sar(bt.param0, bt.param1), m.Int32Constant(0)));
+ FOR_INT32_INPUTS(i) {
+ FOR_INT32_SHIFTS(shift) {
+ int32_t expected = 0 == (*i >> shift);
+ CHECK_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Int32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Int32Constant(0), m.Word32Sar(bt.param0, bt.param1)));
+ FOR_INT32_INPUTS(i) {
+ FOR_INT32_SHIFTS(shift) {
+ int32_t expected = 0 == (*i >> shift);
+ CHECK_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ FOR_INT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachInt32);
+ m.Return(
+ m.Word32Equal(m.Int32Constant(0),
+ m.Word32Sar(m.Parameter(0), m.Int32Constant(shift))));
+ FOR_INT32_INPUTS(i) {
+ int32_t expected = 0 == (*i >> shift);
+ CHECK_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+ {
+ FOR_INT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachInt32);
+ m.Return(
+ m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Int32Constant(shift)),
+ m.Int32Constant(0)));
+ FOR_INT32_INPUTS(i) {
+ uint32_t expected = 0 == (*i >> shift);
+ CHECK_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+}
+
+
TEST(RunWord32RorP) {
{
FOR_UINT32_SHIFTS(shift) {
}
+TEST(RunWord32RorInComparison) {
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Word32Ror(bt.param0, bt.param1), m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == bits::RotateRight32(*i, shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ RawMachineAssemblerTester<int32_t> m;
+ Uint32BinopTester bt(&m);
+ bt.AddReturn(
+ m.Word32Equal(m.Int32Constant(0), m.Word32Ror(bt.param0, bt.param1)));
+ FOR_UINT32_INPUTS(i) {
+ FOR_UINT32_SHIFTS(shift) {
+ uint32_t expected = 0 == bits::RotateRight32(*i, shift);
+ CHECK_UINT32_EQ(expected, bt.call(*i, shift));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Int32Constant(0),
+ m.Word32Ror(m.Parameter(0), m.Int32Constant(shift))));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == bits::RotateRight32(*i, shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+ {
+ FOR_UINT32_SHIFTS(shift) {
+ RawMachineAssemblerTester<int32_t> m(kMachUint32);
+ m.Return(
+ m.Word32Equal(m.Word32Ror(m.Parameter(0), m.Int32Constant(shift)),
+ m.Int32Constant(0)));
+ FOR_UINT32_INPUTS(i) {
+ uint32_t expected = 0 == bits::RotateRight32(*i, shift);
+ CHECK_UINT32_EQ(expected, m.Call(*i));
+ }
+ }
+ }
+}
+
+
TEST(RunWord32NotP) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(m.Word32Not(m.Parameter(0)));
}
+TEST_P(ShiftTest, Word32EqualToZeroWithParameters) {
+ const Shift shift = GetParam();
+ StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+ m.Return(
+ m.Word32Equal(m.Int32Constant(0),
+ (m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+ EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(2U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(ShiftTest, Word32EqualToZeroWithImmediate) {
+ const Shift shift = GetParam();
+ TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+ StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+ m.Return(m.Word32Equal(
+ m.Int32Constant(0),
+ (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+ EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+ EXPECT_EQ(2U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kEqual, s[0]->flags_condition());
+ }
+}
+
+
TEST_P(ShiftTest, Word32NotWithParameters) {
const Shift shift = GetParam();
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);