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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node, | 125 void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node, |
126 ImmediateMode operand_mode) { | 126 ImmediateMode operand_mode) { |
127 Arm64OperandGenerator g(selector); | 127 Arm64OperandGenerator g(selector); |
128 selector->Emit(opcode, g.DefineAsRegister(node), | 128 selector->Emit(opcode, g.DefineAsRegister(node), |
129 g.UseRegister(node->InputAt(0)), | 129 g.UseRegister(node->InputAt(0)), |
130 g.UseOperand(node->InputAt(1), operand_mode)); | 130 g.UseOperand(node->InputAt(1), operand_mode)); |
131 } | 131 } |
132 | 132 |
133 | 133 |
134 bool TryMatchAnyShift(InstructionSelector* selector, Node* node, | 134 bool TryMatchAnyShift(InstructionSelector* selector, Node* node, |
135 InstructionCode* opcode, bool try_ror) { | 135 Node* input_node, InstructionCode* opcode, bool try_ror) { |
136 Arm64OperandGenerator g(selector); | 136 Arm64OperandGenerator g(selector); |
137 | 137 |
138 if (node->InputCount() != 2) return false; | 138 if (!selector->CanCover(node, input_node)) return false; |
139 if (!g.IsIntegerConstant(node->InputAt(1))) return false; | 139 if (input_node->InputCount() != 2) return false; |
| 140 if (!g.IsIntegerConstant(input_node->InputAt(1))) return false; |
140 | 141 |
141 switch (node->opcode()) { | 142 switch (input_node->opcode()) { |
142 case IrOpcode::kWord32Shl: | 143 case IrOpcode::kWord32Shl: |
143 case IrOpcode::kWord64Shl: | 144 case IrOpcode::kWord64Shl: |
144 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); | 145 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); |
145 return true; | 146 return true; |
146 case IrOpcode::kWord32Shr: | 147 case IrOpcode::kWord32Shr: |
147 case IrOpcode::kWord64Shr: | 148 case IrOpcode::kWord64Shr: |
148 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); | 149 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); |
149 return true; | 150 return true; |
150 case IrOpcode::kWord32Sar: | 151 case IrOpcode::kWord32Sar: |
151 case IrOpcode::kWord64Sar: | 152 case IrOpcode::kWord64Sar: |
152 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); | 153 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); |
153 return true; | 154 return true; |
154 case IrOpcode::kWord32Ror: | 155 case IrOpcode::kWord32Ror: |
155 case IrOpcode::kWord64Ror: | 156 case IrOpcode::kWord64Ror: |
156 if (try_ror) { | 157 if (try_ror) { |
157 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); | 158 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); |
158 return true; | 159 return true; |
159 } | 160 } |
160 return false; | 161 return false; |
161 default: | 162 default: |
162 return false; | 163 return false; |
163 } | 164 } |
164 } | 165 } |
165 | 166 |
166 | 167 |
167 bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector, | 168 bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector, |
168 Node* left_node, Node* right_node, | 169 Node* node, Node* left_node, Node* right_node, |
169 InstructionOperand* left_op, | 170 InstructionOperand* left_op, |
170 InstructionOperand* right_op, InstructionCode* opcode) { | 171 InstructionOperand* right_op, InstructionCode* opcode) { |
| 172 if (!selector->CanCover(node, right_node)) return false; |
| 173 |
171 NodeMatcher nm(right_node); | 174 NodeMatcher nm(right_node); |
172 | 175 |
173 if (nm.IsWord32And()) { | 176 if (nm.IsWord32And()) { |
174 Int32BinopMatcher mright(right_node); | 177 Int32BinopMatcher mright(right_node); |
175 if (mright.right().Is(0xff) || mright.right().Is(0xffff)) { | 178 if (mright.right().Is(0xff) || mright.right().Is(0xffff)) { |
176 int32_t mask = mright.right().Value(); | 179 int32_t mask = mright.right().Value(); |
177 *left_op = g->UseRegister(left_node); | 180 *left_op = g->UseRegister(left_node); |
178 *right_op = g->UseRegister(mright.left().node()); | 181 *right_op = g->UseRegister(mright.left().node()); |
179 *opcode |= AddressingModeField::encode( | 182 *opcode |= AddressingModeField::encode( |
180 (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH); | 183 (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH); |
(...skipping 19 matching lines...) Expand all Loading... |
200 } | 203 } |
201 | 204 |
202 | 205 |
203 // Shared routine for multiple binary operations. | 206 // Shared routine for multiple binary operations. |
204 template <typename Matcher> | 207 template <typename Matcher> |
205 void VisitBinop(InstructionSelector* selector, Node* node, | 208 void VisitBinop(InstructionSelector* selector, Node* node, |
206 InstructionCode opcode, ImmediateMode operand_mode, | 209 InstructionCode opcode, ImmediateMode operand_mode, |
207 FlagsContinuation* cont) { | 210 FlagsContinuation* cont) { |
208 Arm64OperandGenerator g(selector); | 211 Arm64OperandGenerator g(selector); |
209 Matcher m(node); | 212 Matcher m(node); |
210 InstructionOperand inputs[4]; | 213 InstructionOperand inputs[5]; |
211 size_t input_count = 0; | 214 size_t input_count = 0; |
212 InstructionOperand outputs[2]; | 215 InstructionOperand outputs[2]; |
213 size_t output_count = 0; | 216 size_t output_count = 0; |
214 bool is_add_sub = false; | 217 bool is_cmp = opcode == kArm64Cmp32; |
215 | 218 |
216 if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) { | 219 // We can commute cmp by switching the inputs and commuting the flags |
217 is_add_sub = true; | 220 // continuation. |
218 } | 221 bool can_commute = m.HasProperty(Operator::kCommutative) || is_cmp; |
| 222 |
| 223 // The cmp instruction is encoded as sub with zero output register, and |
| 224 // therefore supports the same operand modes. |
| 225 bool is_add_sub = m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || |
| 226 m.IsInt64Sub() || is_cmp; |
219 | 227 |
220 Node* left_node = m.left().node(); | 228 Node* left_node = m.left().node(); |
221 Node* right_node = m.right().node(); | 229 Node* right_node = m.right().node(); |
222 | 230 |
223 if (g.CanBeImmediate(right_node, operand_mode)) { | 231 if (g.CanBeImmediate(right_node, operand_mode)) { |
224 inputs[input_count++] = g.UseRegister(left_node); | 232 inputs[input_count++] = g.UseRegister(left_node); |
225 inputs[input_count++] = g.UseImmediate(right_node); | 233 inputs[input_count++] = g.UseImmediate(right_node); |
| 234 } else if (is_cmp && g.CanBeImmediate(left_node, operand_mode)) { |
| 235 cont->Commute(); |
| 236 inputs[input_count++] = g.UseRegister(right_node); |
| 237 inputs[input_count++] = g.UseImmediate(left_node); |
226 } else if (is_add_sub && | 238 } else if (is_add_sub && |
227 TryMatchAnyExtend(&g, selector, left_node, right_node, &inputs[0], | 239 TryMatchAnyExtend(&g, selector, node, left_node, right_node, |
228 &inputs[1], &opcode)) { | 240 &inputs[0], &inputs[1], &opcode)) { |
229 input_count += 2; | 241 input_count += 2; |
230 } else if (is_add_sub && m.HasProperty(Operator::kCommutative) && | 242 } else if (is_add_sub && can_commute && |
231 TryMatchAnyExtend(&g, selector, right_node, left_node, &inputs[0], | 243 TryMatchAnyExtend(&g, selector, node, right_node, left_node, |
232 &inputs[1], &opcode)) { | 244 &inputs[0], &inputs[1], &opcode)) { |
| 245 if (is_cmp) cont->Commute(); |
233 input_count += 2; | 246 input_count += 2; |
234 } else if (TryMatchAnyShift(selector, right_node, &opcode, !is_add_sub)) { | 247 } else if (TryMatchAnyShift(selector, node, right_node, &opcode, |
| 248 !is_add_sub)) { |
235 Matcher m_shift(right_node); | 249 Matcher m_shift(right_node); |
236 inputs[input_count++] = g.UseRegister(left_node); | 250 inputs[input_count++] = g.UseRegister(left_node); |
237 inputs[input_count++] = g.UseRegister(m_shift.left().node()); | 251 inputs[input_count++] = g.UseRegister(m_shift.left().node()); |
238 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); | 252 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); |
239 } else if (m.HasProperty(Operator::kCommutative) && | 253 } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode, |
240 TryMatchAnyShift(selector, left_node, &opcode, !is_add_sub)) { | 254 !is_add_sub)) { |
| 255 if (is_cmp) cont->Commute(); |
241 Matcher m_shift(left_node); | 256 Matcher m_shift(left_node); |
242 inputs[input_count++] = g.UseRegister(right_node); | 257 inputs[input_count++] = g.UseRegister(right_node); |
243 inputs[input_count++] = g.UseRegister(m_shift.left().node()); | 258 inputs[input_count++] = g.UseRegister(m_shift.left().node()); |
244 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); | 259 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); |
245 } else { | 260 } else { |
246 inputs[input_count++] = g.UseRegister(left_node); | 261 inputs[input_count++] = g.UseRegister(left_node); |
247 inputs[input_count++] = g.UseRegister(right_node); | 262 inputs[input_count++] = g.UseRegister(right_node); |
248 } | 263 } |
249 | 264 |
250 if (cont->IsBranch()) { | 265 if (cont->IsBranch()) { |
251 inputs[input_count++] = g.Label(cont->true_block()); | 266 inputs[input_count++] = g.Label(cont->true_block()); |
252 inputs[input_count++] = g.Label(cont->false_block()); | 267 inputs[input_count++] = g.Label(cont->false_block()); |
253 } | 268 } |
254 | 269 |
255 outputs[output_count++] = g.DefineAsRegister(node); | 270 if (!is_cmp) { |
| 271 outputs[output_count++] = g.DefineAsRegister(node); |
| 272 } |
| 273 |
256 if (cont->IsSet()) { | 274 if (cont->IsSet()) { |
257 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 275 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
258 } | 276 } |
259 | 277 |
260 DCHECK_NE(0u, input_count); | 278 DCHECK_NE(0u, input_count); |
261 DCHECK_NE(0u, output_count); | 279 DCHECK((output_count != 0) || is_cmp); |
262 DCHECK_GE(arraysize(inputs), input_count); | 280 DCHECK_GE(arraysize(inputs), input_count); |
263 DCHECK_GE(arraysize(outputs), output_count); | 281 DCHECK_GE(arraysize(outputs), output_count); |
264 | 282 |
265 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, | 283 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, |
266 inputs); | 284 inputs); |
267 } | 285 } |
268 | 286 |
269 | 287 |
270 // Shared routine for multiple binary operations. | 288 // Shared routine for multiple binary operations. |
271 template <typename Matcher> | 289 template <typename Matcher> |
(...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1590 cont); | 1608 cont); |
1591 } else { | 1609 } else { |
1592 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), | 1610 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), |
1593 cont); | 1611 cont); |
1594 } | 1612 } |
1595 } | 1613 } |
1596 | 1614 |
1597 | 1615 |
1598 void VisitWord32Compare(InstructionSelector* selector, Node* node, | 1616 void VisitWord32Compare(InstructionSelector* selector, Node* node, |
1599 FlagsContinuation* cont) { | 1617 FlagsContinuation* cont) { |
1600 VisitWordCompare(selector, node, kArm64Cmp32, cont, false, kArithmeticImm); | 1618 VisitBinop<Int32BinopMatcher>(selector, node, kArm64Cmp32, kArithmeticImm, |
| 1619 cont); |
1601 } | 1620 } |
1602 | 1621 |
1603 | 1622 |
1604 void VisitWordTest(InstructionSelector* selector, Node* node, | 1623 void VisitWordTest(InstructionSelector* selector, Node* node, |
1605 InstructionCode opcode, FlagsContinuation* cont) { | 1624 InstructionCode opcode, FlagsContinuation* cont) { |
1606 Arm64OperandGenerator g(selector); | 1625 Arm64OperandGenerator g(selector); |
1607 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node), | 1626 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node), |
1608 cont); | 1627 cont); |
1609 } | 1628 } |
1610 | 1629 |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1749 default: | 1768 default: |
1750 break; | 1769 break; |
1751 } | 1770 } |
1752 } | 1771 } |
1753 } | 1772 } |
1754 break; | 1773 break; |
1755 case IrOpcode::kInt32Add: | 1774 case IrOpcode::kInt32Add: |
1756 return VisitWordCompare(this, value, kArm64Cmn32, &cont, true, | 1775 return VisitWordCompare(this, value, kArm64Cmn32, &cont, true, |
1757 kArithmeticImm); | 1776 kArithmeticImm); |
1758 case IrOpcode::kInt32Sub: | 1777 case IrOpcode::kInt32Sub: |
1759 return VisitWordCompare(this, value, kArm64Cmp32, &cont, false, | 1778 return VisitWord32Compare(this, value, &cont); |
1760 kArithmeticImm); | |
1761 case IrOpcode::kWord32And: { | 1779 case IrOpcode::kWord32And: { |
1762 Int32BinopMatcher m(value); | 1780 Int32BinopMatcher m(value); |
1763 if (m.right().HasValue() && | 1781 if (m.right().HasValue() && |
1764 (base::bits::CountPopulation32(m.right().Value()) == 1)) { | 1782 (base::bits::CountPopulation32(m.right().Value()) == 1)) { |
1765 // If the mask has only one bit set, we can use tbz/tbnz. | 1783 // If the mask has only one bit set, we can use tbz/tbnz. |
1766 DCHECK((cont.condition() == kEqual) || | 1784 DCHECK((cont.condition() == kEqual) || |
1767 (cont.condition() == kNotEqual)); | 1785 (cont.condition() == kNotEqual)); |
1768 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), | 1786 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), |
1769 g.UseRegister(m.left().node()), | 1787 g.UseRegister(m.left().node()), |
1770 g.TempImmediate( | 1788 g.TempImmediate( |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2036 MachineOperatorBuilder::kFloat64RoundTruncate | | 2054 MachineOperatorBuilder::kFloat64RoundTruncate | |
2037 MachineOperatorBuilder::kFloat64RoundTiesAway | | 2055 MachineOperatorBuilder::kFloat64RoundTiesAway | |
2038 MachineOperatorBuilder::kWord32ShiftIsSafe | | 2056 MachineOperatorBuilder::kWord32ShiftIsSafe | |
2039 MachineOperatorBuilder::kInt32DivIsSafe | | 2057 MachineOperatorBuilder::kInt32DivIsSafe | |
2040 MachineOperatorBuilder::kUint32DivIsSafe; | 2058 MachineOperatorBuilder::kUint32DivIsSafe; |
2041 } | 2059 } |
2042 | 2060 |
2043 } // namespace compiler | 2061 } // namespace compiler |
2044 } // namespace internal | 2062 } // namespace internal |
2045 } // namespace v8 | 2063 } // namespace v8 |
OLD | NEW |