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/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/base/bits.h" | 6 #include "src/base/bits.h" |
7 #include "src/compiler/instruction-selector-impl.h" | 7 #include "src/compiler/instruction-selector-impl.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 | 10 |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 if (selector->IsSupported(MLS)) { | 297 if (selector->IsSupported(MLS)) { |
298 selector->Emit(kArmMls, result_operand, div_operand, right_operand, | 298 selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
299 left_operand); | 299 left_operand); |
300 } else { | 300 } else { |
301 InstructionOperand mul_operand = g.TempRegister(); | 301 InstructionOperand mul_operand = g.TempRegister(); |
302 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); | 302 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
303 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); | 303 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); |
304 } | 304 } |
305 } | 305 } |
306 | 306 |
307 void EmitLoad(InstructionSelector* selector, ArchOpcode opcode, Node* node, | |
308 Node* const base, Node* const index) { | |
309 ArmOperandGenerator g(selector); | |
310 InstructionCode icode; | |
311 InstructionOperand index_operand; | |
312 if (g.CanBeImmediate(index, opcode)) { | |
313 icode = opcode | AddressingModeField::encode(kMode_Offset_RI); | |
314 index_operand = g.UseImmediate(index); | |
315 } else { | |
316 icode = opcode | AddressingModeField::encode(kMode_Offset_RR); | |
317 index_operand = g.UseRegister(index); | |
318 } | |
319 selector->Emit(icode, g.DefineAsRegister(node), g.UseRegister(base), | |
320 index_operand); | |
321 } | |
322 | |
323 void EmitCheckedLoad(InstructionSelector* selector, ArchOpcode opcode, | |
324 Node* node, Node* const buffer, Node* const offset, | |
325 Node* const length) { | |
326 ArmOperandGenerator g(selector); | |
327 InstructionOperand offset_operand = g.UseRegister(offset); | |
328 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) | |
329 ? g.UseImmediate(length) | |
330 : g.UseRegister(length); | |
331 selector->Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), | |
332 g.DefineAsRegister(node), offset_operand, length_operand, | |
333 g.UseRegister(buffer), offset_operand); | |
334 } | |
335 | |
336 // Simplify or elide mask on 8-bit and 16-bit stores. Returns the input node of | |
337 // the mask operation if it can be elided, otherwise the value node. | |
338 Node* SimplifyAndForMaskedStore(InstructionSelector* selector, Node* node, | |
Benedikt Meurer
2016/04/14 18:39:58
This looks like something that should be done in t
martyn.capewell
2016/04/15 14:05:49
You're right, I should update MachineOperatorReduc
| |
339 Node* value, ArchOpcode opcode) { | |
340 ArmOperandGenerator g(selector); | |
341 NodeMatcher nm(value); | |
342 if (nm.IsWord32And() && selector->CanCover(node, value)) { | |
343 Uint32BinopMatcher m(value); | |
344 if (m.right().HasValue()) { | |
345 uint32_t mask = m.right().Value(); | |
346 | |
347 // Rewrite the opcode to make the later if statement simpler. | |
348 opcode = (opcode == kCheckedStoreWord8) ? kArmStrb : opcode; | |
349 opcode = (opcode == kCheckedStoreWord16) ? kArmStrh : opcode; | |
350 | |
351 if (((opcode == kArmStrb) && ((mask & 0xff) == 0xff)) || | |
352 ((opcode == kArmStrh) && ((mask & 0xffff) == 0xffff))) { | |
353 // The masking operation can be elided, so return the left input to the | |
354 // mask. | |
355 return m.left().node(); | |
356 } else if (opcode == kArmStrh) { | |
357 // Strh effectively applies a mask of 0xffff, so simplify the AND's mask | |
358 // using this, with the aim of making the new immediate encodable in the | |
359 // instruction. | |
360 mask &= 0xffff; | |
361 if (g.CanBeImmediate(mask)) { | |
362 selector->Emit( | |
363 kArmAnd | AddressingModeField::encode(kMode_Operand2_I), | |
364 g.DefineAsRegister(value), g.UseRegister(m.left().node()), | |
365 g.TempImmediate(mask)); | |
366 } else if (g.CanBeImmediate(mask ^ 0xffff)) { | |
367 selector->Emit( | |
368 kArmBic | AddressingModeField::encode(kMode_Operand2_I), | |
369 g.DefineAsRegister(value), g.UseRegister(m.left().node()), | |
370 g.TempImmediate(mask ^ 0xffff)); | |
371 } | |
372 } | |
373 // TODO(turbofan): Consider similar optimisation for strb/and 0xff. | |
374 } | |
375 } | |
376 return value; | |
377 } | |
378 | |
307 } // namespace | 379 } // namespace |
308 | 380 |
309 | 381 |
310 void InstructionSelector::VisitLoad(Node* node) { | 382 void InstructionSelector::VisitLoad(Node* node) { |
311 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); | 383 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); |
312 ArmOperandGenerator g(this); | 384 ArmOperandGenerator g(this); |
313 Node* base = node->InputAt(0); | 385 Node* base = node->InputAt(0); |
314 Node* index = node->InputAt(1); | 386 Node* index = node->InputAt(1); |
315 | 387 |
316 ArchOpcode opcode = kArchNop; | 388 ArchOpcode opcode = kArchNop; |
(...skipping 15 matching lines...) Expand all Loading... | |
332 case MachineRepresentation::kWord32: | 404 case MachineRepresentation::kWord32: |
333 opcode = kArmLdr; | 405 opcode = kArmLdr; |
334 break; | 406 break; |
335 case MachineRepresentation::kWord64: // Fall through. | 407 case MachineRepresentation::kWord64: // Fall through. |
336 case MachineRepresentation::kSimd128: // Fall through. | 408 case MachineRepresentation::kSimd128: // Fall through. |
337 case MachineRepresentation::kNone: | 409 case MachineRepresentation::kNone: |
338 UNREACHABLE(); | 410 UNREACHABLE(); |
339 return; | 411 return; |
340 } | 412 } |
341 | 413 |
342 if (g.CanBeImmediate(index, opcode)) { | 414 EmitLoad(this, opcode, node, base, index); |
343 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), | |
344 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); | |
345 } else { | |
346 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), | |
347 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); | |
348 } | |
349 } | 415 } |
350 | 416 |
351 | 417 |
352 void InstructionSelector::VisitStore(Node* node) { | 418 void InstructionSelector::VisitStore(Node* node) { |
353 ArmOperandGenerator g(this); | 419 ArmOperandGenerator g(this); |
354 Node* base = node->InputAt(0); | 420 Node* base = node->InputAt(0); |
355 Node* index = node->InputAt(1); | 421 Node* index = node->InputAt(1); |
356 Node* value = node->InputAt(2); | 422 Node* value = node->InputAt(2); |
357 | 423 |
358 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); | 424 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 case MachineRepresentation::kWord32: | 482 case MachineRepresentation::kWord32: |
417 opcode = kArmStr; | 483 opcode = kArmStr; |
418 break; | 484 break; |
419 case MachineRepresentation::kWord64: // Fall through. | 485 case MachineRepresentation::kWord64: // Fall through. |
420 case MachineRepresentation::kSimd128: // Fall through. | 486 case MachineRepresentation::kSimd128: // Fall through. |
421 case MachineRepresentation::kNone: | 487 case MachineRepresentation::kNone: |
422 UNREACHABLE(); | 488 UNREACHABLE(); |
423 return; | 489 return; |
424 } | 490 } |
425 | 491 |
492 value = SimplifyAndForMaskedStore(this, node, value, opcode); | |
493 | |
426 if (g.CanBeImmediate(index, opcode)) { | 494 if (g.CanBeImmediate(index, opcode)) { |
427 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(), | 495 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(), |
428 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); | 496 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); |
429 } else { | 497 } else { |
430 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), | 498 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
431 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); | 499 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); |
432 } | 500 } |
433 } | 501 } |
434 } | 502 } |
435 | 503 |
(...skipping 22 matching lines...) Expand all Loading... | |
458 opcode = kCheckedLoadFloat64; | 526 opcode = kCheckedLoadFloat64; |
459 break; | 527 break; |
460 case MachineRepresentation::kBit: // Fall through. | 528 case MachineRepresentation::kBit: // Fall through. |
461 case MachineRepresentation::kTagged: // Fall through. | 529 case MachineRepresentation::kTagged: // Fall through. |
462 case MachineRepresentation::kWord64: // Fall through. | 530 case MachineRepresentation::kWord64: // Fall through. |
463 case MachineRepresentation::kSimd128: // Fall through. | 531 case MachineRepresentation::kSimd128: // Fall through. |
464 case MachineRepresentation::kNone: | 532 case MachineRepresentation::kNone: |
465 UNREACHABLE(); | 533 UNREACHABLE(); |
466 return; | 534 return; |
467 } | 535 } |
468 InstructionOperand offset_operand = g.UseRegister(offset); | 536 EmitCheckedLoad(this, opcode, node, buffer, offset, length); |
469 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) | |
470 ? g.UseImmediate(length) | |
471 : g.UseRegister(length); | |
472 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), | |
473 g.DefineAsRegister(node), offset_operand, length_operand, | |
474 g.UseRegister(buffer), offset_operand); | |
475 } | 537 } |
476 | 538 |
477 | 539 |
478 void InstructionSelector::VisitCheckedStore(Node* node) { | 540 void InstructionSelector::VisitCheckedStore(Node* node) { |
479 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op()); | 541 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op()); |
480 ArmOperandGenerator g(this); | 542 ArmOperandGenerator g(this); |
481 Node* const buffer = node->InputAt(0); | 543 Node* const buffer = node->InputAt(0); |
482 Node* const offset = node->InputAt(1); | 544 Node* const offset = node->InputAt(1); |
483 Node* const length = node->InputAt(2); | 545 Node* const length = node->InputAt(2); |
484 Node* const value = node->InputAt(3); | 546 Node* value = node->InputAt(3); |
485 ArchOpcode opcode = kArchNop; | 547 ArchOpcode opcode = kArchNop; |
486 switch (rep) { | 548 switch (rep) { |
487 case MachineRepresentation::kWord8: | 549 case MachineRepresentation::kWord8: |
488 opcode = kCheckedStoreWord8; | 550 opcode = kCheckedStoreWord8; |
489 break; | 551 break; |
490 case MachineRepresentation::kWord16: | 552 case MachineRepresentation::kWord16: |
491 opcode = kCheckedStoreWord16; | 553 opcode = kCheckedStoreWord16; |
492 break; | 554 break; |
493 case MachineRepresentation::kWord32: | 555 case MachineRepresentation::kWord32: |
494 opcode = kCheckedStoreWord32; | 556 opcode = kCheckedStoreWord32; |
495 break; | 557 break; |
496 case MachineRepresentation::kFloat32: | 558 case MachineRepresentation::kFloat32: |
497 opcode = kCheckedStoreFloat32; | 559 opcode = kCheckedStoreFloat32; |
498 break; | 560 break; |
499 case MachineRepresentation::kFloat64: | 561 case MachineRepresentation::kFloat64: |
500 opcode = kCheckedStoreFloat64; | 562 opcode = kCheckedStoreFloat64; |
501 break; | 563 break; |
502 case MachineRepresentation::kBit: // Fall through. | 564 case MachineRepresentation::kBit: // Fall through. |
503 case MachineRepresentation::kTagged: // Fall through. | 565 case MachineRepresentation::kTagged: // Fall through. |
504 case MachineRepresentation::kWord64: // Fall through. | 566 case MachineRepresentation::kWord64: // Fall through. |
505 case MachineRepresentation::kSimd128: // Fall through. | 567 case MachineRepresentation::kSimd128: // Fall through. |
506 case MachineRepresentation::kNone: | 568 case MachineRepresentation::kNone: |
507 UNREACHABLE(); | 569 UNREACHABLE(); |
508 return; | 570 return; |
509 } | 571 } |
572 | |
573 value = SimplifyAndForMaskedStore(this, node, value, opcode); | |
574 | |
510 InstructionOperand offset_operand = g.UseRegister(offset); | 575 InstructionOperand offset_operand = g.UseRegister(offset); |
511 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) | 576 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) |
512 ? g.UseImmediate(length) | 577 ? g.UseImmediate(length) |
513 : g.UseRegister(length); | 578 : g.UseRegister(length); |
514 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), | 579 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
515 offset_operand, length_operand, g.UseRegister(value), | 580 offset_operand, length_operand, g.UseRegister(value), |
516 g.UseRegister(buffer), offset_operand); | 581 g.UseRegister(buffer), offset_operand); |
517 } | 582 } |
518 | 583 |
519 | 584 |
(...skipping 18 matching lines...) Expand all Loading... | |
538 | 603 |
539 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left, | 604 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left, |
540 uint32_t lsb, uint32_t width) { | 605 uint32_t lsb, uint32_t width) { |
541 DCHECK_LE(1u, width); | 606 DCHECK_LE(1u, width); |
542 DCHECK_LE(width, 32u - lsb); | 607 DCHECK_LE(width, 32u - lsb); |
543 ArmOperandGenerator g(selector); | 608 ArmOperandGenerator g(selector); |
544 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left), | 609 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left), |
545 g.TempImmediate(lsb), g.TempImmediate(width)); | 610 g.TempImmediate(lsb), g.TempImmediate(width)); |
546 } | 611 } |
547 | 612 |
613 // Try to emit an AND or BIC instruction when the left input is an 8/16-bit | |
614 // load. Returns true if an instruction was emitted, false otherwise. | |
615 bool TryEmitAndForMaskedLoad(InstructionSelector* selector, Node* node, | |
616 MachineType type, uint32_t value) { | |
617 ArmOperandGenerator g(selector); | |
618 Int32BinopMatcher m(node); | |
619 if (type == MachineType::Uint16()) { | |
620 // The input load has already applied a 0xffff mask to the input, so | |
621 // simplify the value and test if it's an immediate that can be encoded in | |
622 // the instruction. | |
623 value &= 0xffff; | |
624 if (g.CanBeImmediate(value)) { | |
625 selector->Emit(kArmAnd | AddressingModeField::encode(kMode_Operand2_I), | |
626 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
627 g.TempImmediate(value)); | |
628 return true; | |
629 } | |
630 // Test if an inverted value can be used with BIC. | |
631 if (g.CanBeImmediate(value ^ 0xffff)) { | |
632 selector->Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I), | |
633 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
634 g.TempImmediate(value ^ 0xffff)); | |
635 return true; | |
636 } | |
637 } else if (type == MachineType::Uint8()) { | |
638 // The input load has already applied a 0xff mask to the input. | |
639 value &= 0xff; | |
640 DCHECK(g.CanBeImmediate(value)); // All 8-bit values are encodable. | |
641 selector->Emit(kArmAnd | AddressingModeField::encode(kMode_Operand2_I), | |
642 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
643 g.TempImmediate(value)); | |
644 return true; | |
645 } | |
646 return false; | |
647 } | |
648 | |
548 } // namespace | 649 } // namespace |
549 | 650 |
550 | 651 |
551 void InstructionSelector::VisitWord32And(Node* node) { | 652 void InstructionSelector::VisitWord32And(Node* node) { |
552 ArmOperandGenerator g(this); | 653 ArmOperandGenerator g(this); |
553 Int32BinopMatcher m(node); | 654 Int32BinopMatcher m(node); |
554 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { | 655 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { |
555 Int32BinopMatcher mleft(m.left().node()); | 656 Int32BinopMatcher mleft(m.left().node()); |
556 if (mleft.right().Is(-1)) { | 657 if (mleft.right().Is(-1)) { |
557 EmitBic(this, node, m.right().node(), mleft.left().node()); | 658 EmitBic(this, node, m.right().node(), mleft.left().node()); |
558 return; | 659 return; |
559 } | 660 } |
560 } | 661 } |
561 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { | 662 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { |
562 Int32BinopMatcher mright(m.right().node()); | 663 Int32BinopMatcher mright(m.right().node()); |
563 if (mright.right().Is(-1)) { | 664 if (mright.right().Is(-1)) { |
564 EmitBic(this, node, m.left().node(), mright.left().node()); | 665 EmitBic(this, node, m.left().node(), mright.left().node()); |
565 return; | 666 return; |
566 } | 667 } |
567 } | 668 } |
568 if (m.right().HasValue()) { | 669 if (m.right().HasValue()) { |
569 uint32_t const value = m.right().Value(); | 670 uint32_t const value = m.right().Value(); |
570 uint32_t width = base::bits::CountPopulation32(value); | 671 uint32_t width = base::bits::CountPopulation32(value); |
571 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value); | 672 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value); |
572 | 673 |
674 if (m.left().IsLoad()) { | |
675 LoadRepresentation load_rep = LoadRepresentationOf(m.left().node()->op()); | |
676 if (CanCover(node, m.left().node()) && | |
677 ((value == 0xff) || (value == 0xffff))) { | |
678 // Elide mask operation on load inputs by modifying the size of the | |
679 // load. | |
680 ArchOpcode opcode = kArmLdrb; | |
681 if ((value == 0xffff) && | |
682 (load_rep.representation() != MachineRepresentation::kWord8)) { | |
683 opcode = kArmLdrh; | |
684 } | |
685 EmitLoad(this, opcode, node, m.left().InputAt(0), m.left().InputAt(1)); | |
686 return; | |
687 } | |
688 if (!g.CanBeImmediate(value) && | |
689 TryEmitAndForMaskedLoad(this, node, load_rep, value)) { | |
690 return; | |
691 } | |
692 } else if (m.left().IsCheckedLoad()) { | |
693 CheckedLoadRepresentation load_rep = | |
694 CheckedLoadRepresentationOf(m.left().node()->op()); | |
695 if (CanCover(node, m.left().node()) && | |
696 ((value == 0xff) || (value == 0xffff))) { | |
697 // Elide mask operation on load inputs by modifying the size of the | |
698 // load. | |
699 ArchOpcode opcode = kCheckedLoadUint8; | |
700 if ((value == 0xffff) && | |
701 (load_rep.representation() != MachineRepresentation::kWord8)) { | |
702 opcode = kCheckedLoadUint16; | |
703 } | |
704 EmitCheckedLoad(this, opcode, node, m.left().InputAt(0), | |
705 m.left().InputAt(1), m.left().InputAt(2)); | |
706 return; | |
707 } | |
708 if (!g.CanBeImmediate(value) && | |
709 TryEmitAndForMaskedLoad(this, node, load_rep, value)) { | |
710 return; | |
711 } | |
712 } | |
713 | |
573 // Try to merge SHR operations on the left hand input into this AND. | 714 // Try to merge SHR operations on the left hand input into this AND. |
574 if (m.left().IsWord32Shr()) { | 715 if (m.left().IsWord32Shr()) { |
575 Int32BinopMatcher mshr(m.left().node()); | 716 Int32BinopMatcher mshr(m.left().node()); |
576 if (mshr.right().HasValue()) { | 717 if (mshr.right().HasValue()) { |
577 uint32_t const shift = mshr.right().Value(); | 718 uint32_t const shift = mshr.right().Value(); |
578 | 719 |
579 if (((shift == 8) || (shift == 16) || (shift == 24)) && | 720 if (((shift == 8) || (shift == 16) || (shift == 24)) && |
580 ((value == 0xff) || (value == 0xffff))) { | 721 ((value == 0xff) || (value == 0xffff))) { |
581 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a | 722 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a |
582 // bytewise rotation. | 723 // bytewise rotation. |
(...skipping 1255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1838 MachineOperatorBuilder::kFloat32Max | | 1979 MachineOperatorBuilder::kFloat32Max | |
1839 MachineOperatorBuilder::kFloat64Min | | 1980 MachineOperatorBuilder::kFloat64Min | |
1840 MachineOperatorBuilder::kFloat64Max; | 1981 MachineOperatorBuilder::kFloat64Max; |
1841 } | 1982 } |
1842 return flags; | 1983 return flags; |
1843 } | 1984 } |
1844 | 1985 |
1845 } // namespace compiler | 1986 } // namespace compiler |
1846 } // namespace internal | 1987 } // namespace internal |
1847 } // namespace v8 | 1988 } // namespace v8 |
OLD | NEW |