| 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 a545c745b6865d007577bddcee04e6e9f3481123..da27be8626acbc43b653c36b541388a76e5bc5f7 100644
|
| --- a/src/compiler/arm64/instruction-selector-arm64.cc
|
| +++ b/src/compiler/arm64/instruction-selector-arm64.cc
|
| @@ -2119,11 +2119,101 @@ void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
|
| }
|
| }
|
|
|
| +// Map {cond} to kEqual or kNotEqual, so that we can select
|
| +// either TBZ or TBNZ when generating code for:
|
| +// (x cmp 0), b.{cond}
|
| +FlagsCondition MapForTbz(FlagsCondition cond) {
|
| + switch (cond) {
|
| + case kSignedLessThan: // generate TBNZ
|
| + return kNotEqual;
|
| + case kSignedGreaterThanOrEqual: // generate TBZ
|
| + return kEqual;
|
| + default:
|
| + UNREACHABLE();
|
| + return cond;
|
| + }
|
| +}
|
| +
|
| +// Map {cond} to kEqual or kNotEqual, so that we can select
|
| +// either CBZ or CBNZ when generating code for:
|
| +// (x cmp 0), b.{cond}
|
| +FlagsCondition MapForCbz(FlagsCondition cond) {
|
| + switch (cond) {
|
| + case kEqual: // generate CBZ
|
| + case kNotEqual: // generate CBNZ
|
| + return cond;
|
| + case kUnsignedLessThanOrEqual: // generate CBZ
|
| + return kEqual;
|
| + case kUnsignedGreaterThan: // generate CBNZ
|
| + return kNotEqual;
|
| + default:
|
| + UNREACHABLE();
|
| + return cond;
|
| + }
|
| +}
|
| +
|
| +// Try to emit TBZ, TBNZ, CBZ or CBNZ for certain comparisons of {node}
|
| +// against zero, depending on the condition.
|
| +bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, Node* user,
|
| + FlagsCondition cond, FlagsContinuation* cont) {
|
| + Int32BinopMatcher m_user(user);
|
| + USE(m_user);
|
| + DCHECK(m_user.right().Is(0) || m_user.left().Is(0));
|
| +
|
| + // Only handle branches.
|
| + if (!cont->IsBranch()) return false;
|
| +
|
| + switch (cond) {
|
| + case kSignedLessThan:
|
| + case kSignedGreaterThanOrEqual: {
|
| + Arm64OperandGenerator g(selector);
|
| + cont->Overwrite(MapForTbz(cond));
|
| + Int32Matcher m(node);
|
| + if (m.IsFloat64ExtractHighWord32() && selector->CanCover(user, node)) {
|
| + // SignedLessThan(Float64ExtractHighWord32(x), 0) and
|
| + // SignedGreaterThanOrEqual(Float64ExtractHighWord32(x), 0) essentially
|
| + // check the sign bit of a 64-bit floating point value.
|
| + InstructionOperand temp = g.TempRegister();
|
| + selector->Emit(kArm64U64MoveFloat64, temp,
|
| + g.UseRegister(node->InputAt(0)));
|
| + selector->Emit(cont->Encode(kArm64TestAndBranch), g.NoOutput(), temp,
|
| + g.TempImmediate(63), g.Label(cont->true_block()),
|
| + g.Label(cont->false_block()));
|
| + return true;
|
| + }
|
| + selector->Emit(cont->Encode(kArm64TestAndBranch32), g.NoOutput(),
|
| + g.UseRegister(node), g.TempImmediate(31),
|
| + g.Label(cont->true_block()), g.Label(cont->false_block()));
|
| + return true;
|
| + }
|
| + case kEqual:
|
| + case kNotEqual:
|
| + case kUnsignedLessThanOrEqual:
|
| + case kUnsignedGreaterThan: {
|
| + Arm64OperandGenerator g(selector);
|
| + cont->Overwrite(MapForCbz(cond));
|
| + selector->Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(),
|
| + g.UseRegister(node), g.Label(cont->true_block()),
|
| + g.Label(cont->false_block()));
|
| + return true;
|
| + }
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| void VisitWord32Compare(InstructionSelector* selector, Node* node,
|
| FlagsContinuation* cont) {
|
| Int32BinopMatcher m(node);
|
| ArchOpcode opcode = kArm64Cmp32;
|
| FlagsCondition cond = cont->condition();
|
| + if (m.right().Is(0)) {
|
| + if (TryEmitCbzOrTbz(selector, m.left().node(), node, cond, cont)) return;
|
| + } else if (m.left().Is(0)) {
|
| + FlagsCondition commuted_cond = CommuteFlagsCondition(cond);
|
| + if (TryEmitCbzOrTbz(selector, m.right().node(), node, commuted_cond, cont))
|
| + return;
|
| + }
|
| ImmediateMode immediate_mode = kArithmeticImm;
|
| if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32And())) {
|
| // Emit flag setting add/and instructions for comparisons against zero.
|
| @@ -2136,11 +2226,12 @@ void VisitWord32Compare(InstructionSelector* selector, Node* node,
|
| (m.right().IsInt32Add() || m.right().IsWord32And())) {
|
| // Same as above, but we need to commute the condition before we
|
| // continue with the rest of the checks.
|
| - cond = CommuteFlagsCondition(cond);
|
| - if (CanUseFlagSettingBinop(cond)) {
|
| + FlagsCondition commuted_cond = CommuteFlagsCondition(cond);
|
| + if (CanUseFlagSettingBinop(commuted_cond)) {
|
| Node* binop = m.right().node();
|
| MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
|
| - cond, cont, &immediate_mode);
|
| + commuted_cond, cont,
|
| + &immediate_mode);
|
| }
|
| } else if (m.right().IsInt32Sub() && (cond == kEqual || cond == kNotEqual)) {
|
| // Select negated compare for comparisons with negated right input.
|
|
|