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 2101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2112 // We can also handle the case where the add and the compare are in the | 2112 // We can also handle the case where the add and the compare are in the |
2113 // same basic block, and the compare is the only use of add in this basic | 2113 // same basic block, and the compare is the only use of add in this basic |
2114 // block (the add has users in other basic blocks). | 2114 // block (the add has users in other basic blocks). |
2115 cont->Overwrite(MapForFlagSettingBinop(cond)); | 2115 cont->Overwrite(MapForFlagSettingBinop(cond)); |
2116 *opcode = binop_opcode; | 2116 *opcode = binop_opcode; |
2117 *node = binop; | 2117 *node = binop; |
2118 *immediate_mode = binop_immediate_mode; | 2118 *immediate_mode = binop_immediate_mode; |
2119 } | 2119 } |
2120 } | 2120 } |
2121 | 2121 |
| 2122 // Map {cond} to kEqual or kNotEqual, so that we can select |
| 2123 // either TBZ or TBNZ when generating code for: |
| 2124 // (x cmp 0), b.{cond} |
| 2125 FlagsCondition MapForTbz(FlagsCondition cond) { |
| 2126 switch (cond) { |
| 2127 case kSignedLessThan: // generate TBNZ |
| 2128 return kNotEqual; |
| 2129 case kSignedGreaterThanOrEqual: // generate TBZ |
| 2130 return kEqual; |
| 2131 default: |
| 2132 UNREACHABLE(); |
| 2133 return cond; |
| 2134 } |
| 2135 } |
| 2136 |
| 2137 // Map {cond} to kEqual or kNotEqual, so that we can select |
| 2138 // either CBZ or CBNZ when generating code for: |
| 2139 // (x cmp 0), b.{cond} |
| 2140 FlagsCondition MapForCbz(FlagsCondition cond) { |
| 2141 switch (cond) { |
| 2142 case kEqual: // generate CBZ |
| 2143 case kNotEqual: // generate CBNZ |
| 2144 return cond; |
| 2145 case kUnsignedLessThanOrEqual: // generate CBZ |
| 2146 return kEqual; |
| 2147 case kUnsignedGreaterThan: // generate CBNZ |
| 2148 return kNotEqual; |
| 2149 default: |
| 2150 UNREACHABLE(); |
| 2151 return cond; |
| 2152 } |
| 2153 } |
| 2154 |
| 2155 // Try to emit TBZ, TBNZ, CBZ or CBNZ for certain comparisons of {node} |
| 2156 // against zero, depending on the condition. |
| 2157 bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, Node* user, |
| 2158 FlagsCondition cond, FlagsContinuation* cont) { |
| 2159 Int32BinopMatcher m_user(user); |
| 2160 USE(m_user); |
| 2161 DCHECK(m_user.right().Is(0) || m_user.left().Is(0)); |
| 2162 |
| 2163 // Only handle branches. |
| 2164 if (!cont->IsBranch()) return false; |
| 2165 |
| 2166 switch (cond) { |
| 2167 case kSignedLessThan: |
| 2168 case kSignedGreaterThanOrEqual: { |
| 2169 Arm64OperandGenerator g(selector); |
| 2170 cont->Overwrite(MapForTbz(cond)); |
| 2171 Int32Matcher m(node); |
| 2172 if (m.IsFloat64ExtractHighWord32() && selector->CanCover(user, node)) { |
| 2173 // SignedLessThan(Float64ExtractHighWord32(x), 0) and |
| 2174 // SignedGreaterThanOrEqual(Float64ExtractHighWord32(x), 0) essentially |
| 2175 // check the sign bit of a 64-bit floating point value. |
| 2176 InstructionOperand temp = g.TempRegister(); |
| 2177 selector->Emit(kArm64U64MoveFloat64, temp, |
| 2178 g.UseRegister(node->InputAt(0))); |
| 2179 selector->Emit(cont->Encode(kArm64TestAndBranch), g.NoOutput(), temp, |
| 2180 g.TempImmediate(63), g.Label(cont->true_block()), |
| 2181 g.Label(cont->false_block())); |
| 2182 return true; |
| 2183 } |
| 2184 selector->Emit(cont->Encode(kArm64TestAndBranch32), g.NoOutput(), |
| 2185 g.UseRegister(node), g.TempImmediate(31), |
| 2186 g.Label(cont->true_block()), g.Label(cont->false_block())); |
| 2187 return true; |
| 2188 } |
| 2189 case kEqual: |
| 2190 case kNotEqual: |
| 2191 case kUnsignedLessThanOrEqual: |
| 2192 case kUnsignedGreaterThan: { |
| 2193 Arm64OperandGenerator g(selector); |
| 2194 cont->Overwrite(MapForCbz(cond)); |
| 2195 selector->Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(), |
| 2196 g.UseRegister(node), g.Label(cont->true_block()), |
| 2197 g.Label(cont->false_block())); |
| 2198 return true; |
| 2199 } |
| 2200 default: |
| 2201 return false; |
| 2202 } |
| 2203 } |
| 2204 |
2122 void VisitWord32Compare(InstructionSelector* selector, Node* node, | 2205 void VisitWord32Compare(InstructionSelector* selector, Node* node, |
2123 FlagsContinuation* cont) { | 2206 FlagsContinuation* cont) { |
2124 Int32BinopMatcher m(node); | 2207 Int32BinopMatcher m(node); |
2125 ArchOpcode opcode = kArm64Cmp32; | 2208 ArchOpcode opcode = kArm64Cmp32; |
2126 FlagsCondition cond = cont->condition(); | 2209 FlagsCondition cond = cont->condition(); |
| 2210 if (m.right().Is(0)) { |
| 2211 if (TryEmitCbzOrTbz(selector, m.left().node(), node, cond, cont)) return; |
| 2212 } else if (m.left().Is(0)) { |
| 2213 FlagsCondition commuted_cond = CommuteFlagsCondition(cond); |
| 2214 if (TryEmitCbzOrTbz(selector, m.right().node(), node, commuted_cond, cont)) |
| 2215 return; |
| 2216 } |
2127 ImmediateMode immediate_mode = kArithmeticImm; | 2217 ImmediateMode immediate_mode = kArithmeticImm; |
2128 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32And())) { | 2218 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32And())) { |
2129 // Emit flag setting add/and instructions for comparisons against zero. | 2219 // Emit flag setting add/and instructions for comparisons against zero. |
2130 if (CanUseFlagSettingBinop(cond)) { | 2220 if (CanUseFlagSettingBinop(cond)) { |
2131 Node* binop = m.left().node(); | 2221 Node* binop = m.left().node(); |
2132 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, | 2222 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, |
2133 cond, cont, &immediate_mode); | 2223 cond, cont, &immediate_mode); |
2134 } | 2224 } |
2135 } else if (m.left().Is(0) && | 2225 } else if (m.left().Is(0) && |
2136 (m.right().IsInt32Add() || m.right().IsWord32And())) { | 2226 (m.right().IsInt32Add() || m.right().IsWord32And())) { |
2137 // Same as above, but we need to commute the condition before we | 2227 // Same as above, but we need to commute the condition before we |
2138 // continue with the rest of the checks. | 2228 // continue with the rest of the checks. |
2139 cond = CommuteFlagsCondition(cond); | 2229 FlagsCondition commuted_cond = CommuteFlagsCondition(cond); |
2140 if (CanUseFlagSettingBinop(cond)) { | 2230 if (CanUseFlagSettingBinop(commuted_cond)) { |
2141 Node* binop = m.right().node(); | 2231 Node* binop = m.right().node(); |
2142 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, | 2232 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, |
2143 cond, cont, &immediate_mode); | 2233 commuted_cond, cont, |
| 2234 &immediate_mode); |
2144 } | 2235 } |
2145 } else if (m.right().IsInt32Sub() && (cond == kEqual || cond == kNotEqual)) { | 2236 } else if (m.right().IsInt32Sub() && (cond == kEqual || cond == kNotEqual)) { |
2146 // Select negated compare for comparisons with negated right input. | 2237 // Select negated compare for comparisons with negated right input. |
2147 // Only do this for kEqual and kNotEqual, which do not depend on the | 2238 // Only do this for kEqual and kNotEqual, which do not depend on the |
2148 // C and V flags, as those flags will be different with CMN when the | 2239 // C and V flags, as those flags will be different with CMN when the |
2149 // right-hand side of the original subtraction is INT_MIN. | 2240 // right-hand side of the original subtraction is INT_MIN. |
2150 Node* sub = m.right().node(); | 2241 Node* sub = m.right().node(); |
2151 Int32BinopMatcher msub(sub); | 2242 Int32BinopMatcher msub(sub); |
2152 if (msub.left().Is(0)) { | 2243 if (msub.left().Is(0)) { |
2153 bool can_cover = selector->CanCover(node, sub); | 2244 bool can_cover = selector->CanCover(node, sub); |
(...skipping 643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2797 // static | 2888 // static |
2798 MachineOperatorBuilder::AlignmentRequirements | 2889 MachineOperatorBuilder::AlignmentRequirements |
2799 InstructionSelector::AlignmentRequirements() { | 2890 InstructionSelector::AlignmentRequirements() { |
2800 return MachineOperatorBuilder::AlignmentRequirements:: | 2891 return MachineOperatorBuilder::AlignmentRequirements:: |
2801 FullUnalignedAccessSupport(); | 2892 FullUnalignedAccessSupport(); |
2802 } | 2893 } |
2803 | 2894 |
2804 } // namespace compiler | 2895 } // namespace compiler |
2805 } // namespace internal | 2896 } // namespace internal |
2806 } // namespace v8 | 2897 } // namespace v8 |
OLD | NEW |