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 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 return false; | 249 return false; |
250 } | 250 } |
251 *index_op = g->UseRegister(left); | 251 *index_op = g->UseRegister(left); |
252 *shift_immediate_op = g->UseImmediate(right); | 252 *shift_immediate_op = g->UseImmediate(right); |
253 return true; | 253 return true; |
254 default: | 254 default: |
255 return false; | 255 return false; |
256 } | 256 } |
257 } | 257 } |
258 | 258 |
| 259 // Bitfields describing binary operator properties: |
| 260 // CanCommuteField is true if we can switch the two operands, potentially |
| 261 // requiring commuting the flags continuation condition. |
| 262 typedef BitField8<bool, 1, 1> CanCommuteField; |
| 263 // MustCommuteCondField is true when we need to commute the flags continuation |
| 264 // condition in order to switch the operands. |
| 265 typedef BitField8<bool, 2, 1> MustCommuteCondField; |
| 266 // IsComparisonField is true when the operation is a comparison and has no other |
| 267 // result other than the condition. |
| 268 typedef BitField8<bool, 3, 1> IsComparisonField; |
| 269 // IsAddSubField is true when an instruction is encoded as ADD or SUB. |
| 270 typedef BitField8<bool, 4, 1> IsAddSubField; |
| 271 |
| 272 // Get properties of a binary operator. |
| 273 uint8_t GetBinopProperties(InstructionCode opcode) { |
| 274 uint8_t result = 0; |
| 275 switch (opcode) { |
| 276 case kArm64Cmp32: |
| 277 case kArm64Cmp: |
| 278 // We can commute CMP by switching the inputs and commuting |
| 279 // the flags continuation. |
| 280 result = CanCommuteField::update(result, true); |
| 281 result = MustCommuteCondField::update(result, true); |
| 282 result = IsComparisonField::update(result, true); |
| 283 // The CMP and CMN instructions are encoded as SUB or ADD |
| 284 // with zero output register, and therefore support the same |
| 285 // operand modes. |
| 286 result = IsAddSubField::update(result, true); |
| 287 break; |
| 288 case kArm64Cmn32: |
| 289 case kArm64Cmn: |
| 290 result = CanCommuteField::update(result, true); |
| 291 result = IsComparisonField::update(result, true); |
| 292 result = IsAddSubField::update(result, true); |
| 293 break; |
| 294 case kArm64Add32: |
| 295 case kArm64Add: |
| 296 result = CanCommuteField::update(result, true); |
| 297 result = IsAddSubField::update(result, true); |
| 298 break; |
| 299 case kArm64Sub32: |
| 300 case kArm64Sub: |
| 301 result = IsAddSubField::update(result, true); |
| 302 break; |
| 303 case kArm64Tst32: |
| 304 case kArm64Tst: |
| 305 result = CanCommuteField::update(result, true); |
| 306 result = IsComparisonField::update(result, true); |
| 307 break; |
| 308 case kArm64And32: |
| 309 case kArm64And: |
| 310 case kArm64Or32: |
| 311 case kArm64Or: |
| 312 case kArm64Eor32: |
| 313 case kArm64Eor: |
| 314 result = CanCommuteField::update(result, true); |
| 315 break; |
| 316 default: |
| 317 UNREACHABLE(); |
| 318 return 0; |
| 319 } |
| 320 DCHECK_IMPLIES(MustCommuteCondField::decode(result), |
| 321 CanCommuteField::decode(result)); |
| 322 return result; |
| 323 } |
| 324 |
259 // Shared routine for multiple binary operations. | 325 // Shared routine for multiple binary operations. |
260 template <typename Matcher> | 326 template <typename Matcher> |
261 void VisitBinop(InstructionSelector* selector, Node* node, | 327 void VisitBinop(InstructionSelector* selector, Node* node, |
262 InstructionCode opcode, ImmediateMode operand_mode, | 328 InstructionCode opcode, ImmediateMode operand_mode, |
263 FlagsContinuation* cont) { | 329 FlagsContinuation* cont) { |
264 Arm64OperandGenerator g(selector); | 330 Arm64OperandGenerator g(selector); |
265 Matcher m(node); | |
266 InstructionOperand inputs[5]; | 331 InstructionOperand inputs[5]; |
267 size_t input_count = 0; | 332 size_t input_count = 0; |
268 InstructionOperand outputs[2]; | 333 InstructionOperand outputs[2]; |
269 size_t output_count = 0; | 334 size_t output_count = 0; |
270 bool is_cmp = (opcode == kArm64Cmp32) || (opcode == kArm64Cmn32); | |
271 | 335 |
272 // We can commute cmp by switching the inputs and commuting the flags | 336 Node* left_node = node->InputAt(0); |
273 // continuation. | 337 Node* right_node = node->InputAt(1); |
274 bool can_commute = m.HasProperty(Operator::kCommutative) || is_cmp; | |
275 | 338 |
276 // The cmp and cmn instructions are encoded as sub or add with zero output | 339 uint8_t properties = GetBinopProperties(opcode); |
277 // register, and therefore support the same operand modes. | 340 bool can_commute = CanCommuteField::decode(properties); |
278 bool is_add_sub = m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || | 341 bool must_commute_cond = MustCommuteCondField::decode(properties); |
279 m.IsInt64Sub() || is_cmp; | 342 bool is_add_sub = IsAddSubField::decode(properties); |
280 | |
281 Node* left_node = m.left().node(); | |
282 Node* right_node = m.right().node(); | |
283 | 343 |
284 if (g.CanBeImmediate(right_node, operand_mode)) { | 344 if (g.CanBeImmediate(right_node, operand_mode)) { |
285 inputs[input_count++] = g.UseRegister(left_node); | 345 inputs[input_count++] = g.UseRegister(left_node); |
286 inputs[input_count++] = g.UseImmediate(right_node); | 346 inputs[input_count++] = g.UseImmediate(right_node); |
287 } else if (is_cmp && g.CanBeImmediate(left_node, operand_mode)) { | 347 } else if (can_commute && g.CanBeImmediate(left_node, operand_mode)) { |
288 cont->Commute(); | 348 if (must_commute_cond) cont->Commute(); |
289 inputs[input_count++] = g.UseRegister(right_node); | 349 inputs[input_count++] = g.UseRegister(right_node); |
290 inputs[input_count++] = g.UseImmediate(left_node); | 350 inputs[input_count++] = g.UseImmediate(left_node); |
291 } else if (is_add_sub && | 351 } else if (is_add_sub && |
292 TryMatchAnyExtend(&g, selector, node, left_node, right_node, | 352 TryMatchAnyExtend(&g, selector, node, left_node, right_node, |
293 &inputs[0], &inputs[1], &opcode)) { | 353 &inputs[0], &inputs[1], &opcode)) { |
294 input_count += 2; | 354 input_count += 2; |
295 } else if (is_add_sub && can_commute && | 355 } else if (is_add_sub && can_commute && |
296 TryMatchAnyExtend(&g, selector, node, right_node, left_node, | 356 TryMatchAnyExtend(&g, selector, node, right_node, left_node, |
297 &inputs[0], &inputs[1], &opcode)) { | 357 &inputs[0], &inputs[1], &opcode)) { |
298 if (is_cmp) cont->Commute(); | 358 if (must_commute_cond) cont->Commute(); |
299 input_count += 2; | 359 input_count += 2; |
300 } else if (TryMatchAnyShift(selector, node, right_node, &opcode, | 360 } else if (TryMatchAnyShift(selector, node, right_node, &opcode, |
301 !is_add_sub)) { | 361 !is_add_sub)) { |
302 Matcher m_shift(right_node); | 362 Matcher m_shift(right_node); |
303 inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node); | 363 inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node); |
304 inputs[input_count++] = g.UseRegister(m_shift.left().node()); | 364 inputs[input_count++] = g.UseRegister(m_shift.left().node()); |
305 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); | 365 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); |
306 } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode, | 366 } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode, |
307 !is_add_sub)) { | 367 !is_add_sub)) { |
308 if (is_cmp) cont->Commute(); | 368 if (must_commute_cond) cont->Commute(); |
309 Matcher m_shift(left_node); | 369 Matcher m_shift(left_node); |
310 inputs[input_count++] = g.UseRegisterOrImmediateZero(right_node); | 370 inputs[input_count++] = g.UseRegisterOrImmediateZero(right_node); |
311 inputs[input_count++] = g.UseRegister(m_shift.left().node()); | 371 inputs[input_count++] = g.UseRegister(m_shift.left().node()); |
312 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); | 372 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); |
313 } else { | 373 } else { |
314 inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node); | 374 inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node); |
315 inputs[input_count++] = g.UseRegister(right_node); | 375 inputs[input_count++] = g.UseRegister(right_node); |
316 } | 376 } |
317 | 377 |
318 if (cont->IsBranch()) { | 378 if (cont->IsBranch()) { |
319 inputs[input_count++] = g.Label(cont->true_block()); | 379 inputs[input_count++] = g.Label(cont->true_block()); |
320 inputs[input_count++] = g.Label(cont->false_block()); | 380 inputs[input_count++] = g.Label(cont->false_block()); |
321 } | 381 } |
322 | 382 |
323 if (!is_cmp) { | 383 if (!IsComparisonField::decode(properties)) { |
324 outputs[output_count++] = g.DefineAsRegister(node); | 384 outputs[output_count++] = g.DefineAsRegister(node); |
325 } | 385 } |
326 | 386 |
327 if (cont->IsSet()) { | 387 if (cont->IsSet()) { |
328 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 388 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
329 } | 389 } |
330 | 390 |
331 DCHECK_NE(0u, input_count); | 391 DCHECK_NE(0u, input_count); |
332 DCHECK((output_count != 0) || is_cmp); | 392 DCHECK((output_count != 0) || IsComparisonField::decode(properties)); |
333 DCHECK_GE(arraysize(inputs), input_count); | 393 DCHECK_GE(arraysize(inputs), input_count); |
334 DCHECK_GE(arraysize(outputs), output_count); | 394 DCHECK_GE(arraysize(outputs), output_count); |
335 | 395 |
336 opcode = cont->Encode(opcode); | 396 opcode = cont->Encode(opcode); |
337 if (cont->IsDeoptimize()) { | 397 if (cont->IsDeoptimize()) { |
338 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, | 398 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
339 cont->frame_state()); | 399 cont->frame_state()); |
340 } else { | 400 } else { |
341 selector->Emit(opcode, output_count, outputs, input_count, inputs); | 401 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
342 } | 402 } |
(...skipping 2146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2489 // static | 2549 // static |
2490 MachineOperatorBuilder::AlignmentRequirements | 2550 MachineOperatorBuilder::AlignmentRequirements |
2491 InstructionSelector::AlignmentRequirements() { | 2551 InstructionSelector::AlignmentRequirements() { |
2492 return MachineOperatorBuilder::AlignmentRequirements:: | 2552 return MachineOperatorBuilder::AlignmentRequirements:: |
2493 FullUnalignedAccessSupport(); | 2553 FullUnalignedAccessSupport(); |
2494 } | 2554 } |
2495 | 2555 |
2496 } // namespace compiler | 2556 } // namespace compiler |
2497 } // namespace internal | 2557 } // namespace internal |
2498 } // namespace v8 | 2558 } // namespace v8 |
OLD | NEW |