Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/compiler/arm/instruction-selector-arm.cc

Issue 1883133002: [turbofan] ARM: elide masks on loads and stores (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/unittests/compiler/arm/instruction-selector-arm-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | test/unittests/compiler/arm/instruction-selector-arm-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698