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

Side by Side 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, 5 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/instruction-selector-impl.h" 5 #include "src/compiler/instruction-selector-impl.h"
6 #include "src/compiler/node-matchers.h" 6 #include "src/compiler/node-matchers.h"
7 #include "src/compiler/node-properties.h" 7 #include "src/compiler/node-properties.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 1903 matching lines...) Expand 10 before | Expand all | Expand 10 after
1914 } else if (g.CanBeImmediate(left, immediate_mode)) { 1914 } else if (g.CanBeImmediate(left, immediate_mode)) {
1915 if (!commutative) cont->Commute(); 1915 if (!commutative) cont->Commute();
1916 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), 1916 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
1917 cont); 1917 cont);
1918 } else { 1918 } else {
1919 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), 1919 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1920 cont); 1920 cont);
1921 } 1921 }
1922 } 1922 }
1923 1923
1924 // This function checks whether we can convert:
1925 // ((a <op> b) cmp 0), b.<cond>
1926 // to:
1927 // (a <ops> b), b.<cond'>
1928 // where <ops> is the flag setting version of <op>.
1929 // We only generate conditions <cond'> that are a combination of the N
1930 // and Z flags. This avoids the need to make this function dependent on
1931 // the flag-setting operation.
1932 bool CanUseFlagSettingBinop(FlagsCondition cond) {
1933 switch (cond) {
1934 case kEqual:
1935 case kNotEqual:
1936 case kSignedLessThan:
1937 case kSignedGreaterThanOrEqual:
1938 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
1939 case kUnsignedGreaterThan: // x > 0 -> x != 0
1940 return true;
1941 default:
1942 return false;
1943 }
1944 }
1945
1946 // Map <cond> to <cond'> so that the following transformation is possible:
1947 // ((a <op> b) cmp 0), b.<cond>
1948 // to:
1949 // (a <ops> b), b.<cond'>
1950 // where <ops> is the flag setting version of <op>.
1951 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
1952 DCHECK(CanUseFlagSettingBinop(cond));
1953 switch (cond) {
1954 case kEqual:
1955 case kNotEqual:
1956 return cond;
1957 case kSignedLessThan:
1958 return kNegative;
1959 case kSignedGreaterThanOrEqual:
1960 return kPositiveOrZero;
1961 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
1962 return kEqual;
1963 case kUnsignedGreaterThan: // x > 0 -> x != 0
1964 return kNotEqual;
1965 default:
1966 UNREACHABLE();
1967 return cond;
1968 }
1969 }
1970
1971 // This function checks if we can perform the transformation:
1972 // ((a <op> b) cmp 0), b.<cond>
1973 // to:
1974 // (a <ops> b), b.<cond'>
1975 // where <ops> is the flag setting version of <op>, and if so,
1976 // updates {node}, {opcode} and {cont} accordingly.
1977 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
1978 Node** node, Node* binop,
1979 ArchOpcode* opcode,
1980 FlagsCondition cond,
1981 FlagsContinuation* cont,
1982 ImmediateMode* immediate_mode) {
1983 ArchOpcode binop_opcode;
1984 ArchOpcode no_output_opcode;
1985 ImmediateMode binop_immediate_mode;
1986 switch (binop->opcode()) {
1987 case IrOpcode::kInt32Add:
1988 binop_opcode = kArm64Add32;
1989 no_output_opcode = kArm64Cmn32;
1990 binop_immediate_mode = kArithmeticImm;
1991 break;
1992 case IrOpcode::kWord32And:
1993 binop_opcode = kArm64And32;
1994 no_output_opcode = kArm64Tst32;
1995 binop_immediate_mode = kLogical32Imm;
1996 break;
1997 default:
1998 UNREACHABLE();
1999 return;
2000 }
2001 if (selector->CanCover(*node, binop)) {
2002 // The comparison is the only user of the add or and, so we can generate
2003 // a cmn or tst instead.
2004 cont->Overwrite(MapForFlagSettingBinop(cond));
2005 *opcode = no_output_opcode;
2006 *node = binop;
2007 *immediate_mode = binop_immediate_mode;
2008 } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
2009 // We can also handle the case where the add and the compare are in the
2010 // same basic block, and the compare is the only use of add in this basic
2011 // block (the add has users in other basic blocks).
2012 cont->Overwrite(MapForFlagSettingBinop(cond));
2013 *opcode = binop_opcode;
2014 *node = binop;
2015 *immediate_mode = binop_immediate_mode;
2016 }
2017 }
1924 2018
1925 void VisitWord32Compare(InstructionSelector* selector, Node* node, 2019 void VisitWord32Compare(InstructionSelector* selector, Node* node,
1926 FlagsContinuation* cont) { 2020 FlagsContinuation* cont) {
1927 Int32BinopMatcher m(node); 2021 Int32BinopMatcher m(node);
1928 ArchOpcode opcode = kArm64Cmp32; 2022 ArchOpcode opcode = kArm64Cmp32;
1929 2023 FlagsCondition cond = cont->condition();
1930 // Select negated compare for comparisons with negated right input. 2024 ImmediateMode immediate_mode = kArithmeticImm;
1931 if (m.right().IsInt32Sub()) { 2025 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32And())) {
2026 // Emit flag setting add/and instructions for comparisons against zero.
2027 if (CanUseFlagSettingBinop(cond)) {
2028 Node* binop = m.left().node();
2029 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
2030 cond, cont, &immediate_mode);
2031 }
2032 } else if (m.left().Is(0) &&
2033 (m.right().IsInt32Add() || m.right().IsWord32And())) {
2034 // Same as above, but we need to commute the condition before we
2035 // continue with the rest of the checks.
2036 cond = CommuteFlagsCondition(cond);
2037 if (CanUseFlagSettingBinop(cond)) {
2038 Node* binop = m.right().node();
2039 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
2040 cond, cont, &immediate_mode);
2041 }
2042 } else if (m.right().IsInt32Sub()) {
2043 // Select negated compare for comparisons with negated right input.
1932 Node* sub = m.right().node(); 2044 Node* sub = m.right().node();
1933 Int32BinopMatcher msub(sub); 2045 Int32BinopMatcher msub(sub);
1934 if (msub.left().Is(0)) { 2046 if (msub.left().Is(0)) {
1935 bool can_cover = selector->CanCover(node, sub); 2047 bool can_cover = selector->CanCover(node, sub);
1936 node->ReplaceInput(1, msub.right().node()); 2048 node->ReplaceInput(1, msub.right().node());
1937 // Even if the comparison node covers the subtraction, after the input 2049 // Even if the comparison node covers the subtraction, after the input
1938 // replacement above, the node still won't cover the input to the 2050 // replacement above, the node still won't cover the input to the
1939 // subtraction; the subtraction still uses it. 2051 // subtraction; the subtraction still uses it.
1940 // In order to get shifted operations to work, we must remove the rhs 2052 // In order to get shifted operations to work, we must remove the rhs
1941 // input to the subtraction, as TryMatchAnyShift requires this node to 2053 // input to the subtraction, as TryMatchAnyShift requires this node to
1942 // cover the input shift. We do this by setting it to the lhs input, 2054 // cover the input shift. We do this by setting it to the lhs input,
1943 // as we know it's zero, and the result of the subtraction isn't used by 2055 // as we know it's zero, and the result of the subtraction isn't used by
1944 // any other node. 2056 // any other node.
1945 if (can_cover) sub->ReplaceInput(1, msub.left().node()); 2057 if (can_cover) sub->ReplaceInput(1, msub.left().node());
1946 opcode = kArm64Cmn32; 2058 opcode = kArm64Cmn32;
1947 } 2059 }
1948 } 2060 }
1949 VisitBinop<Int32BinopMatcher>(selector, node, opcode, kArithmeticImm, cont); 2061 VisitBinop<Int32BinopMatcher>(selector, node, opcode, immediate_mode, cont);
1950 } 2062 }
1951 2063
1952 2064
1953 void VisitWordTest(InstructionSelector* selector, Node* node, 2065 void VisitWordTest(InstructionSelector* selector, Node* node,
1954 InstructionCode opcode, FlagsContinuation* cont) { 2066 InstructionCode opcode, FlagsContinuation* cont) {
1955 Arm64OperandGenerator g(selector); 2067 Arm64OperandGenerator g(selector);
1956 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node), 2068 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node),
1957 cont); 2069 cont);
1958 } 2070 }
1959 2071
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
2238 2350
2239 void InstructionSelector::VisitWord32Equal(Node* const node) { 2351 void InstructionSelector::VisitWord32Equal(Node* const node) {
2240 Node* const user = node; 2352 Node* const user = node;
2241 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); 2353 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2242 Int32BinopMatcher m(user); 2354 Int32BinopMatcher m(user);
2243 if (m.right().Is(0)) { 2355 if (m.right().Is(0)) {
2244 Node* const value = m.left().node(); 2356 Node* const value = m.left().node();
2245 if (CanCover(user, value)) { 2357 if (CanCover(user, value)) {
2246 switch (value->opcode()) { 2358 switch (value->opcode()) {
2247 case IrOpcode::kInt32Add: 2359 case IrOpcode::kInt32Add:
2248 return VisitWordCompare(this, value, kArm64Cmn32, &cont, true, 2360 case IrOpcode::kWord32And:
2249 kArithmeticImm); 2361 return VisitWord32Compare(this, node, &cont);
2250 case IrOpcode::kInt32Sub: 2362 case IrOpcode::kInt32Sub:
2251 return VisitWordCompare(this, value, kArm64Cmp32, &cont, false, 2363 return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
2252 kArithmeticImm); 2364 kArithmeticImm);
2253 case IrOpcode::kWord32And:
2254 return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
2255 kLogical32Imm);
2256 case IrOpcode::kWord32Equal: { 2365 case IrOpcode::kWord32Equal: {
2257 // Word32Equal(Word32Equal(x, y), 0) => Word32Compare(x, y, ne). 2366 // Word32Equal(Word32Equal(x, y), 0) => Word32Compare(x, y, ne).
2258 Int32BinopMatcher mequal(value); 2367 Int32BinopMatcher mequal(value);
2259 node->ReplaceInput(0, mequal.left().node()); 2368 node->ReplaceInput(0, mequal.left().node());
2260 node->ReplaceInput(1, mequal.right().node()); 2369 node->ReplaceInput(1, mequal.right().node());
2261 cont.Negate(); 2370 cont.Negate();
2371 // {node} still does not cover its new operands, because {mequal} is
2372 // still using them.
2373 // Since we won't generate any more code for {mequal}, set its
2374 // operands to zero to make sure {node} can cover them.
2375 // This improves pattern matching in VisitWord32Compare.
2376 mequal.node()->ReplaceInput(0, m.right().node());
2377 mequal.node()->ReplaceInput(1, m.right().node());
2262 return VisitWord32Compare(this, node, &cont); 2378 return VisitWord32Compare(this, node, &cont);
2263 } 2379 }
2264 default: 2380 default:
2265 break; 2381 break;
2266 } 2382 }
2267 return VisitWord32Test(this, value, &cont); 2383 return VisitWord32Test(this, value, &cont);
2268 } 2384 }
2269 } 2385 }
2270 VisitWord32Compare(this, node, &cont); 2386 VisitWord32Compare(this, node, &cont);
2271 } 2387 }
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
2562 // static 2678 // static
2563 MachineOperatorBuilder::AlignmentRequirements 2679 MachineOperatorBuilder::AlignmentRequirements
2564 InstructionSelector::AlignmentRequirements() { 2680 InstructionSelector::AlignmentRequirements() {
2565 return MachineOperatorBuilder::AlignmentRequirements:: 2681 return MachineOperatorBuilder::AlignmentRequirements::
2566 FullUnalignedAccessSupport(); 2682 FullUnalignedAccessSupport();
2567 } 2683 }
2568 2684
2569 } // namespace compiler 2685 } // namespace compiler
2570 } // namespace internal 2686 } // namespace internal
2571 } // namespace v8 2687 } // namespace v8
OLDNEW
« 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