Commit e4db78e7 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[arm] Recognize comparisons of shifts with zero.

For example, recognize

  0 == r1 << r2

and generate a single

  MOVS rt, r1, lsl r2

instruction.

TEST=cctest,compiler-unittests
R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23148 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8da9f23d
......@@ -152,8 +152,11 @@ class MacroAssembler: public Assembler {
// Register move. May do nothing if the registers are identical.
void Move(Register dst, Handle<Object> value);
void Move(Register dst, Register src, Condition cond = al);
void Move(Register dst, const Operand& src, Condition cond = al) {
if (!src.is_reg() || !src.rm().is(dst)) mov(dst, src, LeaveCC, cond);
void Move(Register dst, const Operand& src, SBit sbit = LeaveCC,
Condition cond = al) {
if (!src.is_reg() || !src.rm().is(dst) || sbit != LeaveCC) {
mov(dst, src, sbit, cond);
}
}
void Move(DwVfpRegister dst, DwVfpRegister src);
......
......@@ -198,8 +198,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break;
}
case kArmMov:
__ Move(i.OutputRegister(), i.InputOperand2(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
__ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
break;
case kArmMvn:
__ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
......
......@@ -480,15 +480,44 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
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);
}
......@@ -878,6 +907,14 @@ void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* 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;
}
......
......@@ -2214,6 +2214,58 @@ TEST(RunWord32ShlP) {
}
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) {
......@@ -2240,6 +2292,58 @@ TEST(RunWord32ShrP) {
}
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) {
......@@ -2266,6 +2370,58 @@ TEST(RunWord32SarP) {
}
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) {
......@@ -2291,6 +2447,58 @@ TEST(RunWord32RorP) {
}
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)));
......
......@@ -1094,6 +1094,43 @@ TEST_P(ShiftTest, Word32EqualWithParameterAndImmediate) {
}
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);
......
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