[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
This commit is contained in:
parent
8da9f23d44
commit
e4db78e705
@ -152,8 +152,11 @@ class MacroAssembler: public Assembler {
|
|||||||
// Register move. May do nothing if the registers are identical.
|
// Register move. May do nothing if the registers are identical.
|
||||||
void Move(Register dst, Handle<Object> value);
|
void Move(Register dst, Handle<Object> value);
|
||||||
void Move(Register dst, Register src, Condition cond = al);
|
void Move(Register dst, Register src, Condition cond = al);
|
||||||
void Move(Register dst, const Operand& src, Condition cond = al) {
|
void Move(Register dst, const Operand& src, SBit sbit = LeaveCC,
|
||||||
if (!src.is_reg() || !src.rm().is(dst)) mov(dst, src, LeaveCC, cond);
|
Condition cond = al) {
|
||||||
|
if (!src.is_reg() || !src.rm().is(dst) || sbit != LeaveCC) {
|
||||||
|
mov(dst, src, sbit, cond);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void Move(DwVfpRegister dst, DwVfpRegister src);
|
void Move(DwVfpRegister dst, DwVfpRegister src);
|
||||||
|
|
||||||
|
@ -198,8 +198,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kArmMov:
|
case kArmMov:
|
||||||
__ Move(i.OutputRegister(), i.InputOperand2(0));
|
__ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
|
||||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
|
||||||
break;
|
break;
|
||||||
case kArmMvn:
|
case kArmMvn:
|
||||||
__ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
|
__ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
|
||||||
|
@ -480,15 +480,44 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
|
|||||||
|
|
||||||
template <typename TryMatchShift>
|
template <typename TryMatchShift>
|
||||||
static inline void VisitShift(InstructionSelector* selector, Node* node,
|
static inline void VisitShift(InstructionSelector* selector, Node* node,
|
||||||
TryMatchShift try_match_shift) {
|
TryMatchShift try_match_shift,
|
||||||
|
FlagsContinuation* cont) {
|
||||||
ArmOperandGenerator g(selector);
|
ArmOperandGenerator g(selector);
|
||||||
InstructionCode opcode = kArmMov;
|
InstructionCode opcode = kArmMov;
|
||||||
InstructionOperand* value_operand = NULL;
|
InstructionOperand* inputs[4];
|
||||||
InstructionOperand* shift_operand = NULL;
|
size_t input_count = 2;
|
||||||
CHECK(
|
InstructionOperand* outputs[2];
|
||||||
try_match_shift(selector, &opcode, node, &value_operand, &shift_operand));
|
size_t output_count = 0;
|
||||||
selector->Emit(opcode, g.DefineAsRegister(node), value_operand,
|
|
||||||
shift_operand);
|
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);
|
return VisitBinop(this, node, kArmOrr, kArmOrr, cont);
|
||||||
case IrOpcode::kWord32Xor:
|
case IrOpcode::kWord32Xor:
|
||||||
return VisitWordCompare(this, node, kArmTeq, cont, true);
|
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:
|
default:
|
||||||
break;
|
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) {
|
TEST(RunWord32ShrP) {
|
||||||
{
|
{
|
||||||
FOR_UINT32_SHIFTS(shift) {
|
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) {
|
TEST(RunWord32SarP) {
|
||||||
{
|
{
|
||||||
FOR_INT32_SHIFTS(shift) {
|
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) {
|
TEST(RunWord32RorP) {
|
||||||
{
|
{
|
||||||
FOR_UINT32_SHIFTS(shift) {
|
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) {
|
TEST(RunWord32NotP) {
|
||||||
RawMachineAssemblerTester<int32_t> m(kMachInt32);
|
RawMachineAssemblerTester<int32_t> m(kMachInt32);
|
||||||
m.Return(m.Word32Not(m.Parameter(0)));
|
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) {
|
TEST_P(ShiftTest, Word32NotWithParameters) {
|
||||||
const Shift shift = GetParam();
|
const Shift shift = GetParam();
|
||||||
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
|
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
|
||||||
|
Loading…
Reference in New Issue
Block a user