| Index: src/compiler/arm64/instruction-selector-arm64.cc
|
| diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc
|
| index 4be5c8371e70b4416741daae11c3535b2c03c52b..3eb37e1ab87cd93f8b6add3e8f678b85141bd970 100644
|
| --- a/src/compiler/arm64/instruction-selector-arm64.cc
|
| +++ b/src/compiler/arm64/instruction-selector-arm64.cc
|
| @@ -132,13 +132,14 @@ void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node,
|
|
|
|
|
| bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
|
| - InstructionCode* opcode, bool try_ror) {
|
| + Node* input_node, InstructionCode* opcode, bool try_ror) {
|
| Arm64OperandGenerator g(selector);
|
|
|
| - if (node->InputCount() != 2) return false;
|
| - if (!g.IsIntegerConstant(node->InputAt(1))) return false;
|
| + if (!selector->CanCover(node, input_node)) return false;
|
| + if (input_node->InputCount() != 2) return false;
|
| + if (!g.IsIntegerConstant(input_node->InputAt(1))) return false;
|
|
|
| - switch (node->opcode()) {
|
| + switch (input_node->opcode()) {
|
| case IrOpcode::kWord32Shl:
|
| case IrOpcode::kWord64Shl:
|
| *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
|
| @@ -165,9 +166,11 @@ bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
|
|
|
|
|
| bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector,
|
| - Node* left_node, Node* right_node,
|
| + Node* node, Node* left_node, Node* right_node,
|
| InstructionOperand* left_op,
|
| InstructionOperand* right_op, InstructionCode* opcode) {
|
| + if (!selector->CanCover(node, right_node)) return false;
|
| +
|
| NodeMatcher nm(right_node);
|
|
|
| if (nm.IsWord32And()) {
|
| @@ -207,15 +210,20 @@ void VisitBinop(InstructionSelector* selector, Node* node,
|
| FlagsContinuation* cont) {
|
| Arm64OperandGenerator g(selector);
|
| Matcher m(node);
|
| - InstructionOperand inputs[4];
|
| + InstructionOperand inputs[5];
|
| size_t input_count = 0;
|
| InstructionOperand outputs[2];
|
| size_t output_count = 0;
|
| - bool is_add_sub = false;
|
| + bool is_cmp = opcode == kArm64Cmp32;
|
|
|
| - if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) {
|
| - is_add_sub = true;
|
| - }
|
| + // We can commute cmp by switching the inputs and commuting the flags
|
| + // continuation.
|
| + bool can_commute = m.HasProperty(Operator::kCommutative) || is_cmp;
|
| +
|
| + // The cmp instruction is encoded as sub with zero output register, and
|
| + // therefore supports the same operand modes.
|
| + bool is_add_sub = m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() ||
|
| + m.IsInt64Sub() || is_cmp;
|
|
|
| Node* left_node = m.left().node();
|
| Node* right_node = m.right().node();
|
| @@ -223,21 +231,28 @@ void VisitBinop(InstructionSelector* selector, Node* node,
|
| if (g.CanBeImmediate(right_node, operand_mode)) {
|
| inputs[input_count++] = g.UseRegister(left_node);
|
| inputs[input_count++] = g.UseImmediate(right_node);
|
| + } else if (is_cmp && g.CanBeImmediate(left_node, operand_mode)) {
|
| + cont->Commute();
|
| + inputs[input_count++] = g.UseRegister(right_node);
|
| + inputs[input_count++] = g.UseImmediate(left_node);
|
| } else if (is_add_sub &&
|
| - TryMatchAnyExtend(&g, selector, left_node, right_node, &inputs[0],
|
| - &inputs[1], &opcode)) {
|
| + TryMatchAnyExtend(&g, selector, node, left_node, right_node,
|
| + &inputs[0], &inputs[1], &opcode)) {
|
| input_count += 2;
|
| - } else if (is_add_sub && m.HasProperty(Operator::kCommutative) &&
|
| - TryMatchAnyExtend(&g, selector, right_node, left_node, &inputs[0],
|
| - &inputs[1], &opcode)) {
|
| + } else if (is_add_sub && can_commute &&
|
| + TryMatchAnyExtend(&g, selector, node, right_node, left_node,
|
| + &inputs[0], &inputs[1], &opcode)) {
|
| + if (is_cmp) cont->Commute();
|
| input_count += 2;
|
| - } else if (TryMatchAnyShift(selector, right_node, &opcode, !is_add_sub)) {
|
| + } else if (TryMatchAnyShift(selector, node, right_node, &opcode,
|
| + !is_add_sub)) {
|
| Matcher m_shift(right_node);
|
| inputs[input_count++] = g.UseRegister(left_node);
|
| inputs[input_count++] = g.UseRegister(m_shift.left().node());
|
| inputs[input_count++] = g.UseImmediate(m_shift.right().node());
|
| - } else if (m.HasProperty(Operator::kCommutative) &&
|
| - TryMatchAnyShift(selector, left_node, &opcode, !is_add_sub)) {
|
| + } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode,
|
| + !is_add_sub)) {
|
| + if (is_cmp) cont->Commute();
|
| Matcher m_shift(left_node);
|
| inputs[input_count++] = g.UseRegister(right_node);
|
| inputs[input_count++] = g.UseRegister(m_shift.left().node());
|
| @@ -252,13 +267,16 @@ void VisitBinop(InstructionSelector* selector, Node* node,
|
| inputs[input_count++] = g.Label(cont->false_block());
|
| }
|
|
|
| - outputs[output_count++] = g.DefineAsRegister(node);
|
| + if (!is_cmp) {
|
| + outputs[output_count++] = g.DefineAsRegister(node);
|
| + }
|
| +
|
| if (cont->IsSet()) {
|
| outputs[output_count++] = g.DefineAsRegister(cont->result());
|
| }
|
|
|
| DCHECK_NE(0u, input_count);
|
| - DCHECK_NE(0u, output_count);
|
| + DCHECK((output_count != 0) || is_cmp);
|
| DCHECK_GE(arraysize(inputs), input_count);
|
| DCHECK_GE(arraysize(outputs), output_count);
|
|
|
| @@ -1597,7 +1615,8 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
|
|
|
| void VisitWord32Compare(InstructionSelector* selector, Node* node,
|
| FlagsContinuation* cont) {
|
| - VisitWordCompare(selector, node, kArm64Cmp32, cont, false, kArithmeticImm);
|
| + VisitBinop<Int32BinopMatcher>(selector, node, kArm64Cmp32, kArithmeticImm,
|
| + cont);
|
| }
|
|
|
|
|
| @@ -1756,8 +1775,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
| return VisitWordCompare(this, value, kArm64Cmn32, &cont, true,
|
| kArithmeticImm);
|
| case IrOpcode::kInt32Sub:
|
| - return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
|
| - kArithmeticImm);
|
| + return VisitWord32Compare(this, value, &cont);
|
| case IrOpcode::kWord32And: {
|
| Int32BinopMatcher m(value);
|
| if (m.right().HasValue() &&
|
|
|