| Index: src/compiler/arm/instruction-selector-arm.cc
|
| diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
|
| index 95e3333669d8e8592dff60169af3f115b67958ec..03b0565487017a836ab5495016d06971ba1184f9 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());
|
| - }
|
| + 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;
|
| +}
|
| +
|
| +
|
| +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);
|
| - inputs[input_count++] = g.UseRegister(right);
|
| + *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R);
|
| + *shift_return = g.UseRegister(m.right().node());
|
| }
|
| + return true;
|
| +}
|
| +
|
|
|
| - // Append the optional labels.
|
| - while (label_count-- != 0) {
|
| - inputs[input_count++] = *labels++;
|
| +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;
|
| +}
|
|
|
| - 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);
|
| -
|
| - 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()) {
|
| + InstructionOperand* inputs[5];
|
| + size_t input_count = 0;
|
| + InstructionOperand* outputs[1];
|
| + size_t output_count = 0;
|
| +
|
| + 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();
|
| }
|
|
|
|
|
|
|