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 static bool CanUseFlagSettingBinop(FlagsCondition cond) { | |
Benedikt Meurer
2016/06/29 03:54:35
Nit: You don't need static inside an anonymous nam
| |
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 static FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) { | |
Benedikt Meurer
2016/06/29 03:54:35
Nit: You don't need static inside an anonymous nam
| |
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 |