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() && |