72#define DEBUG_TYPE "si-load-store-opt"
80 S_BUFFER_LOAD_SGPR_IMM,
99 unsigned char NumVAddrs = 0;
102 bool SOffset =
false;
110const unsigned MaxAddressRegs = 12 + 1 + 1;
112class SILoadStoreOptimizer {
121 InstClassEnum InstClass;
125 int AddrIdx[MaxAddressRegs];
127 unsigned NumAddresses;
130 bool hasSameBaseAddress(
const CombineInfo &CI) {
131 if (NumAddresses != CI.NumAddresses)
135 for (
unsigned i = 0; i < NumAddresses; i++) {
138 if (AddrReg[i]->isImm() || AddrRegNext.
isImm()) {
139 if (AddrReg[i]->isImm() != AddrRegNext.
isImm() ||
157 for (
unsigned i = 0; i < NumAddresses; ++i) {
166 if (!AddrOp->
isReg())
172 AddrOp->
getReg() != AMDGPU::SGPR_NULL)
191 struct BaseRegisters {
195 unsigned LoSubReg = 0;
196 unsigned HiSubReg = 0;
198 bool UseV64Pattern =
false;
220 static bool dmasksCanBeCombined(
const CombineInfo &CI,
222 const CombineInfo &Paired);
223 static bool offsetsCanBeCombined(CombineInfo &CI,
const GCNSubtarget &STI,
224 CombineInfo &Paired,
bool Modify =
false);
225 static bool widthsFit(
const GCNSubtarget &STI,
const CombineInfo &CI,
226 const CombineInfo &Paired);
227 unsigned getNewOpcode(
const CombineInfo &CI,
const CombineInfo &Paired);
228 static std::pair<unsigned, unsigned> getSubRegIdxs(
const CombineInfo &CI,
229 const CombineInfo &Paired);
231 getTargetRegisterClass(
const CombineInfo &CI,
232 const CombineInfo &Paired)
const;
235 CombineInfo *checkAndPrepareMerge(CombineInfo &CI, CombineInfo &Paired);
237 void copyToDestRegs(CombineInfo &CI, CombineInfo &Paired,
241 Register copyFromSrcRegs(CombineInfo &CI, CombineInfo &Paired,
245 unsigned read2Opcode(
unsigned EltSize)
const;
246 unsigned read2ST64Opcode(
unsigned EltSize)
const;
248 mergeRead2Pair(CombineInfo &CI, CombineInfo &Paired,
251 unsigned write2Opcode(
unsigned EltSize)
const;
252 unsigned write2ST64Opcode(
unsigned EltSize)
const;
253 unsigned getWrite2Opcode(
const CombineInfo &CI)
const;
256 mergeWrite2Pair(CombineInfo &CI, CombineInfo &Paired,
259 mergeImagePair(CombineInfo &CI, CombineInfo &Paired,
262 mergeSMemLoadImmPair(CombineInfo &CI, CombineInfo &Paired,
265 mergeBufferLoadPair(CombineInfo &CI, CombineInfo &Paired,
268 mergeBufferStorePair(CombineInfo &CI, CombineInfo &Paired,
271 mergeTBufferLoadPair(CombineInfo &CI, CombineInfo &Paired,
274 mergeTBufferStorePair(CombineInfo &CI, CombineInfo &Paired,
277 mergeFlatLoadPair(CombineInfo &CI, CombineInfo &Paired,
280 mergeFlatStorePair(CombineInfo &CI, CombineInfo &Paired,
284 int32_t NewOffset)
const;
285 void updateAsyncLDSAddress(
MachineInstr &
MI, int32_t OffsetDiff)
const;
290 MemAddress &Addr)
const;
299 std::list<std::list<CombineInfo> > &MergeableInsts)
const;
304 std::list<std::list<CombineInfo>> &MergeableInsts)
const;
307 const CombineInfo &Paired);
309 static InstClassEnum getCommonInstClass(
const CombineInfo &CI,
310 const CombineInfo &Paired);
312 bool optimizeInstsWithSameBaseAddr(std::list<CombineInfo> &MergeList,
313 bool &OptimizeListAgain);
314 bool optimizeBlock(std::list<std::list<CombineInfo> > &MergeableInsts);
329 StringRef getPassName()
const override {
return "SI Load Store Optimizer"; }
344 const unsigned Opc =
MI.getOpcode();
350 if (
TII.isImage(
MI)) {
352 TII.getNamedOperand(
MI, AMDGPU::OpName::dmask)->getImm();
360 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
361 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
362 case AMDGPU::S_LOAD_DWORD_IMM:
363 case AMDGPU::GLOBAL_LOAD_DWORD:
364 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
365 case AMDGPU::GLOBAL_STORE_DWORD:
366 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
367 case AMDGPU::FLAT_LOAD_DWORD:
368 case AMDGPU::FLAT_STORE_DWORD:
369 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
370 case AMDGPU::FLAT_STORE_DWORD_SADDR:
372 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
373 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
374 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
375 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
376 case AMDGPU::S_LOAD_DWORDX2_IMM:
377 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
378 case AMDGPU::GLOBAL_LOAD_DWORDX2:
379 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
380 case AMDGPU::GLOBAL_STORE_DWORDX2:
381 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
382 case AMDGPU::FLAT_LOAD_DWORDX2:
383 case AMDGPU::FLAT_STORE_DWORDX2:
384 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
385 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
387 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
388 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
389 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
390 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
391 case AMDGPU::S_LOAD_DWORDX3_IMM:
392 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
393 case AMDGPU::GLOBAL_LOAD_DWORDX3:
394 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
395 case AMDGPU::GLOBAL_STORE_DWORDX3:
396 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
397 case AMDGPU::FLAT_LOAD_DWORDX3:
398 case AMDGPU::FLAT_STORE_DWORDX3:
399 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
400 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
402 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
403 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
404 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
405 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
406 case AMDGPU::S_LOAD_DWORDX4_IMM:
407 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
408 case AMDGPU::GLOBAL_LOAD_DWORDX4:
409 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
410 case AMDGPU::GLOBAL_STORE_DWORDX4:
411 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
412 case AMDGPU::FLAT_LOAD_DWORDX4:
413 case AMDGPU::FLAT_STORE_DWORDX4:
414 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
415 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
417 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
418 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
419 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
420 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
421 case AMDGPU::S_LOAD_DWORDX8_IMM:
422 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
424 case AMDGPU::DS_READ_B32:
425 case AMDGPU::DS_READ_B32_gfx9:
426 case AMDGPU::DS_WRITE_B32:
427 case AMDGPU::DS_WRITE_B32_gfx9:
429 case AMDGPU::DS_READ_B64:
430 case AMDGPU::DS_READ_B64_gfx9:
431 case AMDGPU::DS_WRITE_B64:
432 case AMDGPU::DS_WRITE_B64_gfx9:
447 case AMDGPU::BUFFER_LOAD_DWORD_BOTHEN:
448 case AMDGPU::BUFFER_LOAD_DWORD_BOTHEN_exact:
449 case AMDGPU::BUFFER_LOAD_DWORD_IDXEN:
450 case AMDGPU::BUFFER_LOAD_DWORD_IDXEN_exact:
451 case AMDGPU::BUFFER_LOAD_DWORD_OFFEN:
452 case AMDGPU::BUFFER_LOAD_DWORD_OFFEN_exact:
453 case AMDGPU::BUFFER_LOAD_DWORD_OFFSET:
454 case AMDGPU::BUFFER_LOAD_DWORD_OFFSET_exact:
455 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_BOTHEN:
456 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_BOTHEN_exact:
457 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_IDXEN:
458 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_IDXEN_exact:
459 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN:
460 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN_exact:
461 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET:
462 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET_exact:
464 case AMDGPU::BUFFER_STORE_DWORD_BOTHEN:
465 case AMDGPU::BUFFER_STORE_DWORD_BOTHEN_exact:
466 case AMDGPU::BUFFER_STORE_DWORD_IDXEN:
467 case AMDGPU::BUFFER_STORE_DWORD_IDXEN_exact:
468 case AMDGPU::BUFFER_STORE_DWORD_OFFEN:
469 case AMDGPU::BUFFER_STORE_DWORD_OFFEN_exact:
470 case AMDGPU::BUFFER_STORE_DWORD_OFFSET:
471 case AMDGPU::BUFFER_STORE_DWORD_OFFSET_exact:
472 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_BOTHEN:
473 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_BOTHEN_exact:
474 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_IDXEN:
475 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_IDXEN_exact:
476 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN:
477 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN_exact:
478 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET:
479 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET_exact:
492 if (
TII.get(
Opc).mayStore() || !
TII.get(
Opc).mayLoad() ||
501 case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN:
502 case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN_exact:
503 case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN:
504 case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN_exact:
505 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN:
506 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN_exact:
507 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET:
508 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET_exact:
509 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN:
510 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN_exact:
511 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN:
512 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN_exact:
513 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN:
514 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN_exact:
515 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET:
516 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET_exact:
518 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN:
519 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN_exact:
520 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET:
521 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET_exact:
522 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN:
523 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN_exact:
524 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET:
525 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET_exact:
526 return TBUFFER_STORE;
530 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
531 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
532 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
533 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
534 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
535 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
536 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
537 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
538 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
539 return S_BUFFER_LOAD_IMM;
540 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
541 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
542 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
543 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
544 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
545 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
546 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
547 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
548 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
549 return S_BUFFER_LOAD_SGPR_IMM;
550 case AMDGPU::S_LOAD_DWORD_IMM:
551 case AMDGPU::S_LOAD_DWORDX2_IMM:
552 case AMDGPU::S_LOAD_DWORDX3_IMM:
553 case AMDGPU::S_LOAD_DWORDX4_IMM:
554 case AMDGPU::S_LOAD_DWORDX8_IMM:
555 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
556 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
557 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
558 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
560 case AMDGPU::DS_READ_B32:
561 case AMDGPU::DS_READ_B32_gfx9:
562 case AMDGPU::DS_READ_B64:
563 case AMDGPU::DS_READ_B64_gfx9:
565 case AMDGPU::DS_WRITE_B32:
566 case AMDGPU::DS_WRITE_B32_gfx9:
567 case AMDGPU::DS_WRITE_B64:
568 case AMDGPU::DS_WRITE_B64_gfx9:
570 case AMDGPU::GLOBAL_LOAD_DWORD:
571 case AMDGPU::GLOBAL_LOAD_DWORDX2:
572 case AMDGPU::GLOBAL_LOAD_DWORDX3:
573 case AMDGPU::GLOBAL_LOAD_DWORDX4:
574 case AMDGPU::FLAT_LOAD_DWORD:
575 case AMDGPU::FLAT_LOAD_DWORDX2:
576 case AMDGPU::FLAT_LOAD_DWORDX3:
577 case AMDGPU::FLAT_LOAD_DWORDX4:
579 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
580 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
581 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
582 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
583 return GLOBAL_LOAD_SADDR;
584 case AMDGPU::GLOBAL_STORE_DWORD:
585 case AMDGPU::GLOBAL_STORE_DWORDX2:
586 case AMDGPU::GLOBAL_STORE_DWORDX3:
587 case AMDGPU::GLOBAL_STORE_DWORDX4:
588 case AMDGPU::FLAT_STORE_DWORD:
589 case AMDGPU::FLAT_STORE_DWORDX2:
590 case AMDGPU::FLAT_STORE_DWORDX3:
591 case AMDGPU::FLAT_STORE_DWORDX4:
593 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
594 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
595 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
596 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
597 return GLOBAL_STORE_SADDR;
598 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
599 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
600 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
601 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
602 return FLAT_LOAD_SADDR;
603 case AMDGPU::FLAT_STORE_DWORD_SADDR:
604 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
605 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
606 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
607 return FLAT_STORE_SADDR;
622 return Info->BaseOpcode;
627 case AMDGPU::DS_READ_B32:
628 case AMDGPU::DS_READ_B32_gfx9:
629 case AMDGPU::DS_READ_B64:
630 case AMDGPU::DS_READ_B64_gfx9:
631 case AMDGPU::DS_WRITE_B32:
632 case AMDGPU::DS_WRITE_B32_gfx9:
633 case AMDGPU::DS_WRITE_B64:
634 case AMDGPU::DS_WRITE_B64_gfx9:
636 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
637 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
638 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
639 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
640 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
641 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
642 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
643 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
644 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
645 return AMDGPU::S_BUFFER_LOAD_DWORD_IMM;
646 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
647 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
648 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
649 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
650 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
651 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
652 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
653 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
654 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
655 return AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM;
656 case AMDGPU::S_LOAD_DWORD_IMM:
657 case AMDGPU::S_LOAD_DWORDX2_IMM:
658 case AMDGPU::S_LOAD_DWORDX3_IMM:
659 case AMDGPU::S_LOAD_DWORDX4_IMM:
660 case AMDGPU::S_LOAD_DWORDX8_IMM:
661 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
662 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
663 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
664 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
665 return AMDGPU::S_LOAD_DWORD_IMM;
666 case AMDGPU::GLOBAL_LOAD_DWORD:
667 case AMDGPU::GLOBAL_LOAD_DWORDX2:
668 case AMDGPU::GLOBAL_LOAD_DWORDX3:
669 case AMDGPU::GLOBAL_LOAD_DWORDX4:
670 case AMDGPU::FLAT_LOAD_DWORD:
671 case AMDGPU::FLAT_LOAD_DWORDX2:
672 case AMDGPU::FLAT_LOAD_DWORDX3:
673 case AMDGPU::FLAT_LOAD_DWORDX4:
674 return AMDGPU::FLAT_LOAD_DWORD;
675 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
676 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
677 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
678 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
679 return AMDGPU::GLOBAL_LOAD_DWORD_SADDR;
680 case AMDGPU::GLOBAL_STORE_DWORD:
681 case AMDGPU::GLOBAL_STORE_DWORDX2:
682 case AMDGPU::GLOBAL_STORE_DWORDX3:
683 case AMDGPU::GLOBAL_STORE_DWORDX4:
684 case AMDGPU::FLAT_STORE_DWORD:
685 case AMDGPU::FLAT_STORE_DWORDX2:
686 case AMDGPU::FLAT_STORE_DWORDX3:
687 case AMDGPU::FLAT_STORE_DWORDX4:
688 return AMDGPU::FLAT_STORE_DWORD;
689 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
690 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
691 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
692 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
693 return AMDGPU::GLOBAL_STORE_DWORD_SADDR;
694 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
695 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
696 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
697 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
698 return AMDGPU::FLAT_LOAD_DWORD_SADDR;
699 case AMDGPU::FLAT_STORE_DWORD_SADDR:
700 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
701 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
702 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
703 return AMDGPU::FLAT_STORE_DWORD_SADDR;
714SILoadStoreOptimizer::getCommonInstClass(
const CombineInfo &CI,
715 const CombineInfo &Paired) {
716 assert(CI.InstClass == Paired.InstClass);
718 if ((CI.InstClass == FLAT_LOAD || CI.InstClass == FLAT_STORE) &&
720 return (CI.InstClass == FLAT_STORE) ? GLOBAL_STORE : GLOBAL_LOAD;
734 Result.SOffset =
true;
740 int VAddr0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr0);
741 if (VAddr0Idx >= 0) {
742 AMDGPU::OpName RsrcName =
743 TII.isMIMG(
Opc) ? AMDGPU::OpName::srsrc : AMDGPU::OpName::rsrc;
744 int RsrcIdx = AMDGPU::getNamedOperandIdx(
Opc, RsrcName);
745 Result.NumVAddrs = RsrcIdx - VAddr0Idx;
762 Result.SOffset =
true;
770 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
771 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
772 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
773 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
774 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
775 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
776 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
777 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
778 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
779 Result.SOffset =
true;
781 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
782 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
783 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
784 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
785 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
786 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
787 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
788 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
789 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
790 case AMDGPU::S_LOAD_DWORD_IMM:
791 case AMDGPU::S_LOAD_DWORDX2_IMM:
792 case AMDGPU::S_LOAD_DWORDX3_IMM:
793 case AMDGPU::S_LOAD_DWORDX4_IMM:
794 case AMDGPU::S_LOAD_DWORDX8_IMM:
795 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
796 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
797 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
798 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
801 case AMDGPU::DS_READ_B32:
802 case AMDGPU::DS_READ_B64:
803 case AMDGPU::DS_READ_B32_gfx9:
804 case AMDGPU::DS_READ_B64_gfx9:
805 case AMDGPU::DS_WRITE_B32:
806 case AMDGPU::DS_WRITE_B64:
807 case AMDGPU::DS_WRITE_B32_gfx9:
808 case AMDGPU::DS_WRITE_B64_gfx9:
811 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
812 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
813 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
814 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
815 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
816 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
817 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
818 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
819 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
820 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
821 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
822 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
823 case AMDGPU::FLAT_STORE_DWORD_SADDR:
824 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
825 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
826 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
829 case AMDGPU::GLOBAL_LOAD_DWORD:
830 case AMDGPU::GLOBAL_LOAD_DWORDX2:
831 case AMDGPU::GLOBAL_LOAD_DWORDX3:
832 case AMDGPU::GLOBAL_LOAD_DWORDX4:
833 case AMDGPU::GLOBAL_STORE_DWORD:
834 case AMDGPU::GLOBAL_STORE_DWORDX2:
835 case AMDGPU::GLOBAL_STORE_DWORDX3:
836 case AMDGPU::GLOBAL_STORE_DWORDX4:
837 case AMDGPU::FLAT_LOAD_DWORD:
838 case AMDGPU::FLAT_LOAD_DWORDX2:
839 case AMDGPU::FLAT_LOAD_DWORDX3:
840 case AMDGPU::FLAT_LOAD_DWORDX4:
841 case AMDGPU::FLAT_STORE_DWORD:
842 case AMDGPU::FLAT_STORE_DWORDX2:
843 case AMDGPU::FLAT_STORE_DWORDX3:
844 case AMDGPU::FLAT_STORE_DWORDX4:
851 const SILoadStoreOptimizer &LSO) {
853 unsigned Opc =
MI->getOpcode();
854 InstClass = getInstClass(
Opc, *LSO.TII);
856 if (InstClass == UNKNOWN)
859 DataRC = LSO.getDataRegClass(*
MI);
864 (
Opc == AMDGPU::DS_READ_B64 ||
Opc == AMDGPU::DS_READ_B64_gfx9) ? 8
869 (
Opc == AMDGPU::DS_WRITE_B64 ||
Opc == AMDGPU::DS_WRITE_B64_gfx9) ? 8
872 case S_BUFFER_LOAD_IMM:
873 case S_BUFFER_LOAD_SGPR_IMM:
882 if (InstClass == MIMG) {
887 int OffsetIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::offset);
888 Offset =
I->getOperand(OffsetIdx).getImm();
891 if (InstClass == TBUFFER_LOAD || InstClass == TBUFFER_STORE) {
895 EltSize = Info->BitsPerComp / 8;
898 Width = getOpcodeWidth(*
I, *LSO.TII);
900 if ((InstClass == DS_READ) || (InstClass == DS_WRITE)) {
902 }
else if (InstClass != MIMG) {
906 AddressRegs Regs = getRegs(
Opc, *LSO.TII);
910 for (
unsigned J = 0; J < Regs.NumVAddrs; J++)
911 AddrIdx[NumAddresses++] =
912 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr0) + J;
914 AddrIdx[NumAddresses++] =
915 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::addr);
917 AddrIdx[NumAddresses++] =
918 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::sbase);
920 AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
921 Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::rsrc : AMDGPU::OpName::srsrc);
923 AddrIdx[NumAddresses++] =
924 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::soffset);
926 AddrIdx[NumAddresses++] =
927 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
929 AddrIdx[NumAddresses++] =
930 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
932 AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
933 Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::samp : AMDGPU::OpName::ssamp);
934 assert(NumAddresses <= MaxAddressRegs);
936 for (
unsigned J = 0; J < NumAddresses; J++)
937 AddrReg[J] = &
I->getOperand(AddrIdx[J]);
943 "SI Load Store Optimizer",
false,
false)
948char SILoadStoreOptimizerLegacy::ID = 0;
953 return new SILoadStoreOptimizerLegacy();
959 for (
const auto &
Op :
MI.operands()) {
969bool SILoadStoreOptimizer::canSwapInstructions(
970 const DenseSet<Register> &ARegDefs,
const DenseSet<Register> &ARegUses,
971 const MachineInstr &
A,
const MachineInstr &
B)
const {
972 if (
A.mayLoadOrStore() &&
B.mayLoadOrStore() &&
973 (
A.mayStore() ||
B.mayStore()) &&
A.mayAlias(AA,
B,
true))
975 for (
const auto &BOp :
B.operands()) {
978 if ((BOp.isDef() || BOp.readsReg()) && ARegDefs.
contains(BOp.getReg()))
980 if (BOp.isDef() && ARegUses.
contains(BOp.getReg()))
989SILoadStoreOptimizer::combineKnownAdjacentMMOs(
const CombineInfo &CI,
990 const CombineInfo &Paired) {
991 const MachineMemOperand *MMOa = *CI.I->memoperands_begin();
992 const MachineMemOperand *MMOb = *Paired.I->memoperands_begin();
1006 MachineFunction *MF = CI.I->getMF();
1010bool SILoadStoreOptimizer::dmasksCanBeCombined(
const CombineInfo &CI,
1011 const SIInstrInfo &
TII,
1012 const CombineInfo &Paired) {
1013 assert(CI.InstClass == MIMG);
1016 const auto *TFEOp =
TII.getNamedOperand(*CI.I, AMDGPU::OpName::tfe);
1017 const auto *LWEOp =
TII.getNamedOperand(*CI.I, AMDGPU::OpName::lwe);
1019 if ((TFEOp && TFEOp->getImm()) || (LWEOp && LWEOp->getImm()))
1023 AMDGPU::OpName OperandsToMatch[] = {
1024 AMDGPU::OpName::cpol, AMDGPU::OpName::d16, AMDGPU::OpName::unorm,
1025 AMDGPU::OpName::da, AMDGPU::OpName::r128, AMDGPU::OpName::a16};
1027 for (AMDGPU::OpName
op : OperandsToMatch) {
1028 int Idx = AMDGPU::getNamedOperandIdx(CI.I->getOpcode(),
op);
1029 if (AMDGPU::getNamedOperandIdx(Paired.I->getOpcode(),
op) != Idx)
1032 CI.I->getOperand(Idx).getImm() != Paired.I->getOperand(Idx).getImm())
1037 unsigned MaxMask = std::max(CI.DMask, Paired.DMask);
1038 unsigned MinMask = std::min(CI.DMask, Paired.DMask);
1044 if ((1u << AllowedBitsForMin) <= MinMask)
1051 unsigned ComponentCount,
1053 if (ComponentCount > 4)
1072 return NewFormatInfo->
Format;
1085bool SILoadStoreOptimizer::offsetsCanBeCombined(CombineInfo &CI,
1086 const GCNSubtarget &STI,
1087 CombineInfo &Paired,
1089 assert(CI.InstClass != MIMG);
1093 if (CI.Offset == Paired.Offset)
1097 if ((CI.Offset % CI.EltSize != 0) || (Paired.Offset % CI.EltSize != 0))
1100 if (CI.InstClass == TBUFFER_LOAD || CI.InstClass == TBUFFER_STORE) {
1102 const llvm::AMDGPU::GcnBufferFormatInfo *Info0 =
1104 const llvm::AMDGPU::GcnBufferFormatInfo *Info1 =
1116 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1117 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1118 NumCombinedComponents = 4;
1126 unsigned ElemIndex0 = CI.Offset / CI.EltSize;
1127 unsigned ElemIndex1 = Paired.Offset / Paired.EltSize;
1128 if (ElemIndex0 + CI.Width != ElemIndex1 &&
1129 ElemIndex1 + Paired.Width != ElemIndex0)
1135 unsigned MergedBytes = CI.EltSize * NumCombinedComponents;
1136 unsigned RequiredAlign = std::min(MergedBytes, 4u);
1137 unsigned MinOff = std::min(CI.Offset, Paired.Offset);
1138 if (MinOff % RequiredAlign != 0)
1144 uint32_t EltOffset0 = CI.Offset / CI.EltSize;
1145 uint32_t EltOffset1 = Paired.Offset / CI.EltSize;
1150 if ((CI.InstClass != DS_READ) && (CI.InstClass != DS_WRITE)) {
1151 if (EltOffset0 + CI.Width != EltOffset1 &&
1152 EltOffset1 + Paired.Width != EltOffset0)
1158 if (CI.InstClass == S_LOAD_IMM || CI.InstClass == S_BUFFER_LOAD_IMM ||
1159 CI.InstClass == S_BUFFER_LOAD_SGPR_IMM) {
1165 if (CI.Width != Paired.Width &&
1166 (CI.Width < Paired.Width) == (CI.Offset < Paired.Offset))
1174 if ((EltOffset0 % 64 == 0) && (EltOffset1 % 64) == 0 &&
1177 CI.Offset = EltOffset0 / 64;
1178 Paired.Offset = EltOffset1 / 64;
1187 CI.Offset = EltOffset0;
1188 Paired.Offset = EltOffset1;
1194 uint32_t Min = std::min(EltOffset0, EltOffset1);
1195 uint32_t
Max = std::max(EltOffset0, EltOffset1);
1198 if (((Max - Min) & ~Mask) == 0) {
1207 CI.BaseOff = BaseOff * CI.EltSize;
1208 CI.Offset = (EltOffset0 - BaseOff) / 64;
1209 Paired.Offset = (EltOffset1 - BaseOff) / 64;
1221 CI.BaseOff = BaseOff * CI.EltSize;
1222 CI.Offset = EltOffset0 - BaseOff;
1223 Paired.Offset = EltOffset1 - BaseOff;
1231bool SILoadStoreOptimizer::widthsFit(
const GCNSubtarget &STM,
1232 const CombineInfo &CI,
1233 const CombineInfo &Paired) {
1234 const unsigned Width = (CI.Width + Paired.Width);
1235 switch (CI.InstClass) {
1238 case S_BUFFER_LOAD_IMM:
1239 case S_BUFFER_LOAD_SGPR_IMM:
1249 return STM.hasScalarDwordx3Loads();
1255SILoadStoreOptimizer::getDataRegClass(
const MachineInstr &
MI)
const {
1256 if (
const auto *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1257 return TRI->getRegClassForReg(*MRI, Dst->getReg());
1259 if (
const auto *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdata)) {
1260 return TRI->getRegClassForReg(*MRI, Src->getReg());
1262 if (
const auto *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::data0)) {
1263 return TRI->getRegClassForReg(*MRI, Src->getReg());
1265 if (
const auto *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst)) {
1266 return TRI->getRegClassForReg(*MRI, Dst->getReg());
1268 if (
const auto *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdata)) {
1269 return TRI->getRegClassForReg(*MRI, Src->getReg());
1276SILoadStoreOptimizer::CombineInfo *
1277SILoadStoreOptimizer::checkAndPrepareMerge(CombineInfo &CI,
1278 CombineInfo &Paired) {
1281 if (CI.InstClass == UNKNOWN || Paired.InstClass == UNKNOWN)
1283 assert(CI.InstClass == Paired.InstClass);
1285 if (getInstSubclass(CI.I->getOpcode(), *
TII) !=
1286 getInstSubclass(Paired.I->getOpcode(), *
TII))
1291 if (CI.InstClass == MIMG) {
1292 if (!dmasksCanBeCombined(CI, *
TII, Paired))
1295 if (!widthsFit(*STM, CI, Paired) || !offsetsCanBeCombined(CI, *STM, Paired))
1299 DenseSet<Register> RegDefs;
1300 DenseSet<Register> RegUses;
1302 if (CI.I->mayLoad()) {
1306 if (!canSwapInstructions(RegDefs, RegUses, *Paired.I, *
MBBI))
1314 if (!canSwapInstructions(RegDefs, RegUses, *CI.I, *
MBBI))
1324 if (CI.InstClass == DS_READ || CI.InstClass == DS_WRITE)
1325 offsetsCanBeCombined(CI, *STM, Paired,
true);
1327 if (CI.InstClass == DS_WRITE) {
1335 const MachineOperand *Data0 =
1336 TII->getNamedOperand(*CI.I, AMDGPU::OpName::data0);
1337 const MachineOperand *Data1 =
1338 TII->getNamedOperand(*Paired.I, AMDGPU::OpName::data0);
1340 const MCInstrDesc &Write2Opc =
TII->get(getWrite2Opcode(CI));
1341 int Data0Idx = AMDGPU::getNamedOperandIdx(Write2Opc.
getOpcode(),
1342 AMDGPU::OpName::data0);
1343 int Data1Idx = AMDGPU::getNamedOperandIdx(Write2Opc.
getOpcode(),
1344 AMDGPU::OpName::data1);
1350 if (
unsigned SubReg = Data0->
getSubReg()) {
1355 if (
unsigned SubReg = Data1->
getSubReg()) {
1373void SILoadStoreOptimizer::copyToDestRegs(
1374 CombineInfo &CI, CombineInfo &Paired,
1376 AMDGPU::OpName OpName,
Register DestReg)
const {
1377 MachineBasicBlock *
MBB = CI.I->getParent();
1379 auto [SubRegIdx0, SubRegIdx1] = getSubRegIdxs(CI, Paired);
1382 const MCInstrDesc &CopyDesc =
TII->get(TargetOpcode::COPY);
1383 auto *Dest0 =
TII->getNamedOperand(*CI.I, OpName);
1384 auto *Dest1 =
TII->getNamedOperand(*Paired.I, OpName);
1389 Dest0->setIsEarlyClobber(
false);
1390 Dest1->setIsEarlyClobber(
false);
1394 .
addReg(DestReg, {}, SubRegIdx0);
1397 .
addReg(DestReg, RegState::Kill, SubRegIdx1);
1403SILoadStoreOptimizer::copyFromSrcRegs(CombineInfo &CI, CombineInfo &Paired,
1406 AMDGPU::OpName OpName)
const {
1407 MachineBasicBlock *
MBB = CI.I->getParent();
1409 auto [SubRegIdx0, SubRegIdx1] = getSubRegIdxs(CI, Paired);
1415 const auto *Src0 =
TII->getNamedOperand(*CI.I, OpName);
1416 const auto *Src1 =
TII->getNamedOperand(*Paired.I, OpName);
1418 BuildMI(*
MBB, InsertBefore,
DL,
TII->get(AMDGPU::REG_SEQUENCE), SrcReg)
1427unsigned SILoadStoreOptimizer::read2Opcode(
unsigned EltSize)
const {
1429 return (EltSize == 4) ? AMDGPU::DS_READ2_B32 : AMDGPU::DS_READ2_B64;
1430 return (EltSize == 4) ? AMDGPU::DS_READ2_B32_gfx9 : AMDGPU::DS_READ2_B64_gfx9;
1433unsigned SILoadStoreOptimizer::read2ST64Opcode(
unsigned EltSize)
const {
1435 return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32 : AMDGPU::DS_READ2ST64_B64;
1437 return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32_gfx9
1438 : AMDGPU::DS_READ2ST64_B64_gfx9;
1442SILoadStoreOptimizer::mergeRead2Pair(CombineInfo &CI, CombineInfo &Paired,
1444 MachineBasicBlock *
MBB = CI.I->getParent();
1448 const auto *AddrReg =
TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);
1450 unsigned NewOffset0 = std::min(CI.Offset, Paired.Offset);
1451 unsigned NewOffset1 = std::max(CI.Offset, Paired.Offset);
1453 CI.UseST64 ? read2ST64Opcode(CI.EltSize) : read2Opcode(CI.EltSize);
1456 (NewOffset0 != NewOffset1) &&
"Computed offset doesn't fit");
1458 const MCInstrDesc &Read2Desc =
TII->get(
Opc);
1467 unsigned BaseSubReg = AddrReg->getSubReg();
1475 BaseRegFlags = RegState::Kill;
1477 TII->getAddNoCarry(*
MBB, InsertBefore,
DL, BaseReg)
1479 .addReg(AddrReg->getReg(), {}, BaseSubReg)
1484 MachineInstrBuilder Read2 =
1486 .
addReg(BaseReg, BaseRegFlags, BaseSubReg)
1492 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdst, DestReg);
1494 CI.I->eraseFromParent();
1495 Paired.I->eraseFromParent();
1501unsigned SILoadStoreOptimizer::write2Opcode(
unsigned EltSize)
const {
1503 return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32 : AMDGPU::DS_WRITE2_B64;
1504 return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32_gfx9
1505 : AMDGPU::DS_WRITE2_B64_gfx9;
1508unsigned SILoadStoreOptimizer::write2ST64Opcode(
unsigned EltSize)
const {
1510 return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32
1511 : AMDGPU::DS_WRITE2ST64_B64;
1513 return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32_gfx9
1514 : AMDGPU::DS_WRITE2ST64_B64_gfx9;
1517unsigned SILoadStoreOptimizer::getWrite2Opcode(
const CombineInfo &CI)
const {
1518 return CI.UseST64 ? write2ST64Opcode(CI.EltSize) : write2Opcode(CI.EltSize);
1522 CombineInfo &CI, CombineInfo &Paired,
1524 MachineBasicBlock *
MBB = CI.I->getParent();
1528 const MachineOperand *AddrReg =
1529 TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);
1530 const MachineOperand *Data0 =
1531 TII->getNamedOperand(*CI.I, AMDGPU::OpName::data0);
1532 const MachineOperand *Data1 =
1533 TII->getNamedOperand(*Paired.I, AMDGPU::OpName::data0);
1535 unsigned NewOffset0 = CI.Offset;
1536 unsigned NewOffset1 = Paired.Offset;
1537 unsigned Opc = getWrite2Opcode(CI);
1539 if (NewOffset0 > NewOffset1) {
1546 (NewOffset0 != NewOffset1) &&
"Computed offset doesn't fit");
1548 const MCInstrDesc &Write2Desc =
TII->get(
Opc);
1553 unsigned BaseSubReg = AddrReg->
getSubReg();
1561 BaseRegFlags = RegState::Kill;
1563 TII->getAddNoCarry(*
MBB, InsertBefore,
DL, BaseReg)
1565 .addReg(AddrReg->
getReg(), {}, BaseSubReg)
1570 MachineInstrBuilder Write2 =
1572 .
addReg(BaseReg, BaseRegFlags, BaseSubReg)
1580 CI.I->eraseFromParent();
1581 Paired.I->eraseFromParent();
1583 LLVM_DEBUG(
dbgs() <<
"Inserted write2 inst: " << *Write2 <<
'\n');
1588SILoadStoreOptimizer::mergeImagePair(CombineInfo &CI, CombineInfo &Paired,
1590 MachineBasicBlock *
MBB = CI.I->getParent();
1594 const unsigned Opcode = getNewOpcode(CI, Paired);
1599 unsigned MergedDMask = CI.DMask | Paired.DMask;
1601 AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), AMDGPU::OpName::dmask);
1603 auto MIB =
BuildMI(*
MBB, InsertBefore,
DL,
TII->get(Opcode), DestReg);
1604 for (
unsigned I = 1,
E = (*CI.I).getNumOperands();
I !=
E; ++
I) {
1606 MIB.addImm(MergedDMask);
1608 MIB.add((*CI.I).getOperand(
I));
1614 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1616 MachineInstr *
New = MIB.addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1618 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata, DestReg);
1620 CI.I->eraseFromParent();
1621 Paired.I->eraseFromParent();
1626 CombineInfo &CI, CombineInfo &Paired,
1628 MachineBasicBlock *
MBB = CI.I->getParent();
1632 const unsigned Opcode = getNewOpcode(CI, Paired);
1637 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1642 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1644 MachineInstrBuilder
New =
1646 .
add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::sbase));
1647 if (CI.InstClass == S_BUFFER_LOAD_SGPR_IMM)
1648 New.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset));
1649 New.addImm(MergedOffset);
1650 New.addImm(CI.CPol).addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1652 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::sdst, DestReg);
1654 CI.I->eraseFromParent();
1655 Paired.I->eraseFromParent();
1660 CombineInfo &CI, CombineInfo &Paired,
1662 MachineBasicBlock *
MBB = CI.I->getParent();
1667 const unsigned Opcode = getNewOpcode(CI, Paired);
1673 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1675 auto MIB =
BuildMI(*
MBB, InsertBefore,
DL,
TII->get(Opcode), DestReg);
1677 AddressRegs Regs = getRegs(Opcode, *
TII);
1680 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1685 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1688 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1689 .add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1690 .addImm(MergedOffset)
1693 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1695 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata, DestReg);
1697 CI.I->eraseFromParent();
1698 Paired.I->eraseFromParent();
1703 CombineInfo &CI, CombineInfo &Paired,
1705 MachineBasicBlock *
MBB = CI.I->getParent();
1710 const unsigned Opcode = getNewOpcode(CI, Paired);
1716 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1718 auto MIB =
BuildMI(*
MBB, InsertBefore,
DL,
TII->get(Opcode), DestReg);
1720 AddressRegs Regs = getRegs(Opcode, *
TII);
1723 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1728 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1729 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1730 NumCombinedComponents = 4;
1731 unsigned JoinedFormat =
1737 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1740 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1741 .add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1742 .addImm(MergedOffset)
1743 .addImm(JoinedFormat)
1746 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1748 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata, DestReg);
1750 CI.I->eraseFromParent();
1751 Paired.I->eraseFromParent();
1756 CombineInfo &CI, CombineInfo &Paired,
1758 MachineBasicBlock *
MBB = CI.I->getParent();
1762 const unsigned Opcode = getNewOpcode(CI, Paired);
1765 copyFromSrcRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata);
1768 .
addReg(SrcReg, RegState::Kill);
1770 AddressRegs Regs = getRegs(Opcode, *
TII);
1773 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1778 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1779 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1780 NumCombinedComponents = 4;
1781 unsigned JoinedFormat =
1787 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1790 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1791 .add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1792 .addImm(std::min(CI.Offset, Paired.Offset))
1793 .addImm(JoinedFormat)
1796 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1798 CI.I->eraseFromParent();
1799 Paired.I->eraseFromParent();
1804 CombineInfo &CI, CombineInfo &Paired,
1806 MachineBasicBlock *
MBB = CI.I->getParent();
1811 const unsigned Opcode = getNewOpcode(CI, Paired);
1816 auto MIB =
BuildMI(*
MBB, InsertBefore,
DL,
TII->get(Opcode), DestReg);
1818 if (
auto *SAddr =
TII->getNamedOperand(*CI.I, AMDGPU::OpName::saddr))
1822 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr))
1823 .addImm(std::min(CI.Offset, Paired.Offset))
1825 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1827 copyToDestRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdst, DestReg);
1829 CI.I->eraseFromParent();
1830 Paired.I->eraseFromParent();
1835 CombineInfo &CI, CombineInfo &Paired,
1837 MachineBasicBlock *
MBB = CI.I->getParent();
1842 const unsigned Opcode = getNewOpcode(CI, Paired);
1845 copyFromSrcRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata);
1848 .
add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr))
1849 .
addReg(SrcReg, RegState::Kill);
1851 if (
auto *SAddr =
TII->getNamedOperand(*CI.I, AMDGPU::OpName::saddr))
1855 MIB.addImm(std::min(CI.Offset, Paired.Offset))
1857 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1859 CI.I->eraseFromParent();
1860 Paired.I->eraseFromParent();
1869 (MMOs.
size() != 1 || MMOs[0]->
getAlign().value() < Width * 4);
1872unsigned SILoadStoreOptimizer::getNewOpcode(
const CombineInfo &CI,
1873 const CombineInfo &Paired) {
1874 const unsigned Width = CI.Width + Paired.Width;
1876 switch (getCommonInstClass(CI, Paired)) {
1878 assert(CI.InstClass == BUFFER_LOAD || CI.InstClass == BUFFER_STORE);
1889 case S_BUFFER_LOAD_IMM: {
1892 bool NeedsConstrainedOpc =
1898 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec
1899 : AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM;
1901 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec
1902 : AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM;
1904 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec
1905 : AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM;
1907 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec
1908 : AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM;
1911 case S_BUFFER_LOAD_SGPR_IMM: {
1914 bool NeedsConstrainedOpc =
1920 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec
1921 : AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM;
1923 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec
1924 : AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM;
1926 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec
1927 : AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM;
1929 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec
1930 : AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM;
1936 bool NeedsConstrainedOpc =
1942 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX2_IMM_ec
1943 : AMDGPU::S_LOAD_DWORDX2_IMM;
1945 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX3_IMM_ec
1946 : AMDGPU::S_LOAD_DWORDX3_IMM;
1948 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX4_IMM_ec
1949 : AMDGPU::S_LOAD_DWORDX4_IMM;
1951 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX8_IMM_ec
1952 : AMDGPU::S_LOAD_DWORDX8_IMM;
1960 return AMDGPU::GLOBAL_LOAD_DWORDX2;
1962 return AMDGPU::GLOBAL_LOAD_DWORDX3;
1964 return AMDGPU::GLOBAL_LOAD_DWORDX4;
1966 case GLOBAL_LOAD_SADDR:
1971 return AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR;
1973 return AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR;
1975 return AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR;
1982 return AMDGPU::GLOBAL_STORE_DWORDX2;
1984 return AMDGPU::GLOBAL_STORE_DWORDX3;
1986 return AMDGPU::GLOBAL_STORE_DWORDX4;
1988 case GLOBAL_STORE_SADDR:
1993 return AMDGPU::GLOBAL_STORE_DWORDX2_SADDR;
1995 return AMDGPU::GLOBAL_STORE_DWORDX3_SADDR;
1997 return AMDGPU::GLOBAL_STORE_DWORDX4_SADDR;
2004 return AMDGPU::FLAT_LOAD_DWORDX2;
2006 return AMDGPU::FLAT_LOAD_DWORDX3;
2008 return AMDGPU::FLAT_LOAD_DWORDX4;
2015 return AMDGPU::FLAT_STORE_DWORDX2;
2017 return AMDGPU::FLAT_STORE_DWORDX3;
2019 return AMDGPU::FLAT_STORE_DWORDX4;
2021 case FLAT_LOAD_SADDR:
2026 return AMDGPU::FLAT_LOAD_DWORDX2_SADDR;
2028 return AMDGPU::FLAT_LOAD_DWORDX3_SADDR;
2030 return AMDGPU::FLAT_LOAD_DWORDX4_SADDR;
2032 case FLAT_STORE_SADDR:
2037 return AMDGPU::FLAT_STORE_DWORDX2_SADDR;
2039 return AMDGPU::FLAT_STORE_DWORDX3_SADDR;
2041 return AMDGPU::FLAT_STORE_DWORDX4_SADDR;
2050std::pair<unsigned, unsigned>
2051SILoadStoreOptimizer::getSubRegIdxs(
const CombineInfo &CI,
2052 const CombineInfo &Paired) {
2053 assert((CI.InstClass != MIMG ||
2055 CI.Width + Paired.Width)) &&
2061 static const unsigned Idxs[5][4] = {
2062 {AMDGPU::sub0, AMDGPU::sub0_sub1, AMDGPU::sub0_sub1_sub2, AMDGPU::sub0_sub1_sub2_sub3},
2063 {AMDGPU::sub1, AMDGPU::sub1_sub2, AMDGPU::sub1_sub2_sub3, AMDGPU::sub1_sub2_sub3_sub4},
2064 {AMDGPU::sub2, AMDGPU::sub2_sub3, AMDGPU::sub2_sub3_sub4, AMDGPU::sub2_sub3_sub4_sub5},
2065 {AMDGPU::sub3, AMDGPU::sub3_sub4, AMDGPU::sub3_sub4_sub5, AMDGPU::sub3_sub4_sub5_sub6},
2066 {AMDGPU::sub4, AMDGPU::sub4_sub5, AMDGPU::sub4_sub5_sub6, AMDGPU::sub4_sub5_sub6_sub7},
2069 assert(CI.Width >= 1 && CI.Width <= 4);
2070 assert(Paired.Width >= 1 && Paired.Width <= 4);
2073 Idx1 = Idxs[0][Paired.Width - 1];
2074 Idx0 = Idxs[Paired.Width][CI.Width - 1];
2076 Idx0 = Idxs[0][CI.Width - 1];
2077 Idx1 = Idxs[CI.Width][Paired.Width - 1];
2080 return {Idx0, Idx1};
2084SILoadStoreOptimizer::getTargetRegisterClass(
const CombineInfo &CI,
2085 const CombineInfo &Paired)
const {
2086 if (CI.InstClass == S_BUFFER_LOAD_IMM ||
2087 CI.InstClass == S_BUFFER_LOAD_SGPR_IMM || CI.InstClass == S_LOAD_IMM) {
2088 switch (CI.Width + Paired.Width) {
2092 return &AMDGPU::SReg_64_XEXECRegClass;
2094 return &AMDGPU::SGPR_96RegClass;
2096 return &AMDGPU::SGPR_128RegClass;
2098 return &AMDGPU::SGPR_256RegClass;
2100 return &AMDGPU::SGPR_512RegClass;
2106 unsigned BitWidth = 32 * (CI.Width + Paired.Width);
2107 return TRI->isAGPRClass(getDataRegClass(*CI.I))
2113 CombineInfo &CI, CombineInfo &Paired,
2115 MachineBasicBlock *
MBB = CI.I->getParent();
2119 const unsigned Opcode = getNewOpcode(CI, Paired);
2122 copyFromSrcRegs(CI, Paired, InsertBefore,
DL, AMDGPU::OpName::vdata);
2125 .
addReg(SrcReg, RegState::Kill);
2127 AddressRegs Regs = getRegs(Opcode, *
TII);
2130 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
2136 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
2139 MIB.add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
2140 .add(*
TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
2141 .addImm(std::min(CI.Offset, Paired.Offset))
2144 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
2146 CI.I->eraseFromParent();
2147 Paired.I->eraseFromParent();
2152SILoadStoreOptimizer::createRegOrImm(int32_t Val, MachineInstr &
MI)
const {
2153 APInt
V(32, Val,
true);
2154 if (
TII->isInlineConstant(V))
2159 BuildMI(*
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc(),
2160 TII->get(AMDGPU::S_MOV_B32),
Reg)
2168Register SILoadStoreOptimizer::computeBase(MachineInstr &
MI,
2169 const MemAddress &Addr)
const {
2170 MachineBasicBlock *
MBB =
MI.getParent();
2177 if (Addr.Base.UseV64Pattern) {
2179 TII->getRegClass(
TII->get(AMDGPU::V_ADD_U64_e64), 0));
2183 MachineInstr *MovOffset =
2187 MachineInstr *
Add64 =
2190 .
addReg(OffsetReg, RegState::Kill)
2201 assert((
TRI->getRegSizeInBits(Addr.Base.LoReg, *MRI) == 32 ||
2202 Addr.Base.LoSubReg) &&
2203 "Expected 32-bit Base-Register-Low!!");
2205 assert((
TRI->getRegSizeInBits(Addr.Base.HiReg, *MRI) == 32 ||
2206 Addr.Base.HiSubReg) &&
2207 "Expected 32-bit Base-Register-Hi!!");
2209 MachineOperand OffsetLo = createRegOrImm(
static_cast<int32_t
>(Addr.Offset),
MI);
2210 MachineOperand OffsetHi =
2211 createRegOrImm(
static_cast<int32_t
>(Addr.Offset >> 32),
MI);
2213 const auto *CarryRC =
TRI->getWaveMaskRegClass();
2219 MachineInstr *LoHalf =
2221 .
addReg(CarryReg, RegState::Define)
2222 .
addReg(Addr.Base.LoReg, {}, Addr.Base.LoSubReg)
2226 MachineInstr *HiHalf =
2228 .
addReg(DeadCarryReg, RegState::Define | RegState::Dead)
2229 .
addReg(Addr.Base.HiReg, {}, Addr.Base.HiSubReg)
2231 .
addReg(CarryReg, RegState::Kill)
2235 MachineInstr *FullBase =
2246 dbgs() <<
" " << *HiHalf <<
"\n";
2247 dbgs() <<
" " << *FullBase <<
"\n\n";);
2253void SILoadStoreOptimizer::updateBaseAndOffset(MachineInstr &
MI,
2255 int32_t NewOffset)
const {
2256 auto *
Base =
TII->getNamedOperand(
MI, AMDGPU::OpName::vaddr);
2257 Base->setReg(NewBase);
2258 Base->setIsKill(
false);
2259 TII->getNamedOperand(
MI, AMDGPU::OpName::offset)->setImm(NewOffset);
2265bool SILoadStoreOptimizer::processBaseWithConstOffset64(
2266 MachineInstr *AddDef,
const MachineOperand &
Base, MemAddress &Addr)
const {
2270 MachineOperand *Src0 =
TII->getNamedOperand(*AddDef, AMDGPU::OpName::src0);
2271 MachineOperand *Src1 =
TII->getNamedOperand(*AddDef, AMDGPU::OpName::src1);
2273 const MachineOperand *BaseOp =
nullptr;
2275 auto Offset =
TII->getImmOrMaterializedImm(*Src1);
2286 Addr.Base.LoReg = BaseOp->
getReg();
2287 Addr.Base.UseV64Pattern =
true;
2305void SILoadStoreOptimizer::processBaseWithConstOffset(
const MachineOperand &
Base,
2306 MemAddress &Addr)
const {
2315 if (
Def->getOpcode() == AMDGPU::V_ADD_U64_e64) {
2316 if (processBaseWithConstOffset64(Def,
Base, Addr))
2321 if (
Def->getOpcode() != AMDGPU::REG_SEQUENCE ||
Def->getNumOperands() != 5)
2324 MachineOperand BaseLo =
Def->getOperand(1);
2325 MachineOperand BaseHi =
Def->getOperand(3);
2332 if (!BaseLoDef || BaseLoDef->
getOpcode() != AMDGPU::V_ADD_CO_U32_e64 ||
2333 !BaseHiDef || BaseHiDef->
getOpcode() != AMDGPU::V_ADDC_U32_e64)
2336 MachineOperand *Src0 =
TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src0);
2337 MachineOperand *Src1 =
TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src1);
2339 auto Offset0P =
TII->getImmOrMaterializedImm(*Src0);
2343 if (!(Offset0P =
TII->getImmOrMaterializedImm(*Src1)))
2348 if (!BaseLo.
isReg())
2351 Src0 =
TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src0);
2352 Src1 =
TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src1);
2360 uint64_t Offset1 = Src1->
getImm();
2363 if (!BaseHi.
isReg())
2366 Addr.Base.LoReg = BaseLo.
getReg();
2367 Addr.Base.HiReg = BaseHi.
getReg();
2368 Addr.Base.LoSubReg = BaseLo.
getSubReg();
2369 Addr.Base.HiSubReg = BaseHi.
getSubReg();
2370 Addr.Offset = (*Offset0P & 0x00000000ffffffff) | (Offset1 << 32);
2377void SILoadStoreOptimizer::updateAsyncLDSAddress(MachineInstr &
MI,
2378 int32_t OffsetDiff)
const {
2379 if (!
TII->usesASYNC_CNT(
MI) || OffsetDiff == 0)
2382 MachineOperand *LDSAddr =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
2384 LDSAddr =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdata);
2389 MachineBasicBlock &
MBB = *
MI.getParent();
2399bool SILoadStoreOptimizer::promoteConstantOffsetToImm(
2401 MemInfoMap &Visited,
2402 SmallPtrSet<MachineInstr *, 4> &
AnchorList)
const {
2415 ? AMDGPU::FlatAddrSpace::FlatGlobal
2416 : AMDGPU::FlatAddrSpace::FLAT;
2417 bool AllowNegativeOffset =
2418 TII->allowNegativeFlatOffset(FlatVariant) && !
TII->usesASYNC_CNT(
MI);
2422 bool IsOffsetU16 =
TII->usesASYNC_CNT(
MI);
2429 if (
TII->getNamedOperand(
MI, AMDGPU::OpName::offset)->getImm()) {
2435 MachineOperand &
Base = *
TII->getNamedOperand(
MI, AMDGPU::OpName::vaddr);
2436 auto [It,
Inserted] = Visited.try_emplace(&
MI);
2439 processBaseWithConstOffset(
Base, MAddr);
2444 if (MAddr.Offset == 0) {
2445 LLVM_DEBUG(
dbgs() <<
" Failed to extract constant-offset or there are no"
2446 " constant offsets that can be promoted.\n";);
2452 <<
"} Offset: " << MAddr.Offset <<
"\n\n";);
2479 MachineInstr *AnchorInst =
nullptr;
2480 MemAddress AnchorAddr;
2481 uint32_t MaxDist = std::numeric_limits<uint32_t>::min();
2483 bool MIIsAnchor =
false;
2485 MachineBasicBlock *
MBB =
MI.getParent();
2492 MachineInstr &MINext = *
MBBI;
2496 TII->getNamedOperand(MINext, AMDGPU::OpName::offset)->getImm())
2499 const MachineOperand &BaseNext =
2500 *
TII->getNamedOperand(MINext, AMDGPU::OpName::vaddr);
2501 MemAddress MAddrNext;
2502 auto [It,
Inserted] = Visited.try_emplace(&MINext);
2504 processBaseWithConstOffset(BaseNext, MAddrNext);
2505 It->second = MAddrNext;
2507 MAddrNext = It->second;
2509 if (MAddrNext.Base.LoReg != MAddr.Base.LoReg ||
2510 MAddrNext.Base.HiReg != MAddr.Base.HiReg ||
2511 MAddrNext.Base.LoSubReg != MAddr.Base.LoSubReg ||
2512 MAddrNext.Base.HiSubReg != MAddr.Base.HiSubReg)
2515 InstsWCommonBase.
emplace_back(&MINext, MAddrNext.Offset);
2517 if (AllowNegativeOffset) {
2518 int64_t Dist = MAddr.Offset - MAddrNext.Offset;
2519 TargetLoweringBase::AddrMode AM;
2523 (uint32_t)std::abs(Dist) > MaxDist) {
2524 MaxDist = std::abs(Dist);
2526 AnchorAddr = MAddrNext;
2527 AnchorInst = &MINext;
2535 if (!AllowNegativeOffset && !InstsWCommonBase.
empty()) {
2536 for (
auto &[Inst,
Offset] : InstsWCommonBase) {
2537 int64_t Dist = MAddr.Offset -
Offset;
2538 TargetLoweringBase::AddrMode AM;
2543 (!AnchorInst ||
Offset < AnchorAddr.Offset)) {
2544 AnchorAddr = Visited[Inst];
2553 LLVM_DEBUG(
dbgs() <<
" Anchor-Inst(with max-distance from Offset): ";
2554 AnchorInst->
dump());
2556 << AnchorAddr.Offset <<
"\n\n");
2561 int32_t OffsetDiff = MAddr.Offset - AnchorAddr.Offset;
2562 updateBaseAndOffset(
MI,
Base, OffsetDiff);
2563 updateAsyncLDSAddress(
MI, OffsetDiff);
2566 for (
auto [OtherMI, OtherOffset] : InstsWCommonBase) {
2567 TargetLoweringBase::AddrMode AM;
2569 AM.
BaseOffs = OtherOffset - AnchorAddr.Offset;
2572 (AllowNegativeOffset || AM.
BaseOffs >= 0) &&
2576 int32_t OtherOffsetDiff = OtherOffset - AnchorAddr.Offset;
2577 updateBaseAndOffset(*OtherMI,
Base, OtherOffsetDiff);
2578 updateAsyncLDSAddress(*OtherMI, OtherOffsetDiff);
2587 LLVM_DEBUG(
dbgs() <<
" MI is anchor (smallest offset); promoting "
2588 "candidates relative to MI's base.\n");
2591 bool AnyPromoted =
false;
2593 for (
auto [OtherMI, OtherOffset] : InstsWCommonBase) {
2594 int64_t Dist = OtherOffset - MAddr.Offset;
2595 TargetLoweringBase::AddrMode AM;
2602 updateBaseAndOffset(*OtherMI,
Base, Dist);
2603 updateAsyncLDSAddress(*OtherMI, Dist);
2610 TII->getNamedOperand(
MI, AMDGPU::OpName::vaddr)->setIsKill(
false);
2619void SILoadStoreOptimizer::addInstToMergeableList(
const CombineInfo &CI,
2620 std::list<std::list<CombineInfo> > &MergeableInsts)
const {
2621 for (std::list<CombineInfo> &AddrList : MergeableInsts) {
2622 if (AddrList.front().InstClass == CI.InstClass &&
2623 AddrList.front().hasSameBaseAddress(CI)) {
2624 AddrList.emplace_back(CI);
2630 MergeableInsts.emplace_back(1, CI);
2633std::pair<MachineBasicBlock::iterator, bool>
2634SILoadStoreOptimizer::collectMergeableInsts(
2636 MemInfoMap &Visited, SmallPtrSet<MachineInstr *, 4> &
AnchorList,
2637 std::list<std::list<CombineInfo>> &MergeableInsts)
const {
2643 for (; BlockI != End; ++BlockI) {
2644 MachineInstr &
MI = *BlockI;
2648 if (promoteConstantOffsetToImm(
MI, Visited,
AnchorList))
2653 if (
MI.hasOrderedMemoryRef() ||
MI.hasUnmodeledSideEffects()) {
2661 const InstClassEnum InstClass = getInstClass(
MI.getOpcode(), *
TII);
2662 if (InstClass == UNKNOWN)
2667 AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::swz);
2668 if (Swizzled != -1 &&
MI.getOperand(Swizzled).getImm())
2671 if (InstClass == TBUFFER_LOAD || InstClass == TBUFFER_STORE) {
2672 const MachineOperand *Fmt =
2673 TII->getNamedOperand(
MI, AMDGPU::OpName::format);
2681 CI.setMI(
MI, *
this);
2684 if (!CI.hasMergeableAddress(*MRI))
2699 for (std::list<std::list<CombineInfo>>::iterator
I = MergeableInsts.begin(),
2700 E = MergeableInsts.end();
I !=
E;) {
2702 std::list<CombineInfo> &MergeList = *
I;
2703 if (MergeList.size() <= 1) {
2707 I = MergeableInsts.erase(
I);
2715 [] (
const CombineInfo &
A,
const CombineInfo &
B) {
2716 return A.Offset <
B.Offset;
2727bool SILoadStoreOptimizer::optimizeBlock(
2728 std::list<std::list<CombineInfo> > &MergeableInsts) {
2731 for (std::list<std::list<CombineInfo>>::iterator
I = MergeableInsts.begin(),
2732 E = MergeableInsts.end();
I !=
E;) {
2733 std::list<CombineInfo> &MergeList = *
I;
2735 bool OptimizeListAgain =
false;
2736 if (!optimizeInstsWithSameBaseAddr(MergeList, OptimizeListAgain)) {
2740 I = MergeableInsts.erase(
I);
2748 if (!OptimizeListAgain) {
2749 I = MergeableInsts.erase(
I);
2752 OptimizeAgain =
true;
2758SILoadStoreOptimizer::optimizeInstsWithSameBaseAddr(
2759 std::list<CombineInfo> &MergeList,
2760 bool &OptimizeListAgain) {
2761 if (MergeList.empty())
2766 for (
auto I = MergeList.begin(),
Next = std::next(
I);
Next != MergeList.end();
2767 Next = std::next(
I)) {
2772 if ((*First).Order > (*Second).Order)
2774 CombineInfo &CI = *
First;
2775 CombineInfo &Paired = *Second;
2777 CombineInfo *Where = checkAndPrepareMerge(CI, Paired);
2785 LLVM_DEBUG(
dbgs() <<
"Merging: " << *CI.I <<
" with: " << *Paired.I);
2788 switch (CI.InstClass) {
2793 NewMI = mergeRead2Pair(CI, Paired, Where->I);
2796 NewMI = mergeWrite2Pair(CI, Paired, Where->I);
2798 case S_BUFFER_LOAD_IMM:
2799 case S_BUFFER_LOAD_SGPR_IMM:
2801 NewMI = mergeSMemLoadImmPair(CI, Paired, Where->I);
2802 OptimizeListAgain |= CI.Width + Paired.Width < 8;
2805 NewMI = mergeBufferLoadPair(CI, Paired, Where->I);
2806 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2809 NewMI = mergeBufferStorePair(CI, Paired, Where->I);
2810 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2813 NewMI = mergeImagePair(CI, Paired, Where->I);
2814 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2817 NewMI = mergeTBufferLoadPair(CI, Paired, Where->I);
2818 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2821 NewMI = mergeTBufferStorePair(CI, Paired, Where->I);
2822 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2825 case FLAT_LOAD_SADDR:
2827 case GLOBAL_LOAD_SADDR:
2828 NewMI = mergeFlatLoadPair(CI, Paired, Where->I);
2829 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2832 case FLAT_STORE_SADDR:
2834 case GLOBAL_STORE_SADDR:
2835 NewMI = mergeFlatStorePair(CI, Paired, Where->I);
2836 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2839 CI.setMI(NewMI, *
this);
2840 CI.Order = Where->Order;
2844 MergeList.erase(Second);
2850bool SILoadStoreOptimizerLegacy::runOnMachineFunction(MachineFunction &MF) {
2853 return SILoadStoreOptimizer(
2854 &getAnalysis<AAResultsWrapperPass>().getAAResults())
2858bool SILoadStoreOptimizer::run(MachineFunction &MF) {
2878 for (MachineBasicBlock &
MBB : MF) {
2882 bool CollectModified;
2883 std::list<std::list<CombineInfo>> MergeableInsts;
2887 std::tie(SectionEnd, CollectModified) =
2893 OptimizeAgain =
false;
2895 }
while (OptimizeAgain);
2917 bool Changed = SILoadStoreOptimizer(&
AA).run(MF);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
INITIALIZE_PASS(AMDGPUImageIntrinsicOptimizer, DEBUG_TYPE, "AMDGPU Image Intrinsic Optimizer", false, false) char AMDGPUImageIntrinsicOptimizer void addInstToMergeableList(IntrinsicInst *II, SmallVector< SmallVector< IntrinsicInst *, 4 > > &MergeableInsts, const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr)
BasicBlock::iterator collectMergeableInsts(BasicBlock::iterator I, BasicBlock::iterator E, SmallVector< SmallVector< IntrinsicInst *, 4 > > &MergeableInsts)
Provides AMDGPU specific target descriptions.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
static MaybeAlign getAlign(Value *Ptr)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static uint32_t mostAlignedValueInRange(uint32_t Lo, uint32_t Hi)
static bool needsConstrainedOpcode(const GCNSubtarget &STM, ArrayRef< MachineMemOperand * > MMOs, unsigned Width)
static void addDefsUsesToList(const MachineInstr &MI, DenseSet< Register > &RegDefs, DenseSet< Register > &RegUses)
static unsigned getBufferFormatWithCompCount(unsigned OldFormat, unsigned ComponentCount, const GCNSubtarget &STI)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
Represents analyses that only rely on functions' control flow.
static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
bool hasOptNone() const
Do not optimize this function (-O0).
bool loadStoreOptEnabled() const
const SIInstrInfo * getInstrInfo() const override
bool hasDwordx3LoadStores() const
const SITargetLowering * getTargetLowering() const override
bool ldsRequiresM0Init() const
Return if most LDS instructions have an m0 use that require m0 to be initialized.
bool isXNACKEnabled() const
const HexagonRegisterInfo & getRegisterInfo() const
TypeSize getValue() const
unsigned getOpcode() const
Return the opcode number for this descriptor.
An RAII based helper class to modify MachineFunctionProperties when running pass.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void dump() const
A description of a memory reference used in the backend.
LocationSize getSize() const
Return the size in bytes of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Wrapper class representing virtual and physical registers.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
static bool isFLATScratch(const MachineInstr &MI)
static bool isVIMAGE(const MachineInstr &MI)
static bool isFLATGlobal(const MachineInstr &MI)
static bool isVSAMPLE(const MachineInstr &MI)
static bool isFLAT(const MachineInstr &MI)
LLVM_READONLY MachineOperand * getNamedOperand(MachineInstr &MI, AMDGPU::OpName OperandName) const
Returns the operand named Op.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
bool isLegalFlatAddressingMode(const AddrMode &AM, unsigned AddrSpace) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
Represent a constant reference to a string, i.e.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
LLVM_READONLY const MIMGInfo * getMIMGInfo(unsigned Opc)
uint64_t convertSMRDOffsetUnits(const MCSubtargetInfo &ST, uint64_t ByteOffset)
Convert ByteOffset to dwords if the subtarget uses dword SMRD immediate offsets.
bool getMTBUFHasSrsrc(unsigned Opc)
int getMTBUFElements(unsigned Opc)
bool getMTBUFHasSoffset(unsigned Opc)
int getMUBUFOpcode(unsigned BaseOpc, unsigned Elements)
int getMUBUFBaseOpcode(unsigned Opc)
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
int getMTBUFBaseOpcode(unsigned Opc)
bool getMUBUFHasVAddr(unsigned Opc)
int getMTBUFOpcode(unsigned BaseOpc, unsigned Elements)
bool getMUBUFHasSoffset(unsigned Opc)
const MIMGBaseOpcodeInfo * getMIMGBaseOpcode(unsigned Opc)
LLVM_READONLY const MIMGBaseOpcodeInfo * getMIMGBaseOpcodeInfo(unsigned BaseOpcode)
int getMaskedMIMGOp(unsigned Opc, unsigned NewChannels)
bool getMTBUFHasVAddr(unsigned Opc)
int getMUBUFElements(unsigned Opc)
const GcnBufferFormatInfo * getGcnBufferFormatInfo(uint8_t BitsPerComp, uint8_t NumComponents, uint8_t NumFormat, const MCSubtargetInfo &STI)
bool getMUBUFHasSrsrc(unsigned Opc)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Add64
64 bits label addition
NodeAddr< DefNode * > Def
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
RegState
Flags to represent properties of register accesses.
constexpr T maskLeadingOnes(unsigned N)
Create a bitmask with the N left-most bits set to 1, and all other bits set to 0.
FunctionPass * createSILoadStoreOptimizerLegacyPass()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
char & SILoadStoreOptimizerLegacyID
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
DWARFExpression::Operation Op
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
constexpr unsigned BitWidth
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.