54#define DEBUG_TYPE "aarch64-ldst-opt"
56STATISTIC(NumPairCreated,
"Number of load/store pair instructions generated");
57STATISTIC(NumPostFolded,
"Number of post-index updates folded");
58STATISTIC(NumPreFolded,
"Number of pre-index updates folded");
60 "Number of load/store from unscaled generated");
61STATISTIC(NumZeroStoresPromoted,
"Number of narrow zero stores promoted");
62STATISTIC(NumLoadsFromStoresPromoted,
"Number of loads from stores promoted");
63STATISTIC(NumFailedAlignmentCheck,
"Number of load/store pair transformation "
64 "not passed the alignment check");
66 "Number of const offset of index address folded");
68 "Number of UMOV + GPR stores folded to FPR stores");
71 "Controls which pairs are considered for renaming");
73#define AARCH64_LOAD_STORE_OPT_NAME "AArch64 load / store optimization pass"
77using LdStPairFlags =
struct LdStPairFlags {
81 bool MergeForward =
false;
92 std::optional<MCPhysReg> RenameReg;
94 LdStPairFlags() =
default;
96 void setMergeForward(
bool V =
true) { MergeForward = V; }
97 bool getMergeForward()
const {
return MergeForward; }
99 void setSExtIdx(
int V) { SExtIdx = V; }
100 int getSExtIdx()
const {
return SExtIdx; }
102 void setRenameReg(
MCPhysReg R) { RenameReg = R; }
103 void clearRenameReg() { RenameReg = std::nullopt; }
104 std::optional<MCPhysReg> getRenameReg()
const {
return RenameReg; }
107struct AArch64LoadStoreOpt {
121 LdStPairFlags &Flags,
123 bool FindNarrowMerge);
134 const LdStPairFlags &Flags);
140 const LdStPairFlags &Flags);
152 int UnscaledOffset,
unsigned Limit);
174 unsigned BaseReg,
int Offset);
177 unsigned IndexReg,
unsigned &
Offset);
180 std::optional<MachineBasicBlock::iterator>
183 bool IsPreIdx,
bool MergeEither);
233char AArch64LoadStoreOptLegacy::ID = 0;
240static
bool isNarrowStore(
unsigned Opc) {
244 case AArch64::STRBBui:
245 case AArch64::STURBBi:
246 case AArch64::STRHHui:
247 case AArch64::STURHHi:
255 switch (
MI.getOpcode()) {
261 case AArch64::STZ2Gi:
267 bool *IsValidLdStrOpc =
nullptr) {
269 *IsValidLdStrOpc =
true;
273 *IsValidLdStrOpc =
false;
274 return std::numeric_limits<unsigned>::max();
275 case AArch64::STRDui:
276 case AArch64::STURDi:
277 case AArch64::STRDpre:
278 case AArch64::STRQui:
279 case AArch64::STURQi:
280 case AArch64::STRQpre:
281 case AArch64::STRBBui:
282 case AArch64::STURBBi:
283 case AArch64::STRHHui:
284 case AArch64::STURHHi:
285 case AArch64::STRWui:
286 case AArch64::STRWpre:
287 case AArch64::STURWi:
288 case AArch64::STRXui:
289 case AArch64::STRXpre:
290 case AArch64::STURXi:
291 case AArch64::STR_ZXI:
292 case AArch64::LDRDui:
293 case AArch64::LDURDi:
294 case AArch64::LDRDpre:
295 case AArch64::LDRQui:
296 case AArch64::LDURQi:
297 case AArch64::LDRQpre:
298 case AArch64::LDRWui:
299 case AArch64::LDURWi:
300 case AArch64::LDRWpre:
301 case AArch64::LDRXui:
302 case AArch64::LDURXi:
303 case AArch64::LDRXpre:
304 case AArch64::STRSui:
305 case AArch64::STURSi:
306 case AArch64::STRSpre:
307 case AArch64::LDRSui:
308 case AArch64::LDURSi:
309 case AArch64::LDRSpre:
310 case AArch64::LDR_ZXI:
312 case AArch64::LDRSWui:
313 return AArch64::LDRWui;
314 case AArch64::LDURSWi:
315 return AArch64::LDURWi;
316 case AArch64::LDRSWpre:
317 return AArch64::LDRWpre;
325 case AArch64::STRBBui:
326 return AArch64::STRHHui;
327 case AArch64::STRHHui:
328 return AArch64::STRWui;
329 case AArch64::STURBBi:
330 return AArch64::STURHHi;
331 case AArch64::STURHHi:
332 return AArch64::STURWi;
333 case AArch64::STURWi:
334 return AArch64::STURXi;
335 case AArch64::STRWui:
336 return AArch64::STRXui;
344 case AArch64::STRSui:
345 case AArch64::STURSi:
346 return AArch64::STPSi;
347 case AArch64::STRSpre:
348 return AArch64::STPSpre;
349 case AArch64::STRDui:
350 case AArch64::STURDi:
351 return AArch64::STPDi;
352 case AArch64::STRDpre:
353 return AArch64::STPDpre;
354 case AArch64::STRQui:
355 case AArch64::STURQi:
356 case AArch64::STR_ZXI:
357 return AArch64::STPQi;
358 case AArch64::STRQpre:
359 return AArch64::STPQpre;
360 case AArch64::STRWui:
361 case AArch64::STURWi:
362 return AArch64::STPWi;
363 case AArch64::STRWpre:
364 return AArch64::STPWpre;
365 case AArch64::STRXui:
366 case AArch64::STURXi:
367 return AArch64::STPXi;
368 case AArch64::STRXpre:
369 return AArch64::STPXpre;
370 case AArch64::LDRSui:
371 case AArch64::LDURSi:
372 return AArch64::LDPSi;
373 case AArch64::LDRSpre:
374 return AArch64::LDPSpre;
375 case AArch64::LDRDui:
376 case AArch64::LDURDi:
377 return AArch64::LDPDi;
378 case AArch64::LDRDpre:
379 return AArch64::LDPDpre;
380 case AArch64::LDRQui:
381 case AArch64::LDURQi:
382 case AArch64::LDR_ZXI:
383 return AArch64::LDPQi;
384 case AArch64::LDRQpre:
385 return AArch64::LDPQpre;
386 case AArch64::LDRWui:
387 case AArch64::LDURWi:
388 return AArch64::LDPWi;
389 case AArch64::LDRWpre:
390 return AArch64::LDPWpre;
391 case AArch64::LDRXui:
392 case AArch64::LDURXi:
393 return AArch64::LDPXi;
394 case AArch64::LDRXpre:
395 return AArch64::LDPXpre;
396 case AArch64::LDRSWui:
397 case AArch64::LDURSWi:
398 return AArch64::LDPSWi;
399 case AArch64::LDRSWpre:
400 return AArch64::LDPSWpre;
411 case AArch64::LDRBBui:
412 return StOpc == AArch64::STRBBui || StOpc == AArch64::STRHHui ||
413 StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
414 case AArch64::LDURBBi:
415 return StOpc == AArch64::STURBBi || StOpc == AArch64::STURHHi ||
416 StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
417 case AArch64::LDRHHui:
418 return StOpc == AArch64::STRHHui || StOpc == AArch64::STRWui ||
419 StOpc == AArch64::STRXui;
420 case AArch64::LDURHHi:
421 return StOpc == AArch64::STURHHi || StOpc == AArch64::STURWi ||
422 StOpc == AArch64::STURXi;
423 case AArch64::LDRWui:
424 return StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
425 case AArch64::LDURWi:
426 return StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
427 case AArch64::LDRXui:
428 return StOpc == AArch64::STRXui;
429 case AArch64::LDURXi:
430 return StOpc == AArch64::STURXi;
442 case AArch64::STRBui:
443 return AArch64::STRBpre;
444 case AArch64::STRHui:
445 return AArch64::STRHpre;
446 case AArch64::STRSui:
447 return AArch64::STRSpre;
448 case AArch64::STRDui:
449 return AArch64::STRDpre;
450 case AArch64::STRQui:
451 return AArch64::STRQpre;
452 case AArch64::STRBBui:
453 return AArch64::STRBBpre;
454 case AArch64::STRHHui:
455 return AArch64::STRHHpre;
456 case AArch64::STRWui:
457 return AArch64::STRWpre;
458 case AArch64::STRXui:
459 return AArch64::STRXpre;
460 case AArch64::LDRBui:
461 return AArch64::LDRBpre;
462 case AArch64::LDRHui:
463 return AArch64::LDRHpre;
464 case AArch64::LDRSui:
465 return AArch64::LDRSpre;
466 case AArch64::LDRDui:
467 return AArch64::LDRDpre;
468 case AArch64::LDRQui:
469 return AArch64::LDRQpre;
470 case AArch64::LDRBBui:
471 return AArch64::LDRBBpre;
472 case AArch64::LDRHHui:
473 return AArch64::LDRHHpre;
474 case AArch64::LDRWui:
475 return AArch64::LDRWpre;
476 case AArch64::LDRXui:
477 return AArch64::LDRXpre;
478 case AArch64::LDRSWui:
479 return AArch64::LDRSWpre;
481 return AArch64::LDPSpre;
482 case AArch64::LDPSWi:
483 return AArch64::LDPSWpre;
485 return AArch64::LDPDpre;
487 return AArch64::LDPQpre;
489 return AArch64::LDPWpre;
491 return AArch64::LDPXpre;
493 return AArch64::STPSpre;
495 return AArch64::STPDpre;
497 return AArch64::STPQpre;
499 return AArch64::STPWpre;
501 return AArch64::STPXpre;
503 return AArch64::STGPreIndex;
505 return AArch64::STZGPreIndex;
507 return AArch64::ST2GPreIndex;
508 case AArch64::STZ2Gi:
509 return AArch64::STZ2GPreIndex;
511 return AArch64::STGPpre;
520 case AArch64::LDRBroX:
521 return AArch64::LDRBui;
522 case AArch64::LDRBBroX:
523 return AArch64::LDRBBui;
524 case AArch64::LDRSBXroX:
525 return AArch64::LDRSBXui;
526 case AArch64::LDRSBWroX:
527 return AArch64::LDRSBWui;
528 case AArch64::LDRHroX:
529 return AArch64::LDRHui;
530 case AArch64::LDRHHroX:
531 return AArch64::LDRHHui;
532 case AArch64::LDRSHXroX:
533 return AArch64::LDRSHXui;
534 case AArch64::LDRSHWroX:
535 return AArch64::LDRSHWui;
536 case AArch64::LDRWroX:
537 return AArch64::LDRWui;
538 case AArch64::LDRSroX:
539 return AArch64::LDRSui;
540 case AArch64::LDRSWroX:
541 return AArch64::LDRSWui;
542 case AArch64::LDRDroX:
543 return AArch64::LDRDui;
544 case AArch64::LDRXroX:
545 return AArch64::LDRXui;
546 case AArch64::LDRQroX:
547 return AArch64::LDRQui;
555 case AArch64::STRBui:
556 return AArch64::STRBpost;
557 case AArch64::STRHui:
558 return AArch64::STRHpost;
559 case AArch64::STRSui:
560 case AArch64::STURSi:
561 return AArch64::STRSpost;
562 case AArch64::STRDui:
563 case AArch64::STURDi:
564 return AArch64::STRDpost;
565 case AArch64::STRQui:
566 case AArch64::STURQi:
567 return AArch64::STRQpost;
568 case AArch64::STRBBui:
569 return AArch64::STRBBpost;
570 case AArch64::STRHHui:
571 return AArch64::STRHHpost;
572 case AArch64::STRWui:
573 case AArch64::STURWi:
574 return AArch64::STRWpost;
575 case AArch64::STRXui:
576 case AArch64::STURXi:
577 return AArch64::STRXpost;
578 case AArch64::LDRBui:
579 return AArch64::LDRBpost;
580 case AArch64::LDRHui:
581 return AArch64::LDRHpost;
582 case AArch64::LDRSui:
583 case AArch64::LDURSi:
584 return AArch64::LDRSpost;
585 case AArch64::LDRDui:
586 case AArch64::LDURDi:
587 return AArch64::LDRDpost;
588 case AArch64::LDRQui:
589 case AArch64::LDURQi:
590 return AArch64::LDRQpost;
591 case AArch64::LDRBBui:
592 return AArch64::LDRBBpost;
593 case AArch64::LDRHHui:
594 return AArch64::LDRHHpost;
595 case AArch64::LDRWui:
596 case AArch64::LDURWi:
597 return AArch64::LDRWpost;
598 case AArch64::LDRXui:
599 case AArch64::LDURXi:
600 return AArch64::LDRXpost;
601 case AArch64::LDRSWui:
602 return AArch64::LDRSWpost;
604 return AArch64::LDPSpost;
605 case AArch64::LDPSWi:
606 return AArch64::LDPSWpost;
608 return AArch64::LDPDpost;
610 return AArch64::LDPQpost;
612 return AArch64::LDPWpost;
614 return AArch64::LDPXpost;
616 return AArch64::STPSpost;
618 return AArch64::STPDpost;
620 return AArch64::STPQpost;
622 return AArch64::STPWpost;
624 return AArch64::STPXpost;
626 return AArch64::STGPostIndex;
628 return AArch64::STZGPostIndex;
630 return AArch64::ST2GPostIndex;
631 case AArch64::STZ2Gi:
632 return AArch64::STZ2GPostIndex;
634 return AArch64::STGPpost;
641 unsigned OpcB =
MI.getOpcode();
646 case AArch64::STRSpre:
647 return (OpcB == AArch64::STRSui) || (OpcB == AArch64::STURSi);
648 case AArch64::STRDpre:
649 return (OpcB == AArch64::STRDui) || (OpcB == AArch64::STURDi);
650 case AArch64::STRQpre:
651 return (OpcB == AArch64::STRQui) || (OpcB == AArch64::STURQi);
652 case AArch64::STRWpre:
653 return (OpcB == AArch64::STRWui) || (OpcB == AArch64::STURWi);
654 case AArch64::STRXpre:
655 return (OpcB == AArch64::STRXui) || (OpcB == AArch64::STURXi);
656 case AArch64::LDRSpre:
657 return (OpcB == AArch64::LDRSui) || (OpcB == AArch64::LDURSi);
658 case AArch64::LDRDpre:
659 return (OpcB == AArch64::LDRDui) || (OpcB == AArch64::LDURDi);
660 case AArch64::LDRQpre:
661 return (OpcB == AArch64::LDRQui) || (OpcB == AArch64::LDURQi);
662 case AArch64::LDRWpre:
663 return (OpcB == AArch64::LDRWui) || (OpcB == AArch64::LDURWi);
664 case AArch64::LDRXpre:
665 return (OpcB == AArch64::LDRXui) || (OpcB == AArch64::LDURXi);
666 case AArch64::LDRSWpre:
667 return (OpcB == AArch64::LDRSWui) || (OpcB == AArch64::LDURSWi);
673 int &MinOffset,
int &MaxOffset) {
691 unsigned PairedRegOp = 0) {
692 assert(PairedRegOp < 2 &&
"Unexpected register operand idx.");
698 return MI.getOperand(Idx);
707 int UnscaledStOffset =
711 int UnscaledLdOffset =
715 return (UnscaledStOffset <= UnscaledLdOffset) &&
716 (UnscaledLdOffset + LoadSize <= (UnscaledStOffset + StoreSize));
720 unsigned Opc =
MI.getOpcode();
721 return (
Opc == AArch64::STRWui ||
Opc == AArch64::STURWi ||
722 isNarrowStore(
Opc)) &&
727 switch (
MI.getOpcode()) {
731 case AArch64::LDRBBui:
732 case AArch64::LDRHHui:
733 case AArch64::LDRWui:
734 case AArch64::LDRXui:
736 case AArch64::LDURBBi:
737 case AArch64::LDURHHi:
738 case AArch64::LDURWi:
739 case AArch64::LDURXi:
745 unsigned Opc =
MI.getOpcode();
750 case AArch64::STRBui:
751 case AArch64::STRHui:
752 case AArch64::STRSui:
753 case AArch64::STRDui:
754 case AArch64::STRQui:
755 case AArch64::STRXui:
756 case AArch64::STRWui:
757 case AArch64::STRHHui:
758 case AArch64::STRBBui:
759 case AArch64::LDRBui:
760 case AArch64::LDRHui:
761 case AArch64::LDRSui:
762 case AArch64::LDRDui:
763 case AArch64::LDRQui:
764 case AArch64::LDRXui:
765 case AArch64::LDRWui:
766 case AArch64::LDRHHui:
767 case AArch64::LDRBBui:
771 case AArch64::STZ2Gi:
774 case AArch64::STURSi:
775 case AArch64::STURDi:
776 case AArch64::STURQi:
777 case AArch64::STURWi:
778 case AArch64::STURXi:
779 case AArch64::LDURSi:
780 case AArch64::LDURDi:
781 case AArch64::LDURQi:
782 case AArch64::LDURWi:
783 case AArch64::LDURXi:
786 case AArch64::LDPSWi:
815 unsigned Opc =
MI.getOpcode();
821 case AArch64::LDRBroX:
822 case AArch64::LDRBBroX:
823 case AArch64::LDRSBXroX:
824 case AArch64::LDRSBWroX:
827 case AArch64::LDRHroX:
828 case AArch64::LDRHHroX:
829 case AArch64::LDRSHXroX:
830 case AArch64::LDRSHWroX:
833 case AArch64::LDRWroX:
834 case AArch64::LDRSroX:
835 case AArch64::LDRSWroX:
838 case AArch64::LDRDroX:
839 case AArch64::LDRXroX:
842 case AArch64::LDRQroX:
850 switch (
MI.getOpcode()) {
853 case AArch64::ORRWrs:
854 case AArch64::ADDWri:
862 const LdStPairFlags &Flags) {
864 "Expected promotable zero stores.");
872 if (NextI == MergeMI)
875 unsigned Opc =
I->getOpcode();
876 unsigned MergeMIOpc = MergeMI->getOpcode();
877 bool IsScaled = !
TII->hasUnscaledLdStOffset(
Opc);
878 bool IsMergedMIScaled = !
TII->hasUnscaledLdStOffset(MergeMIOpc);
879 int OffsetStride = IsScaled ?
TII->getMemScale(*
I) : 1;
880 int MergeMIOffsetStride = IsMergedMIScaled ?
TII->getMemScale(*MergeMI) : 1;
882 bool MergeForward =
Flags.getMergeForward();
888 const MachineOperand &BaseRegOp =
890 : AArch64InstrInfo::getLdStBaseOp(*
I);
893 int64_t IOffsetInBytes =
895 int64_t MIOffsetInBytes =
900 if (IOffsetInBytes > MIOffsetInBytes)
901 OffsetImm = MIOffsetInBytes;
903 OffsetImm = IOffsetInBytes;
908 if (!
TII->hasUnscaledLdStOffset(NewOpcode)) {
909 int NewOffsetStride =
TII->getMemScale(NewOpcode);
910 assert(((OffsetImm % NewOffsetStride) == 0) &&
911 "Offset should be a multiple of the store memory scale");
912 OffsetImm = OffsetImm / NewOffsetStride;
918 MachineInstrBuilder MIB;
920 .
addReg(isNarrowStore(
Opc) ? AArch64::WZR : AArch64::XZR)
924 .setMIFlags(
I->mergeFlagsWith(*MergeMI));
927 LLVM_DEBUG(
dbgs() <<
"Creating wider store. Replacing instructions:\n ");
936 I->eraseFromParent();
937 MergeMI->eraseFromParent();
947 auto MBB =
MI.getParent();
955 return MOP.isReg() && MOP.isDef() && !MOP.isDebug() && MOP.getReg() &&
956 TRI->regsOverlap(MOP.getReg(), DefReg);
970 if (MOP.isReg() && MOP.isKill())
974 if (MOP.isReg() && !MOP.isKill())
975 Units.
addReg(MOP.getReg());
982 unsigned InstrNumToSet,
989 unsigned OperandNo = 0;
990 bool RegFound =
false;
991 for (
const auto Op : MergedInstr.
operands()) {
992 if (
Op.getReg() ==
Reg) {
1001 {InstrNumToSet, OperandNo});
1007 const LdStPairFlags &Flags) {
1014 if (NextI == Paired)
1017 int SExtIdx =
Flags.getSExtIdx();
1020 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
Opc);
1021 int OffsetStride = IsUnscaled ?
TII->getMemScale(*
I) : 1;
1023 bool MergeForward =
Flags.getMergeForward();
1025 std::optional<MCPhysReg> RenameReg =
Flags.getRenameReg();
1028 DefinedInBB.
addReg(*RenameReg);
1032 auto GetMatchingSubReg =
1035 TRI->sub_and_superregs_inclusive(*RenameReg)) {
1036 if (
C->contains(SubOrSuper))
1042 std::function<bool(MachineInstr &,
bool)> UpdateMIs =
1043 [
this, RegToRename, GetMatchingSubReg, MergeForward](MachineInstr &
MI,
1046 bool SeenDef =
false;
1047 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
1048 MachineOperand &MOP =
MI.getOperand(OpIdx);
1052 (!MergeForward || !SeenDef ||
1054 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
1057 "Need renamable operands");
1060 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
1061 MatchingReg = GetMatchingSubReg(RC);
1065 MatchingReg = GetMatchingSubReg(
1066 TRI->getMinimalPhysRegClass(MOP.
getReg()));
1073 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
1074 MachineOperand &MOP =
MI.getOperand(OpIdx);
1076 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
1079 "Need renamable operands");
1082 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
1083 MatchingReg = GetMatchingSubReg(RC);
1085 MatchingReg = GetMatchingSubReg(
1086 TRI->getMinimalPhysRegClass(MOP.
getReg()));
1088 "Cannot find matching regs for renaming");
1097 TRI, UINT32_MAX, UpdateMIs);
1110 RegToCheck = RegToRename;
1113 MergeForward ? std::next(
I) :
I,
1114 MergeForward ? std::next(Paired) : Paired))
1116 [
this, RegToCheck](
const MachineOperand &MOP) {
1117 return !MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1119 !TRI->regsOverlap(MOP.getReg(), RegToCheck);
1121 "Rename register used between paired instruction, trashing the "
1131 const MachineOperand &BaseRegOp =
1133 : AArch64InstrInfo::getLdStBaseOp(*
I);
1137 bool PairedIsUnscaled =
TII->hasUnscaledLdStOffset(Paired->getOpcode());
1138 if (IsUnscaled != PairedIsUnscaled) {
1142 int MemSize =
TII->getMemScale(*Paired);
1143 if (PairedIsUnscaled) {
1146 assert(!(PairedOffset %
TII->getMemScale(*Paired)) &&
1147 "Offset should be a multiple of the stride!");
1148 PairedOffset /= MemSize;
1150 PairedOffset *= MemSize;
1157 MachineInstr *RtMI, *Rt2MI;
1158 if (
Offset == PairedOffset + OffsetStride &&
1166 SExtIdx = (SExtIdx + 1) % 2;
1174 assert(!(OffsetImm %
TII->getMemScale(*RtMI)) &&
1175 "Unscaled offset cannot be scaled.");
1176 OffsetImm /=
TII->getMemScale(*RtMI);
1180 MachineInstrBuilder MIB;
1185 MachineOperand &PairedRegOp = RtMI == &*Paired ? RegOp0 : RegOp1;
1187 if (RegOp0.
isUse()) {
1188 if (!MergeForward) {
1199 for (
auto It = std::next(
I); It != Paired && PairedRegOp.
isKill(); ++It)
1200 if (It->readsRegister(PairedRegOp.
getReg(),
TRI))
1208 for (MachineInstr &
MI :
1209 make_range(std::next(
I->getIterator()), Paired->getIterator()))
1226 .setMIFlags(
I->mergeFlagsWith(*Paired));
1231 dbgs() <<
"Creating pair load/store. Replacing instructions:\n ");
1236 if (SExtIdx != -1) {
1241 MachineOperand &DstMO = MIB->
getOperand(SExtIdx);
1246 Register DstRegW =
TRI->getSubReg(DstRegX, AArch64::sub_32);
1255 MachineInstrBuilder MIBKill =
1256 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(TargetOpcode::KILL), DstRegW)
1258 .
addReg(DstRegX, RegState::Define);
1261 MachineInstrBuilder MIBSXTW =
1262 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(AArch64::SBFMXri), DstRegX)
1302 if (
I->peekDebugInstrNum()) {
1310 unsigned NewInstrNum;
1311 if (DstRegX ==
I->getOperand(0).getReg()) {
1320 if (Paired->peekDebugInstrNum()) {
1328 unsigned NewInstrNum;
1329 if (DstRegX == Paired->getOperand(0).getReg()) {
1342 }
else if (
Opc == AArch64::LDR_ZXI ||
Opc == AArch64::STR_ZXI) {
1348 AArch64::ZPRRegClass.contains(MOp1.
getReg()) &&
"Invalid register.");
1349 MOp0.
setReg(AArch64::Q0 + (MOp0.
getReg() - AArch64::Z0));
1350 MOp1.
setReg(AArch64::Q0 + (MOp1.
getReg() - AArch64::Z0));
1381 if (
I->peekDebugInstrNum()) {
1386 if (Paired->peekDebugInstrNum()) {
1406 SmallSetVector<Register, 4>
Ops;
1407 for (
const MachineOperand &MO :
1409 if (MO.isReg() && MO.isImplicit() && MO.isDef())
1410 Ops.insert(MO.getReg());
1411 for (
const MachineOperand &MO :
1413 if (MO.isReg() && MO.isImplicit() && MO.isDef())
1414 Ops.insert(MO.getReg());
1416 MIB.addDef(
Op, RegState::Implicit);
1418 CopyImplicitOps(
I, Paired);
1421 I->eraseFromParent();
1422 Paired->eraseFromParent();
1431 next_nodbg(LoadI, LoadI->getParent()->end());
1433 int LoadSize =
TII->getMemScale(*LoadI);
1434 int StoreSize =
TII->getMemScale(*StoreI);
1438 bool IsStoreXReg =
TRI->getRegClass(AArch64::GPR64RegClassID)->contains(StRt);
1441 TRI->getRegClass(AArch64::GPR32RegClassID)->contains(StRt)) &&
1442 "Unexpected RegClass");
1444 MachineInstr *BitExtMI;
1445 if (LoadSize == StoreSize && (LoadSize == 4 || LoadSize == 8)) {
1448 if (StRt == LdRt && LoadSize == 8) {
1449 for (MachineInstr &
MI :
make_range(StoreI->getIterator(),
1450 LoadI->getIterator())) {
1451 if (
MI.killsRegister(StRt,
TRI)) {
1452 MI.clearRegisterKills(StRt,
TRI);
1459 LoadI->eraseFromParent();
1464 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1465 TII->get(IsStoreXReg ? AArch64::ORRXrs : AArch64::ORRWrs), LdRt)
1466 .
addReg(IsStoreXReg ? AArch64::XZR : AArch64::WZR)
1475 bool IsUnscaled =
TII->hasUnscaledLdStOffset(*LoadI);
1476 assert(IsUnscaled ==
TII->hasUnscaledLdStOffset(*StoreI) &&
1477 "Unsupported ld/st match");
1478 assert(LoadSize <= StoreSize &&
"Invalid load size");
1479 int UnscaledLdOffset =
1483 int UnscaledStOffset =
1487 int Width = LoadSize * 8;
1490 LdRt, AArch64::sub_32, &AArch64::GPR64RegClass))
1493 assert((UnscaledLdOffset >= UnscaledStOffset &&
1494 (UnscaledLdOffset + LoadSize) <= UnscaledStOffset + StoreSize) &&
1497 int Immr = 8 * (UnscaledLdOffset - UnscaledStOffset);
1498 int Imms = Immr + Width - 1;
1499 if (UnscaledLdOffset == UnscaledStOffset) {
1500 uint32_t AndMaskEncoded = ((IsStoreXReg ? 1 : 0) << 12)
1506 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1507 TII->get(IsStoreXReg ? AArch64::ANDXri : AArch64::ANDWri),
1512 }
else if (IsStoreXReg && Imms == 31) {
1515 assert(Immr <= Imms &&
"Expected LSR alias of UBFM");
1516 BitExtMI =
BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1517 TII->get(AArch64::UBFMWri),
1518 TRI->getSubReg(DestReg, AArch64::sub_32))
1519 .
addReg(
TRI->getSubReg(StRt, AArch64::sub_32))
1525 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1526 TII->get(IsStoreXReg ? AArch64::UBFMXri : AArch64::UBFMWri),
1536 for (MachineInstr &
MI :
make_range(StoreI->getIterator(),
1538 if (
MI.killsRegister(StRt,
TRI)) {
1539 MI.clearRegisterKills(StRt,
TRI);
1554 LoadI->eraseFromParent();
1564 if (
Offset % OffsetStride)
1576 return (Num + PowOf2 - 1) & ~(PowOf2 - 1);
1593bool AArch64LoadStoreOpt::findMatchingStore(
1598 MachineInstr &LoadMI = *
I;
1608 ModifiedRegUnits.
clear();
1609 UsedRegUnits.
clear();
1614 MachineInstr &
MI = *
MBBI;
1618 if (!
MI.isTransient())
1644 if (!ModifiedRegUnits.
available(BaseReg))
1657 LdStPairFlags &Flags,
1660 if (
MI.hasOrderedMemoryRef() ||
TII->isLdStPairSuppressed(
MI))
1665 !
TII->isLdStPairSuppressed(FirstMI) &&
1666 "FirstMI shouldn't get here if either of these checks are true.");
1670 MI.getMF()->needsWinCFI())
1674 unsigned OpcB =
MI.getOpcode();
1682 if (OpcA == AArch64::LDR_ZXI || OpcA == AArch64::STR_ZXI ||
1683 OpcB == AArch64::LDR_ZXI || OpcB == AArch64::STR_ZXI)
1691 bool IsValidLdStrOpc, PairIsValidLdStrOpc;
1693 assert(IsValidLdStrOpc &&
1694 "Given Opc should be a Load or Store with an immediate");
1697 Flags.setSExtIdx(NonSExtOpc == OpcA ? 1 : 0);
1703 if (!PairIsValidLdStrOpc)
1708 if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
1711 TII->getMemScale(FirstMI) ==
TII->getMemScale(
MI);
1720 return TII->hasUnscaledLdStOffset(OpcA) !=
TII->hasUnscaledLdStOffset(OpcB) &&
1729 auto *RegClass =
TRI->getMinimalPhysRegClass(MOP.
getReg());
1736 if (RegClass->HasDisjunctSubRegs && RegClass->CoveredBySubRegs &&
1737 (
TRI->getSubRegisterClass(RegClass, AArch64::dsub0) ||
1738 TRI->getSubRegisterClass(RegClass, AArch64::qsub0) ||
1739 TRI->getSubRegisterClass(RegClass, AArch64::zsub0))) {
1742 <<
" Cannot rename operands with multiple disjunct subregisters ("
1753 return TRI->isSuperOrSubRegisterEq(
MI.getOperand(0).getReg(),
1760 (
MI.isCall() ||
MI.getDesc().hasImplicitUseOfPhysReg(MOP.
getReg())))
1782 return MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
1783 MOP.isImplicit() && MOP.isKill() &&
1784 TRI->regsOverlap(RegToRename, MOP.getReg());
1790 bool FoundDef =
false;
1821 if (
MI.isPseudo()) {
1822 LLVM_DEBUG(
dbgs() <<
" Cannot rename pseudo/bundle instruction\n");
1826 for (
auto &MOP :
MI.operands()) {
1828 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1838 for (
auto &MOP :
MI.operands()) {
1840 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1853 const AArch64Options &CLOpts =
1856 CLOpts.load_store_scan_limit, CheckMIs))
1860 LLVM_DEBUG(
dbgs() <<
" Did not find definition for register in BB\n");
1888 LLVM_DEBUG(dbgs() <<
"Checking " << MI);
1890 if (MI.getFlag(MachineInstr::FrameSetup)) {
1891 LLVM_DEBUG(dbgs() <<
" Cannot rename framesetup instructions "
1896 for (
auto &MOP :
MI.operands()) {
1897 if (!MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1898 !TRI->regsOverlap(MOP.getReg(), RegToRename))
1900 if (!canRenameMOP(MI, MOP, TRI)) {
1901 LLVM_DEBUG(dbgs() <<
" Cannot rename " << MOP <<
" in " << MI);
1927 auto AnySubOrSuperRegCalleePreserved = [&MF,
TRI](
MCPhysReg PR) {
1928 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1930 return TRI->isCalleeSavedPhysReg(SubOrSuper, MF);
1936 auto CanBeUsedForAllClasses = [&RequiredClasses,
TRI](
MCPhysReg PR) {
1939 TRI->sub_and_superregs_inclusive(PR),
1940 [
C](
MCPhysReg SubOrSuper) { return C->contains(SubOrSuper); });
1944 auto *RegClass =
TRI->getMinimalPhysRegClass(
Reg);
1947 !
RegInfo.isReserved(PR) && !AnySubOrSuperRegCalleePreserved(PR) &&
1948 CanBeUsedForAllClasses(PR)) {
1956 <<
TRI->getRegClassName(RegClass) <<
"\n");
1957 return std::nullopt;
1968 std::optional<MCPhysReg> RenameReg;
1977 const bool IsLoad = FirstMI.
mayLoad();
1979 if (!MaybeCanRename) {
1982 RequiredClasses,
TRI)};
1988 if (*MaybeCanRename) {
1990 RequiredClasses,
TRI);
1999 LdStPairFlags &Flags,
unsigned Limit,
2000 bool FindNarrowMerge) {
2003 MachineInstr &FirstMI = *
I;
2007 bool IsUnscaled =
TII->hasUnscaledLdStOffset(FirstMI);
2011 int OffsetStride = IsUnscaled ?
TII->getMemScale(FirstMI) : 1;
2014 std::optional<bool> MaybeCanRename;
2015 if (!Subtarget->
getCLOpts().load_store_renaming)
2016 MaybeCanRename = {
false};
2018 SmallPtrSet<const TargetRegisterClass *, 5> RequiredClasses;
2019 LiveRegUnits UsedInBetween;
2022 Flags.clearRenameReg();
2026 ModifiedRegUnits.
clear();
2027 UsedRegUnits.
clear();
2030 SmallVector<MachineInstr *, 4> MemInsns;
2035 MachineInstr &
MI = *
MBBI;
2042 if (!
MI.isTransient())
2045 Flags.setSExtIdx(-1);
2048 assert(
MI.mayLoadOrStore() &&
"Expected memory operation.");
2057 bool MIIsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2058 if (IsUnscaled != MIIsUnscaled) {
2062 int MemSize =
TII->getMemScale(
MI);
2066 if (MIOffset % MemSize) {
2072 MIOffset /= MemSize;
2074 MIOffset *= MemSize;
2080 if (BaseReg == MIBaseReg) {
2086 bool IsOutOfBounds = MIOffset !=
TII->getMemScale(
MI);
2087 bool IsBaseRegUsed = !UsedRegUnits.
available(
2089 bool IsBaseRegModified = !ModifiedRegUnits.
available(
2094 bool IsMIRegTheSame =
2097 if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified ||
2105 if ((
Offset != MIOffset + OffsetStride) &&
2106 (
Offset + OffsetStride != MIOffset)) {
2115 if (FindNarrowMerge) {
2120 if ((!IsUnscaled &&
alignTo(MinOffset, 2) != MinOffset) ||
2137 <<
"keep looking.\n");
2143 if (IsUnscaled && (
alignTo(MinOffset, OffsetStride) != MinOffset)) {
2148 <<
"Offset doesn't fit due to alignment requirements, "
2149 <<
"keep looking.\n");
2160 if (!ModifiedRegUnits.
available(BaseReg))
2163 const bool SameLoadReg =
MayLoad &&
TRI->isSuperOrSubRegisterEq(
2170 bool RtNotModified =
2172 bool RtNotUsed = !(
MI.mayLoad() && !SameLoadReg &&
2175 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 2nd into 1st insn:\n"
2177 << (RtNotModified ?
"true" :
"false") <<
"\n"
2179 << (RtNotUsed ?
"true" :
"false") <<
"\n");
2181 if (RtNotModified && RtNotUsed && !
mayAlias(
MI, MemInsns, AA)) {
2186 std::optional<MCPhysReg> RenameReg =
2188 Reg, DefinedInBB, UsedInBetween,
2189 RequiredClasses,
TRI);
2195 <<
"keep looking.\n");
2198 Flags.setRenameReg(*RenameReg);
2201 Flags.setMergeForward(
false);
2203 Flags.clearRenameReg();
2214 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 1st into 2nd insn:\n"
2216 <<
"' not modified: "
2217 << (RtNotModified ?
"true" :
"false") <<
"\n");
2219 if (RtNotModified && !
mayAlias(FirstMI, MemInsns, AA)) {
2221 Flags.setMergeForward(
true);
2222 Flags.clearRenameReg();
2227 MaybeCanRename, FirstMI,
MI,
Reg, DefinedInBB, UsedInBetween,
2228 RequiredClasses,
TRI);
2230 Flags.setMergeForward(
true);
2231 Flags.setRenameReg(*RenameReg);
2235 LLVM_DEBUG(
dbgs() <<
"Unable to combine these instructions due to "
2236 <<
"interference in between, keep looking.\n");
2252 if (!ModifiedRegUnits.
available(BaseReg)) {
2258 if (
MI.mayLoadOrStore())
2266 assert((
MI.getOpcode() == AArch64::SUBXri ||
2267 MI.getOpcode() == AArch64::ADDXri) &&
2268 "Expected a register update instruction");
2269 auto End =
MI.getParent()->end();
2270 if (MaybeCFI ==
End ||
2271 MaybeCFI->getOpcode() != TargetOpcode::CFI_INSTRUCTION ||
2274 MI.getOperand(0).getReg() != AArch64::SP)
2278 unsigned CFIIndex = MaybeCFI->getOperand(0).getCFIIndex();
2289std::optional<MachineBasicBlock::iterator> AArch64LoadStoreOpt::mergeUpdateInsn(
2291 bool IsForward,
bool IsPreIdx,
bool MergeEither) {
2292 assert((Update->getOpcode() == AArch64::ADDXri ||
2293 Update->getOpcode() == AArch64::SUBXri) &&
2294 "Unexpected base register update instruction to merge!");
2310 if (std::any_of(std::next(CFI),
I, [](
const auto &Insn) {
2311 return Insn.getOpcode() == TargetOpcode::CFI_INSTRUCTION;
2313 return std::nullopt;
2315 MachineBasicBlock *
MBB = InsertPt->getParent();
2324 if (NextI == Update)
2327 int Value = Update->getOperand(2).getImm();
2329 "Can't merge 1 << 12 offset into pre-/post-indexed load / store");
2330 if (Update->getOpcode() == AArch64::SUBXri)
2335 MachineInstrBuilder MIB;
2336 int Scale, MinOffset, MaxOffset;
2340 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2342 .
add(Update->getOperand(0))
2350 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2352 .
add(Update->getOperand(0))
2377 I->eraseFromParent();
2378 Update->eraseFromParent();
2386 unsigned Offset,
int Scale) {
2387 assert((Update->getOpcode() == AArch64::MOVKWi) &&
2388 "Unexpected const mov instruction to merge!");
2392 MachineInstr &MemMI = *
I;
2393 unsigned Mask = (1 << 12) * Scale - 1;
2398 MachineInstrBuilder AddMIB, MemMIB;
2402 BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(AArch64::ADDXri))
2410 MemMIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2418 ++NumConstOffsetFolded;
2433 I->eraseFromParent();
2434 PrevI->eraseFromParent();
2435 Update->eraseFromParent();
2440bool AArch64LoadStoreOpt::isMatchingUpdateInsn(MachineInstr &MemMI,
2442 unsigned BaseReg,
int Offset) {
2443 switch (
MI.getOpcode()) {
2446 case AArch64::SUBXri:
2447 case AArch64::ADDXri:
2450 if (!
MI.getOperand(2).isImm())
2458 if (
MI.getOperand(0).getReg() != BaseReg ||
2459 MI.getOperand(1).getReg() != BaseReg)
2462 int UpdateOffset =
MI.getOperand(2).getImm();
2463 if (
MI.getOpcode() == AArch64::SUBXri)
2464 UpdateOffset = -UpdateOffset;
2468 int Scale, MinOffset, MaxOffset;
2470 if (UpdateOffset % Scale != 0)
2474 int ScaledOffset = UpdateOffset / Scale;
2475 if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset)
2487bool AArch64LoadStoreOpt::isMatchingMovConstInsn(MachineInstr &MemMI,
2493 if (
MI.getOpcode() == AArch64::MOVKWi &&
2494 TRI->isSuperOrSubRegisterEq(IndexReg,
MI.getOperand(1).getReg())) {
2503 MachineInstr &MovzMI = *
MBBI;
2505 if (MovzMI.
getOpcode() == AArch64::MOVZWi &&
2508 unsigned High =
MI.getOperand(2).getImm() <<
MI.getOperand(3).getImm();
2511 return Offset >> 24 == 0;
2520 MachineInstr &MemMI = *
I;
2525 TII->getMemScale(MemMI);
2530 if (MIUnscaledOffset != UnscaledOffset)
2541 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2543 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2550 ModifiedRegUnits.
clear();
2551 UsedRegUnits.
clear();
2557 const bool BaseRegSP =
BaseReg == AArch64::SP;
2558 if (BaseRegSP &&
I->getMF()->needsWinCFI()) {
2566 MachineBasicBlock *CurMBB =
I->getParent();
2573 MachineInstr &
MI = *
MBBI;
2577 if (!
MI.isTransient())
2581 if (isMatchingUpdateInsn(*
I,
MI, BaseReg, UnscaledOffset))
2592 if (!ModifiedRegUnits.
available(BaseReg) ||
2594 (BaseRegSP &&
MBBI->mayLoadOrStore()))
2598 if (!VisitSucc || Limit <=
Count)
2603 MachineBasicBlock *SuccToVisit =
nullptr;
2604 unsigned LiveSuccCount = 0;
2605 for (MachineBasicBlock *Succ : CurMBB->
successors()) {
2606 for (MCRegAliasIterator AI(BaseReg,
TRI,
true); AI.isValid(); ++AI) {
2607 if (Succ->isLiveIn(*AI)) {
2608 if (LiveSuccCount++)
2610 if (Succ->pred_size() == 1)
2618 CurMBB = SuccToVisit;
2629 MachineInstr &MemMI = *
I;
2648 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i)
2649 if (DestReg[i] == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg[i]))
2653 const bool BaseRegSP =
BaseReg == AArch64::SP;
2654 if (BaseRegSP &&
I->getMF()->needsWinCFI()) {
2661 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
2662 unsigned RedZoneSize =
2667 ModifiedRegUnits.
clear();
2668 UsedRegUnits.
clear();
2670 bool MemAccessBeforeSPPreInc =
false;
2674 MachineInstr &
MI = *
MBBI;
2678 if (!
MI.isTransient())
2682 if (isMatchingUpdateInsn(*
I,
MI, BaseReg,
Offset)) {
2685 if (MemAccessBeforeSPPreInc &&
MBBI->getOperand(2).getImm() > RedZoneSize)
2695 if (!ModifiedRegUnits.
available(BaseReg) ||
2703 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
2704 (DestReg[0].isValid() && !(ModifiedRegUnits.
available(DestReg[0]) &&
2706 (DestReg[1].isValid() && !(ModifiedRegUnits.
available(DestReg[1]) &&
2708 MergeEither =
false;
2713 if (BaseRegSP &&
MBBI->mayLoadOrStore())
2714 MemAccessBeforeSPPreInc =
true;
2720AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
2724 MachineInstr &MemMI = *
I;
2743 ModifiedRegUnits.
clear();
2744 UsedRegUnits.
clear();
2748 MachineInstr &
MI = *
MBBI;
2752 if (!
MI.isTransient())
2756 if (isMatchingMovConstInsn(*
I,
MI, IndexReg,
Offset)) {
2765 if (!ModifiedRegUnits.
available(IndexReg) ||
2773bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
2775 MachineInstr &
MI = *
MBBI;
2777 if (
MI.hasOrderedMemoryRef())
2790 if (findMatchingStore(
MBBI, Subtarget->
getCLOpts().load_store_scan_limit,
2792 ++NumLoadsFromStoresPromoted;
2796 MBBI = promoteLoadFromStore(
MBBI, StoreI);
2803bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
2806 MachineInstr &
MI = *
MBBI;
2809 if (!
TII->isCandidateToMergeOrPair(
MI))
2813 LdStPairFlags
Flags;
2818 ++NumZeroStoresPromoted;
2822 MBBI = mergeNarrowZeroStores(
MBBI, MergeMI, Flags);
2831 MachineInstr &
MI = *
MBBI;
2834 if (!
TII->isCandidateToMergeOrPair(
MI))
2838 if (
MI.mayLoad() && Subtarget->hasDisableLdp())
2842 if (
MI.mayStore() && Subtarget->hasDisableStp())
2848 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2850 int OffsetStride = IsUnscaled ?
TII->getMemScale(
MI) : 1;
2858 LdStPairFlags
Flags;
2868 auto Prev = std::prev(
MBBI);
2871 MachineMemOperand *MemOp =
2872 MI.memoperands_empty() ? nullptr :
MI.memoperands().front();
2877 if ((
MI.mayLoad() && Subtarget->hasLdpAlignedOnly()) ||
2878 (
MI.mayStore() && Subtarget->hasStpAlignedOnly())) {
2880 if (!MemOp || !MemOp->getMemoryType().isValid()) {
2881 NumFailedAlignmentCheck++;
2887 uint64_t MemAlignment = MemOp->getAlign().value();
2889 Align(MemOp->getSize().getValue().getKnownMinValue()).value();
2891 if (MemAlignment < 2 * TypeAlignment) {
2892 NumFailedAlignmentCheck++;
2898 if (
TII->hasUnscaledLdStOffset(
MI))
2899 ++NumUnscaledPairCreated;
2901 MBBI = mergePairedInsns(
MBBI, Paired, Flags);
2904 for (
auto I = std::next(Prev);
I !=
MBBI;
I++)
2910bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
2912 MachineInstr &
MI = *
MBBI;
2921 if (
MBBI->hasOrderedMemoryRef() &&
2931 Update = findMatchingUpdateInsnForward(
2935 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2944 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2953 Update = findMatchingUpdateInsnBackward(
2954 MBBI, Subtarget->
getCLOpts().update_scan_limit, MergeEither);
2957 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
true,
2958 true, MergeEither)) {
2967 int UnscaledOffset =
2975 Update = findMatchingUpdateInsnForward(
2976 MBBI, UnscaledOffset, Subtarget->
getCLOpts().update_scan_limit);
2979 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2992 MachineInstr &
MI = *
MBBI;
2997 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
3008 Update = findMatchingConstOffsetBackward(
3010 if (Update !=
E && (
Offset & (Scale - 1)) == 0) {
3022 switch (GPRStoreOpc) {
3024 case AArch64::STRBBui:
3025 return AArch64::STRBui;
3026 case AArch64::STRHHui:
3027 return AArch64::STRHui;
3028 case AArch64::STRWui:
3029 return AArch64::STRSui;
3030 case AArch64::STRXui:
3031 return AArch64::STRDui;
3033 case AArch64::STURBBi:
3034 return AArch64::STURBi;
3035 case AArch64::STURHHi:
3036 return AArch64::STURHi;
3037 case AArch64::STURWi:
3038 return AArch64::STURSi;
3039 case AArch64::STURXi:
3040 return AArch64::STURDi;
3042 case AArch64::STRBBroW:
3043 return AArch64::STRBroW;
3044 case AArch64::STRBBroX:
3045 return AArch64::STRBroX;
3046 case AArch64::STRHHroW:
3047 return AArch64::STRHroW;
3048 case AArch64::STRHHroX:
3049 return AArch64::STRHroX;
3050 case AArch64::STRWroW:
3051 return AArch64::STRSroW;
3052 case AArch64::STRWroX:
3053 return AArch64::STRSroX;
3054 case AArch64::STRXroW:
3055 return AArch64::STRDroW;
3056 case AArch64::STRXroX:
3057 return AArch64::STRDroX;
3067 case AArch64::UMOVvi8_idx0:
3068 return AArch64::bsub;
3069 case AArch64::UMOVvi16_idx0:
3070 return AArch64::hsub;
3071 case AArch64::UMOVvi32_idx0:
3072 return AArch64::ssub;
3073 case AArch64::UMOVvi64_idx0:
3074 return AArch64::dsub;
3080bool AArch64LoadStoreOpt::tryToReplaceUMOVStore(
3082 MachineInstr &StoreMI = *
MBBI;
3105 MachineInstr *UMOVMI =
nullptr;
3107 unsigned SubRegIdx = 0;
3109 for (
auto It =
MBBI; It !=
B;) {
3110 MachineInstr &
MI = *--It;
3111 if (
MI.isDebugInstr())
3115 if (
MI.readsRegister(StoreValReg,
TRI))
3117 if (
MI.modifiesRegister(StoreValReg,
TRI)) {
3130 TRI->getRegSizeInBits(*
TRI->getMinimalPhysRegClass(FPRReg)))
3139 if (It->modifiesRegister(VecReg,
TRI))
3141 if (!VecRegKilled && It->killsRegister(VecReg,
TRI))
3142 VecRegKilled =
true;
3149 It->clearRegisterKills(VecReg,
TRI);
3151 LLVM_DEBUG(
dbgs() <<
"Folding UMOV + store: " << *UMOVMI <<
" + "
3163 ++NumUMOVFoldedToFPRStore;
3167bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &
MBB,
3168 bool EnableNarrowZeroStOpt) {
3200 if (EnableNarrowZeroStOpt)
3224 DefinedInBB.
clear();
3233 if (
TII->isPairableLdStInst(*
MBBI) && tryToPairLdStInst(
MBBI))
3277 if (tryToReplaceUMOVStore(
MBBI))
3299 bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
3300 for (
auto &
MBB : Fn) {
3318bool AArch64LoadStoreOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
3321 AArch64LoadStoreOpt Impl;
3322 Impl.AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
3323 return Impl.runOnMachineFunction(MF);
3329 return new AArch64LoadStoreOptLegacy();
3335 AArch64LoadStoreOpt Impl;
3339 bool Changed = Impl.runOnMachineFunction(MF);
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
static MachineOperand & getLdStRegOp(MachineInstr &MI, unsigned PairedRegOp=0)
static bool isPromotableLoadFromStore(MachineInstr &MI)
static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale, int &MinOffset, int &MaxOffset)
static bool inBoundsForPair(bool IsUnscaled, int Offset, int OffsetStride)
static unsigned getMatchingPairOpcode(unsigned Opc)
static unsigned getGPRToFPRStoreOpcode(unsigned GPRStoreOpc)
static bool areCandidatesToMergeOrPair(MachineInstr &FirstMI, MachineInstr &MI, LdStPairFlags &Flags, const AArch64InstrInfo *TII)
static std::optional< MCPhysReg > tryToFindRegisterToRename(const MachineFunction &MF, Register Reg, LiveRegUnits &DefinedInBB, LiveRegUnits &UsedInBetween, SmallPtrSetImpl< const TargetRegisterClass * > &RequiredClasses, const TargetRegisterInfo *TRI)
static bool canRenameUntilSecondLoad(MachineInstr &FirstLoad, MachineInstr &SecondLoad, LiveRegUnits &UsedInBetween, SmallPtrSetImpl< const TargetRegisterClass * > &RequiredClasses, const TargetRegisterInfo *TRI)
static std::optional< MCPhysReg > findRenameRegForSameLdStRegPair(std::optional< bool > MaybeCanRename, MachineInstr &FirstMI, MachineInstr &MI, Register Reg, LiveRegUnits &DefinedInBB, LiveRegUnits &UsedInBetween, SmallPtrSetImpl< const TargetRegisterClass * > &RequiredClasses, const TargetRegisterInfo *TRI)
static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
static unsigned getPreIndexedOpcode(unsigned Opc)
#define AARCH64_LOAD_STORE_OPT_NAME
static void addDebugSubstitutionsToTable(MachineFunction *MF, unsigned InstrNumToSet, MachineInstr &OriginalInstr, MachineInstr &MergedInstr)
This function will add a new entry into the debugValueSubstitutions table when two instruction have b...
static bool isPromotableZeroStoreInst(MachineInstr &MI)
static unsigned getMatchingWideOpcode(unsigned Opc)
static unsigned getMatchingNonSExtOpcode(unsigned Opc, bool *IsValidLdStrOpc=nullptr)
static MachineBasicBlock::iterator maybeMoveCFI(MachineInstr &MI, MachineBasicBlock::iterator MaybeCFI)
static bool isTagStore(const MachineInstr &MI)
static unsigned isMatchingStore(MachineInstr &LoadInst, MachineInstr &StoreInst)
static bool forAllMIsUntilDef(MachineInstr &MI, MCPhysReg DefReg, const TargetRegisterInfo *TRI, unsigned Limit, std::function< bool(MachineInstr &, bool)> &Fn)
static bool isRewritableImplicitDef(const MachineInstr &MI, const MachineOperand &MO)
static unsigned getPostIndexedOpcode(unsigned Opc)
static unsigned getUMOVSubRegIdx(unsigned UMOVOpc)
static bool isMergeableLdStUpdate(MachineInstr &MI, AArch64FunctionInfo &AFI)
static bool canRenameMOP(const MachineInstr &MI, const MachineOperand &MOP, const TargetRegisterInfo *TRI)
static bool isLdOffsetInRangeOfSt(MachineInstr &LoadInst, MachineInstr &StoreInst, const AArch64InstrInfo *TII)
static bool isPreLdStPairCandidate(MachineInstr &FirstMI, MachineInstr &MI)
static bool isMergeableIndexLdSt(MachineInstr &MI, int &Scale)
static void updateDefinedRegisters(MachineInstr &MI, LiveRegUnits &Units, const TargetRegisterInfo *TRI)
static bool canRenameUpToDef(MachineInstr &FirstMI, LiveRegUnits &UsedInBetween, SmallPtrSetImpl< const TargetRegisterClass * > &RequiredClasses, const TargetRegisterInfo *TRI)
static unsigned getBaseAddressOpcode(unsigned Opc)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
const HexagonInstrInfo * TII
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
static const MachineOperand & getLdStOffsetOp(const MachineInstr &MI)
Returns the immediate offset operator of a load/store.
static const MachineOperand & getLdStAmountOp(const MachineInstr &MI)
Returns the shift amount operator of a load/store.
static bool isPreLdSt(const MachineInstr &MI)
Returns whether the instruction is a pre-indexed load/store.
static bool isPairedLdSt(const MachineInstr &MI)
Returns whether the instruction is a paired load/store.
static int getMemScale(unsigned Opc)
Scaling factor for (scaled or unscaled) load or store.
static const MachineOperand & getLdStBaseOp(const MachineInstr &MI)
Returns the base register operator of a load/store.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const AArch64RegisterInfo * getRegisterInfo() const override
const AArch64InstrInfo * getInstrInfo() const override
const AArch64Options & getCLOpts() const
const AArch64TargetLowering * getTargetLowering() const override
bool isLittleEndian() const
unsigned getRedZoneSize(const Function &F) const
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()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represents analyses that only rely on functions' control flow.
static bool shouldExecute(CounterInfo &Counter)
FunctionPass class - This class is used to implement most global optimizations.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
A set of register units used to track register liveness.
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void init(const TargetRegisterInfo &TRI)
Initialize and clear the set.
void addReg(MCRegister Reg)
Adds register units covered by physical register Reg.
void removeReg(MCRegister Reg)
Removes all register units covered by physical register Reg.
LLVM_ABI void addLiveIns(const MachineBasicBlock &MBB)
Adds registers living into block MBB.
void clear()
Clears the set.
LLVM_ABI void accumulate(const MachineInstr &MI)
Adds all register units used, defined or clobbered in MI.
An instruction for reading from memory.
OpType getOperation() const
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
iterator_range< succ_iterator > successors()
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
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.
const std::vector< MCCFIInstruction > & getFrameInstructions() const
Returns a reference to a list of cfi instructions in the function's prologue.
void makeDebugValueSubstitution(DebugInstrOperandPair, DebugInstrOperandPair, unsigned SubReg=0)
Create a substitution between one <instr,operand> value to a different, new value.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
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
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI bool mayAlias(BatchAAResults *AA, const MachineInstr &Other, bool UseTBAA) const
Returns true if this instruction's memory access aliases the memory access of Other.
unsigned peekDebugInstrNum() const
Examine the instruction number of this MachineInstr.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
LLVM_ABI void setMemRefs(MachineFunction &MF, ArrayRef< MachineMemOperand * > MemRefs)
Assign this MachineInstr's memory reference descriptor list.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool killsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr kills the specified register.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
LLVM_ABI bool hasOrderedMemoryRef() const
Return true if this instruction may have an ordered or volatile memory reference, or if the informati...
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
bool isPseudo(QueryType Type=IgnoreBundle) const
Return true if this is a pseudo instruction that doesn't correspond to a real machine instruction.
LLVM_ABI void dump() const
LLVM_ABI unsigned getDebugInstrNum()
Fetch the instruction number of this MachineInstr.
LLVM_ABI void clearRegisterKills(Register Reg, const TargetRegisterInfo *RegInfo)
Clear all kill flags affecting Reg.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setImplicit(bool Val=true)
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.
void setIsKill(bool Val=true)
LLVM_ABI bool isRenamable() const
isRenamable - Returns true if this register may be renamed, i.e.
bool isEarlyClobber() const
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
bool tracksLiveness() const
tracksLiveness - Returns true when tracking register liveness accurately.
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 isValid() const
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< filter_iterator< ConstMIBundleOperands, bool(*)(const MachineOperand &)> > phys_regs_and_masks(const MachineInstr &MI)
Returns an iterator range over all physical register and mask operands for MI and bundled instruction...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
FunctionPass * createAArch64LoadStoreOptLegacyPass()
createAArch64LoadStoreOptimizationPass - returns an instance of the load / store optimization pass.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
@ End
Run the machine verifier once, at the end of the pipeline.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
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