| 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);
|
|
|
|
|