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. |