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 f9ee78f0e554dfded32a84c6903114460f43a11a..637acac58bb43f45ee547d33870c9028980bcbcc 100644 |
--- a/src/compiler/arm64/instruction-selector-arm64.cc |
+++ b/src/compiler/arm64/instruction-selector-arm64.cc |
@@ -256,36 +256,96 @@ bool TryMatchLoadStoreShift(Arm64OperandGenerator* g, |
} |
} |
+// Bitfields describing binary operator properties: |
+// CanCommuteField is true if we can switch the two operands, potentially |
+// requiring commuting the flags continuation condition. |
+typedef BitField8<bool, 1, 1> CanCommuteField; |
+// MustCommuteCondField is true when we need to commute the flags continuation |
+// condition in order to switch the operands. |
+typedef BitField8<bool, 2, 1> MustCommuteCondField; |
+// IsComparisonField is true when the operation is a comparison and has no other |
+// result other than the condition. |
+typedef BitField8<bool, 3, 1> IsComparisonField; |
+// IsAddSubField is true when an instruction is encoded as ADD or SUB. |
+typedef BitField8<bool, 4, 1> IsAddSubField; |
+ |
+// Get properties of a binary operator. |
+uint8_t GetBinopProperties(InstructionCode opcode) { |
+ uint8_t result = 0; |
+ switch (opcode) { |
+ case kArm64Cmp32: |
+ case kArm64Cmp: |
+ // We can commute CMP by switching the inputs and commuting |
+ // the flags continuation. |
+ result = CanCommuteField::update(result, true); |
+ result = MustCommuteCondField::update(result, true); |
+ result = IsComparisonField::update(result, true); |
+ // The CMP and CMN instructions are encoded as SUB or ADD |
+ // with zero output register, and therefore support the same |
+ // operand modes. |
+ result = IsAddSubField::update(result, true); |
+ break; |
+ case kArm64Cmn32: |
+ case kArm64Cmn: |
+ result = CanCommuteField::update(result, true); |
+ result = IsComparisonField::update(result, true); |
+ result = IsAddSubField::update(result, true); |
+ break; |
+ case kArm64Add32: |
+ case kArm64Add: |
+ result = CanCommuteField::update(result, true); |
+ result = IsAddSubField::update(result, true); |
+ break; |
+ case kArm64Sub32: |
+ case kArm64Sub: |
+ result = IsAddSubField::update(result, true); |
+ break; |
+ case kArm64Tst32: |
+ case kArm64Tst: |
+ result = CanCommuteField::update(result, true); |
+ result = IsComparisonField::update(result, true); |
+ break; |
+ case kArm64And32: |
+ case kArm64And: |
+ case kArm64Or32: |
+ case kArm64Or: |
+ case kArm64Eor32: |
+ case kArm64Eor: |
+ result = CanCommuteField::update(result, true); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ return 0; |
+ } |
+ DCHECK_IMPLIES(MustCommuteCondField::decode(result), |
+ CanCommuteField::decode(result)); |
+ return result; |
+} |
+ |
// Shared routine for multiple binary operations. |
template <typename Matcher> |
void VisitBinop(InstructionSelector* selector, Node* node, |
InstructionCode opcode, ImmediateMode operand_mode, |
FlagsContinuation* cont) { |
Arm64OperandGenerator g(selector); |
- Matcher m(node); |
InstructionOperand inputs[5]; |
size_t input_count = 0; |
InstructionOperand outputs[2]; |
size_t output_count = 0; |
- bool is_cmp = (opcode == kArm64Cmp32) || (opcode == kArm64Cmn32); |
- // We can commute cmp by switching the inputs and commuting the flags |
- // continuation. |
- bool can_commute = m.HasProperty(Operator::kCommutative) || is_cmp; |
+ Node* left_node = node->InputAt(0); |
+ Node* right_node = node->InputAt(1); |
- // The cmp and cmn instructions are encoded as sub or add with zero output |
- // register, and therefore support 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(); |
+ uint8_t properties = GetBinopProperties(opcode); |
+ bool can_commute = CanCommuteField::decode(properties); |
+ bool must_commute_cond = MustCommuteCondField::decode(properties); |
+ bool is_add_sub = IsAddSubField::decode(properties); |
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(); |
+ } else if (can_commute && g.CanBeImmediate(left_node, operand_mode)) { |
+ if (must_commute_cond) cont->Commute(); |
inputs[input_count++] = g.UseRegister(right_node); |
inputs[input_count++] = g.UseImmediate(left_node); |
} else if (is_add_sub && |
@@ -295,7 +355,7 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
} 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(); |
+ if (must_commute_cond) cont->Commute(); |
input_count += 2; |
} else if (TryMatchAnyShift(selector, node, right_node, &opcode, |
!is_add_sub)) { |
@@ -305,7 +365,7 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
inputs[input_count++] = g.UseImmediate(m_shift.right().node()); |
} else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode, |
!is_add_sub)) { |
- if (is_cmp) cont->Commute(); |
+ if (must_commute_cond) cont->Commute(); |
Matcher m_shift(left_node); |
inputs[input_count++] = g.UseRegisterOrImmediateZero(right_node); |
inputs[input_count++] = g.UseRegister(m_shift.left().node()); |
@@ -320,7 +380,7 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
inputs[input_count++] = g.Label(cont->false_block()); |
} |
- if (!is_cmp) { |
+ if (!IsComparisonField::decode(properties)) { |
outputs[output_count++] = g.DefineAsRegister(node); |
} |
@@ -329,7 +389,7 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
} |
DCHECK_NE(0u, input_count); |
- DCHECK((output_count != 0) || is_cmp); |
+ DCHECK((output_count != 0) || IsComparisonField::decode(properties)); |
DCHECK_GE(arraysize(inputs), input_count); |
DCHECK_GE(arraysize(outputs), output_count); |