Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Unified Diff: src/compiler/arm64/instruction-selector-arm64.cc

Issue 2359723004: [arm64] Check sign with TBZ/TBNZ. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « no previous file | test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698