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

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

Issue 2065243005: [arm64] Generate adds/ands. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Remove static Created 4 years, 6 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 | « src/compiler/arm64/code-generator-arm64.cc ('k') | src/compiler/instruction.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 25f4de0325d8e33faff1f738a98363e9e9dd5d84..7389c158e425aa9a8a932e18dc7a5f253197044c 100644
--- a/src/compiler/arm64/instruction-selector-arm64.cc
+++ b/src/compiler/arm64/instruction-selector-arm64.cc
@@ -1921,14 +1921,126 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
}
}
+// This function checks whether we can convert:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+// We only generate conditions <cond'> that are a combination of the N
+// and Z flags. This avoids the need to make this function dependent on
+// the flag-setting operation.
+bool CanUseFlagSettingBinop(FlagsCondition cond) {
+ switch (cond) {
+ case kEqual:
+ case kNotEqual:
+ case kSignedLessThan:
+ case kSignedGreaterThanOrEqual:
+ case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
+ case kUnsignedGreaterThan: // x > 0 -> x != 0
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Map <cond> to <cond'> so that the following transformation is possible:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
+ DCHECK(CanUseFlagSettingBinop(cond));
+ switch (cond) {
+ case kEqual:
+ case kNotEqual:
+ return cond;
+ case kSignedLessThan:
+ return kNegative;
+ case kSignedGreaterThanOrEqual:
+ return kPositiveOrZero;
+ case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
+ return kEqual;
+ case kUnsignedGreaterThan: // x > 0 -> x != 0
+ return kNotEqual;
+ default:
+ UNREACHABLE();
+ return cond;
+ }
+}
+
+// This function checks if we can perform the transformation:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>, and if so,
+// updates {node}, {opcode} and {cont} accordingly.
+void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
+ Node** node, Node* binop,
+ ArchOpcode* opcode,
+ FlagsCondition cond,
+ FlagsContinuation* cont,
+ ImmediateMode* immediate_mode) {
+ ArchOpcode binop_opcode;
+ ArchOpcode no_output_opcode;
+ ImmediateMode binop_immediate_mode;
+ switch (binop->opcode()) {
+ case IrOpcode::kInt32Add:
+ binop_opcode = kArm64Add32;
+ no_output_opcode = kArm64Cmn32;
+ binop_immediate_mode = kArithmeticImm;
+ break;
+ case IrOpcode::kWord32And:
+ binop_opcode = kArm64And32;
+ no_output_opcode = kArm64Tst32;
+ binop_immediate_mode = kLogical32Imm;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+ if (selector->CanCover(*node, binop)) {
+ // The comparison is the only user of the add or and, so we can generate
+ // a cmn or tst instead.
+ cont->Overwrite(MapForFlagSettingBinop(cond));
+ *opcode = no_output_opcode;
+ *node = binop;
+ *immediate_mode = binop_immediate_mode;
+ } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
+ // We can also handle the case where the add and the compare are in the
+ // same basic block, and the compare is the only use of add in this basic
+ // block (the add has users in other basic blocks).
+ cont->Overwrite(MapForFlagSettingBinop(cond));
+ *opcode = binop_opcode;
+ *node = binop;
+ *immediate_mode = binop_immediate_mode;
+ }
+}
void VisitWord32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
Int32BinopMatcher m(node);
ArchOpcode opcode = kArm64Cmp32;
-
- // Select negated compare for comparisons with negated right input.
- if (m.right().IsInt32Sub()) {
+ FlagsCondition cond = cont->condition();
+ 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.
+ if (CanUseFlagSettingBinop(cond)) {
+ Node* binop = m.left().node();
+ MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+ cond, cont, &immediate_mode);
+ }
+ } else if (m.left().Is(0) &&
+ (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)) {
+ Node* binop = m.right().node();
+ MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+ cond, cont, &immediate_mode);
+ }
+ } else if (m.right().IsInt32Sub()) {
+ // Select negated compare for comparisons with negated right input.
Node* sub = m.right().node();
Int32BinopMatcher msub(sub);
if (msub.left().Is(0)) {
@@ -1946,7 +2058,7 @@ void VisitWord32Compare(InstructionSelector* selector, Node* node,
opcode = kArm64Cmn32;
}
}
- VisitBinop<Int32BinopMatcher>(selector, node, opcode, kArithmeticImm, cont);
+ VisitBinop<Int32BinopMatcher>(selector, node, opcode, immediate_mode, cont);
}
@@ -2245,20 +2357,24 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
if (CanCover(user, value)) {
switch (value->opcode()) {
case IrOpcode::kInt32Add:
- return VisitWordCompare(this, value, kArm64Cmn32, &cont, true,
- kArithmeticImm);
+ case IrOpcode::kWord32And:
+ return VisitWord32Compare(this, node, &cont);
case IrOpcode::kInt32Sub:
return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
kArithmeticImm);
- case IrOpcode::kWord32And:
- return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
- kLogical32Imm);
case IrOpcode::kWord32Equal: {
// Word32Equal(Word32Equal(x, y), 0) => Word32Compare(x, y, ne).
Int32BinopMatcher mequal(value);
node->ReplaceInput(0, mequal.left().node());
node->ReplaceInput(1, mequal.right().node());
cont.Negate();
+ // {node} still does not cover its new operands, because {mequal} is
+ // still using them.
+ // Since we won't generate any more code for {mequal}, set its
+ // operands to zero to make sure {node} can cover them.
+ // This improves pattern matching in VisitWord32Compare.
+ mequal.node()->ReplaceInput(0, m.right().node());
+ mequal.node()->ReplaceInput(1, m.right().node());
return VisitWord32Compare(this, node, &cont);
}
default:
« no previous file with comments | « src/compiler/arm64/code-generator-arm64.cc ('k') | src/compiler/instruction.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698