OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |