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);
232char AArch64LoadStoreOptLegacy::ID = 0;
239static
bool isNarrowStore(
unsigned Opc) {
243 case AArch64::STRBBui:
244 case AArch64::STURBBi:
245 case AArch64::STRHHui:
246 case AArch64::STURHHi:
254 switch (
MI.getOpcode()) {
260 case AArch64::STZ2Gi:
266 bool *IsValidLdStrOpc =
nullptr) {
268 *IsValidLdStrOpc =
true;
272 *IsValidLdStrOpc =
false;
273 return std::numeric_limits<unsigned>::max();
274 case AArch64::STRDui:
275 case AArch64::STURDi:
276 case AArch64::STRDpre:
277 case AArch64::STRQui:
278 case AArch64::STURQi:
279 case AArch64::STRQpre:
280 case AArch64::STRBBui:
281 case AArch64::STURBBi:
282 case AArch64::STRHHui:
283 case AArch64::STURHHi:
284 case AArch64::STRWui:
285 case AArch64::STRWpre:
286 case AArch64::STURWi:
287 case AArch64::STRXui:
288 case AArch64::STRXpre:
289 case AArch64::STURXi:
290 case AArch64::STR_ZXI:
291 case AArch64::LDRDui:
292 case AArch64::LDURDi:
293 case AArch64::LDRDpre:
294 case AArch64::LDRQui:
295 case AArch64::LDURQi:
296 case AArch64::LDRQpre:
297 case AArch64::LDRWui:
298 case AArch64::LDURWi:
299 case AArch64::LDRWpre:
300 case AArch64::LDRXui:
301 case AArch64::LDURXi:
302 case AArch64::LDRXpre:
303 case AArch64::STRSui:
304 case AArch64::STURSi:
305 case AArch64::STRSpre:
306 case AArch64::LDRSui:
307 case AArch64::LDURSi:
308 case AArch64::LDRSpre:
309 case AArch64::LDR_ZXI:
311 case AArch64::LDRSWui:
312 return AArch64::LDRWui;
313 case AArch64::LDURSWi:
314 return AArch64::LDURWi;
315 case AArch64::LDRSWpre:
316 return AArch64::LDRWpre;
324 case AArch64::STRBBui:
325 return AArch64::STRHHui;
326 case AArch64::STRHHui:
327 return AArch64::STRWui;
328 case AArch64::STURBBi:
329 return AArch64::STURHHi;
330 case AArch64::STURHHi:
331 return AArch64::STURWi;
332 case AArch64::STURWi:
333 return AArch64::STURXi;
334 case AArch64::STRWui:
335 return AArch64::STRXui;
343 case AArch64::STRSui:
344 case AArch64::STURSi:
345 return AArch64::STPSi;
346 case AArch64::STRSpre:
347 return AArch64::STPSpre;
348 case AArch64::STRDui:
349 case AArch64::STURDi:
350 return AArch64::STPDi;
351 case AArch64::STRDpre:
352 return AArch64::STPDpre;
353 case AArch64::STRQui:
354 case AArch64::STURQi:
355 case AArch64::STR_ZXI:
356 return AArch64::STPQi;
357 case AArch64::STRQpre:
358 return AArch64::STPQpre;
359 case AArch64::STRWui:
360 case AArch64::STURWi:
361 return AArch64::STPWi;
362 case AArch64::STRWpre:
363 return AArch64::STPWpre;
364 case AArch64::STRXui:
365 case AArch64::STURXi:
366 return AArch64::STPXi;
367 case AArch64::STRXpre:
368 return AArch64::STPXpre;
369 case AArch64::LDRSui:
370 case AArch64::LDURSi:
371 return AArch64::LDPSi;
372 case AArch64::LDRSpre:
373 return AArch64::LDPSpre;
374 case AArch64::LDRDui:
375 case AArch64::LDURDi:
376 return AArch64::LDPDi;
377 case AArch64::LDRDpre:
378 return AArch64::LDPDpre;
379 case AArch64::LDRQui:
380 case AArch64::LDURQi:
381 case AArch64::LDR_ZXI:
382 return AArch64::LDPQi;
383 case AArch64::LDRQpre:
384 return AArch64::LDPQpre;
385 case AArch64::LDRWui:
386 case AArch64::LDURWi:
387 return AArch64::LDPWi;
388 case AArch64::LDRWpre:
389 return AArch64::LDPWpre;
390 case AArch64::LDRXui:
391 case AArch64::LDURXi:
392 return AArch64::LDPXi;
393 case AArch64::LDRXpre:
394 return AArch64::LDPXpre;
395 case AArch64::LDRSWui:
396 case AArch64::LDURSWi:
397 return AArch64::LDPSWi;
398 case AArch64::LDRSWpre:
399 return AArch64::LDPSWpre;
410 case AArch64::LDRBBui:
411 return StOpc == AArch64::STRBBui || StOpc == AArch64::STRHHui ||
412 StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
413 case AArch64::LDURBBi:
414 return StOpc == AArch64::STURBBi || StOpc == AArch64::STURHHi ||
415 StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
416 case AArch64::LDRHHui:
417 return StOpc == AArch64::STRHHui || StOpc == AArch64::STRWui ||
418 StOpc == AArch64::STRXui;
419 case AArch64::LDURHHi:
420 return StOpc == AArch64::STURHHi || StOpc == AArch64::STURWi ||
421 StOpc == AArch64::STURXi;
422 case AArch64::LDRWui:
423 return StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
424 case AArch64::LDURWi:
425 return StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
426 case AArch64::LDRXui:
427 return StOpc == AArch64::STRXui;
428 case AArch64::LDURXi:
429 return StOpc == AArch64::STURXi;
441 case AArch64::STRBui:
442 return AArch64::STRBpre;
443 case AArch64::STRHui:
444 return AArch64::STRHpre;
445 case AArch64::STRSui:
446 return AArch64::STRSpre;
447 case AArch64::STRDui:
448 return AArch64::STRDpre;
449 case AArch64::STRQui:
450 return AArch64::STRQpre;
451 case AArch64::STRBBui:
452 return AArch64::STRBBpre;
453 case AArch64::STRHHui:
454 return AArch64::STRHHpre;
455 case AArch64::STRWui:
456 return AArch64::STRWpre;
457 case AArch64::STRXui:
458 return AArch64::STRXpre;
459 case AArch64::LDRBui:
460 return AArch64::LDRBpre;
461 case AArch64::LDRHui:
462 return AArch64::LDRHpre;
463 case AArch64::LDRSui:
464 return AArch64::LDRSpre;
465 case AArch64::LDRDui:
466 return AArch64::LDRDpre;
467 case AArch64::LDRQui:
468 return AArch64::LDRQpre;
469 case AArch64::LDRBBui:
470 return AArch64::LDRBBpre;
471 case AArch64::LDRHHui:
472 return AArch64::LDRHHpre;
473 case AArch64::LDRWui:
474 return AArch64::LDRWpre;
475 case AArch64::LDRXui:
476 return AArch64::LDRXpre;
477 case AArch64::LDRSWui:
478 return AArch64::LDRSWpre;
480 return AArch64::LDPSpre;
481 case AArch64::LDPSWi:
482 return AArch64::LDPSWpre;
484 return AArch64::LDPDpre;
486 return AArch64::LDPQpre;
488 return AArch64::LDPWpre;
490 return AArch64::LDPXpre;
492 return AArch64::STPSpre;
494 return AArch64::STPDpre;
496 return AArch64::STPQpre;
498 return AArch64::STPWpre;
500 return AArch64::STPXpre;
502 return AArch64::STGPreIndex;
504 return AArch64::STZGPreIndex;
506 return AArch64::ST2GPreIndex;
507 case AArch64::STZ2Gi:
508 return AArch64::STZ2GPreIndex;
510 return AArch64::STGPpre;
519 case AArch64::LDRBroX:
520 return AArch64::LDRBui;
521 case AArch64::LDRBBroX:
522 return AArch64::LDRBBui;
523 case AArch64::LDRSBXroX:
524 return AArch64::LDRSBXui;
525 case AArch64::LDRSBWroX:
526 return AArch64::LDRSBWui;
527 case AArch64::LDRHroX:
528 return AArch64::LDRHui;
529 case AArch64::LDRHHroX:
530 return AArch64::LDRHHui;
531 case AArch64::LDRSHXroX:
532 return AArch64::LDRSHXui;
533 case AArch64::LDRSHWroX:
534 return AArch64::LDRSHWui;
535 case AArch64::LDRWroX:
536 return AArch64::LDRWui;
537 case AArch64::LDRSroX:
538 return AArch64::LDRSui;
539 case AArch64::LDRSWroX:
540 return AArch64::LDRSWui;
541 case AArch64::LDRDroX:
542 return AArch64::LDRDui;
543 case AArch64::LDRXroX:
544 return AArch64::LDRXui;
545 case AArch64::LDRQroX:
546 return AArch64::LDRQui;
554 case AArch64::STRBui:
555 return AArch64::STRBpost;
556 case AArch64::STRHui:
557 return AArch64::STRHpost;
558 case AArch64::STRSui:
559 case AArch64::STURSi:
560 return AArch64::STRSpost;
561 case AArch64::STRDui:
562 case AArch64::STURDi:
563 return AArch64::STRDpost;
564 case AArch64::STRQui:
565 case AArch64::STURQi:
566 return AArch64::STRQpost;
567 case AArch64::STRBBui:
568 return AArch64::STRBBpost;
569 case AArch64::STRHHui:
570 return AArch64::STRHHpost;
571 case AArch64::STRWui:
572 case AArch64::STURWi:
573 return AArch64::STRWpost;
574 case AArch64::STRXui:
575 case AArch64::STURXi:
576 return AArch64::STRXpost;
577 case AArch64::LDRBui:
578 return AArch64::LDRBpost;
579 case AArch64::LDRHui:
580 return AArch64::LDRHpost;
581 case AArch64::LDRSui:
582 case AArch64::LDURSi:
583 return AArch64::LDRSpost;
584 case AArch64::LDRDui:
585 case AArch64::LDURDi:
586 return AArch64::LDRDpost;
587 case AArch64::LDRQui:
588 case AArch64::LDURQi:
589 return AArch64::LDRQpost;
590 case AArch64::LDRBBui:
591 return AArch64::LDRBBpost;
592 case AArch64::LDRHHui:
593 return AArch64::LDRHHpost;
594 case AArch64::LDRWui:
595 case AArch64::LDURWi:
596 return AArch64::LDRWpost;
597 case AArch64::LDRXui:
598 case AArch64::LDURXi:
599 return AArch64::LDRXpost;
600 case AArch64::LDRSWui:
601 return AArch64::LDRSWpost;
603 return AArch64::LDPSpost;
604 case AArch64::LDPSWi:
605 return AArch64::LDPSWpost;
607 return AArch64::LDPDpost;
609 return AArch64::LDPQpost;
611 return AArch64::LDPWpost;
613 return AArch64::LDPXpost;
615 return AArch64::STPSpost;
617 return AArch64::STPDpost;
619 return AArch64::STPQpost;
621 return AArch64::STPWpost;
623 return AArch64::STPXpost;
625 return AArch64::STGPostIndex;
627 return AArch64::STZGPostIndex;
629 return AArch64::ST2GPostIndex;
630 case AArch64::STZ2Gi:
631 return AArch64::STZ2GPostIndex;
633 return AArch64::STGPpost;
640 unsigned OpcB =
MI.getOpcode();
645 case AArch64::STRSpre:
646 return (OpcB == AArch64::STRSui) || (OpcB == AArch64::STURSi);
647 case AArch64::STRDpre:
648 return (OpcB == AArch64::STRDui) || (OpcB == AArch64::STURDi);
649 case AArch64::STRQpre:
650 return (OpcB == AArch64::STRQui) || (OpcB == AArch64::STURQi);
651 case AArch64::STRWpre:
652 return (OpcB == AArch64::STRWui) || (OpcB == AArch64::STURWi);
653 case AArch64::STRXpre:
654 return (OpcB == AArch64::STRXui) || (OpcB == AArch64::STURXi);
655 case AArch64::LDRSpre:
656 return (OpcB == AArch64::LDRSui) || (OpcB == AArch64::LDURSi);
657 case AArch64::LDRDpre:
658 return (OpcB == AArch64::LDRDui) || (OpcB == AArch64::LDURDi);
659 case AArch64::LDRQpre:
660 return (OpcB == AArch64::LDRQui) || (OpcB == AArch64::LDURQi);
661 case AArch64::LDRWpre:
662 return (OpcB == AArch64::LDRWui) || (OpcB == AArch64::LDURWi);
663 case AArch64::LDRXpre:
664 return (OpcB == AArch64::LDRXui) || (OpcB == AArch64::LDURXi);
665 case AArch64::LDRSWpre:
666 return (OpcB == AArch64::LDRSWui) || (OpcB == AArch64::LDURSWi);
672 int &MinOffset,
int &MaxOffset) {
690 unsigned PairedRegOp = 0) {
691 assert(PairedRegOp < 2 &&
"Unexpected register operand idx.");
697 return MI.getOperand(Idx);
706 int UnscaledStOffset =
710 int UnscaledLdOffset =
714 return (UnscaledStOffset <= UnscaledLdOffset) &&
715 (UnscaledLdOffset + LoadSize <= (UnscaledStOffset + StoreSize));
719 unsigned Opc =
MI.getOpcode();
720 return (
Opc == AArch64::STRWui ||
Opc == AArch64::STURWi ||
721 isNarrowStore(
Opc)) &&
726 switch (
MI.getOpcode()) {
730 case AArch64::LDRBBui:
731 case AArch64::LDRHHui:
732 case AArch64::LDRWui:
733 case AArch64::LDRXui:
735 case AArch64::LDURBBi:
736 case AArch64::LDURHHi:
737 case AArch64::LDURWi:
738 case AArch64::LDURXi:
744 unsigned Opc =
MI.getOpcode();
749 case AArch64::STRBui:
750 case AArch64::STRHui:
751 case AArch64::STRSui:
752 case AArch64::STRDui:
753 case AArch64::STRQui:
754 case AArch64::STRXui:
755 case AArch64::STRWui:
756 case AArch64::STRHHui:
757 case AArch64::STRBBui:
758 case AArch64::LDRBui:
759 case AArch64::LDRHui:
760 case AArch64::LDRSui:
761 case AArch64::LDRDui:
762 case AArch64::LDRQui:
763 case AArch64::LDRXui:
764 case AArch64::LDRWui:
765 case AArch64::LDRHHui:
766 case AArch64::LDRBBui:
770 case AArch64::STZ2Gi:
773 case AArch64::STURSi:
774 case AArch64::STURDi:
775 case AArch64::STURQi:
776 case AArch64::STURWi:
777 case AArch64::STURXi:
778 case AArch64::LDURSi:
779 case AArch64::LDURDi:
780 case AArch64::LDURQi:
781 case AArch64::LDURWi:
782 case AArch64::LDURXi:
785 case AArch64::LDPSWi:
814 unsigned Opc =
MI.getOpcode();
820 case AArch64::LDRBroX:
821 case AArch64::LDRBBroX:
822 case AArch64::LDRSBXroX:
823 case AArch64::LDRSBWroX:
826 case AArch64::LDRHroX:
827 case AArch64::LDRHHroX:
828 case AArch64::LDRSHXroX:
829 case AArch64::LDRSHWroX:
832 case AArch64::LDRWroX:
833 case AArch64::LDRSroX:
834 case AArch64::LDRSWroX:
837 case AArch64::LDRDroX:
838 case AArch64::LDRXroX:
841 case AArch64::LDRQroX:
849 switch (
MI.getOpcode()) {
852 case AArch64::ORRWrs:
853 case AArch64::ADDWri:
861 const LdStPairFlags &Flags) {
863 "Expected promotable zero stores.");
871 if (NextI == MergeMI)
874 unsigned Opc =
I->getOpcode();
875 unsigned MergeMIOpc = MergeMI->getOpcode();
876 bool IsScaled = !
TII->hasUnscaledLdStOffset(
Opc);
877 bool IsMergedMIScaled = !
TII->hasUnscaledLdStOffset(MergeMIOpc);
878 int OffsetStride = IsScaled ?
TII->getMemScale(*
I) : 1;
879 int MergeMIOffsetStride = IsMergedMIScaled ?
TII->getMemScale(*MergeMI) : 1;
881 bool MergeForward =
Flags.getMergeForward();
887 const MachineOperand &BaseRegOp =
889 : AArch64InstrInfo::getLdStBaseOp(*
I);
892 int64_t IOffsetInBytes =
894 int64_t MIOffsetInBytes =
899 if (IOffsetInBytes > MIOffsetInBytes)
900 OffsetImm = MIOffsetInBytes;
902 OffsetImm = IOffsetInBytes;
907 if (!
TII->hasUnscaledLdStOffset(NewOpcode)) {
908 int NewOffsetStride =
TII->getMemScale(NewOpcode);
909 assert(((OffsetImm % NewOffsetStride) == 0) &&
910 "Offset should be a multiple of the store memory scale");
911 OffsetImm = OffsetImm / NewOffsetStride;
917 MachineInstrBuilder MIB;
919 .
addReg(isNarrowStore(
Opc) ? AArch64::WZR : AArch64::XZR)
923 .setMIFlags(
I->mergeFlagsWith(*MergeMI));
926 LLVM_DEBUG(
dbgs() <<
"Creating wider store. Replacing instructions:\n ");
935 I->eraseFromParent();
936 MergeMI->eraseFromParent();
946 auto MBB =
MI.getParent();
954 return MOP.isReg() && MOP.isDef() && !MOP.isDebug() && MOP.getReg() &&
955 TRI->regsOverlap(MOP.getReg(), DefReg);
969 if (MOP.isReg() && MOP.isKill())
973 if (MOP.isReg() && !MOP.isKill())
974 Units.
addReg(MOP.getReg());
981 unsigned InstrNumToSet,
988 unsigned OperandNo = 0;
989 bool RegFound =
false;
990 for (
const auto Op : MergedInstr.
operands()) {
991 if (
Op.getReg() ==
Reg) {
1000 {InstrNumToSet, OperandNo});
1006 const LdStPairFlags &Flags) {
1013 if (NextI == Paired)
1016 int SExtIdx =
Flags.getSExtIdx();
1019 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
Opc);
1020 int OffsetStride = IsUnscaled ?
TII->getMemScale(*
I) : 1;
1022 bool MergeForward =
Flags.getMergeForward();
1024 std::optional<MCPhysReg> RenameReg =
Flags.getRenameReg();
1027 DefinedInBB.
addReg(*RenameReg);
1031 auto GetMatchingSubReg =
1034 TRI->sub_and_superregs_inclusive(*RenameReg)) {
1035 if (
C->contains(SubOrSuper))
1041 std::function<bool(MachineInstr &,
bool)> UpdateMIs =
1042 [
this, RegToRename, GetMatchingSubReg, MergeForward](MachineInstr &
MI,
1045 bool SeenDef =
false;
1046 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
1047 MachineOperand &MOP =
MI.getOperand(OpIdx);
1051 (!MergeForward || !SeenDef ||
1053 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
1056 "Need renamable operands");
1059 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
1060 MatchingReg = GetMatchingSubReg(RC);
1064 MatchingReg = GetMatchingSubReg(
1065 TRI->getMinimalPhysRegClass(MOP.
getReg()));
1072 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
1073 MachineOperand &MOP =
MI.getOperand(OpIdx);
1075 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
1078 "Need renamable operands");
1081 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
1082 MatchingReg = GetMatchingSubReg(RC);
1084 MatchingReg = GetMatchingSubReg(
1085 TRI->getMinimalPhysRegClass(MOP.
getReg()));
1087 "Cannot find matching regs for renaming");
1096 TRI, UINT32_MAX, UpdateMIs);
1109 RegToCheck = RegToRename;
1112 MergeForward ? std::next(
I) :
I,
1113 MergeForward ? std::next(Paired) : Paired))
1115 [
this, RegToCheck](
const MachineOperand &MOP) {
1116 return !MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1118 !TRI->regsOverlap(MOP.getReg(), RegToCheck);
1120 "Rename register used between paired instruction, trashing the "
1130 const MachineOperand &BaseRegOp =
1132 : AArch64InstrInfo::getLdStBaseOp(*
I);
1136 bool PairedIsUnscaled =
TII->hasUnscaledLdStOffset(Paired->getOpcode());
1137 if (IsUnscaled != PairedIsUnscaled) {
1141 int MemSize =
TII->getMemScale(*Paired);
1142 if (PairedIsUnscaled) {
1145 assert(!(PairedOffset %
TII->getMemScale(*Paired)) &&
1146 "Offset should be a multiple of the stride!");
1147 PairedOffset /= MemSize;
1149 PairedOffset *= MemSize;
1156 MachineInstr *RtMI, *Rt2MI;
1157 if (
Offset == PairedOffset + OffsetStride &&
1165 SExtIdx = (SExtIdx + 1) % 2;
1173 assert(!(OffsetImm %
TII->getMemScale(*RtMI)) &&
1174 "Unscaled offset cannot be scaled.");
1175 OffsetImm /=
TII->getMemScale(*RtMI);
1179 MachineInstrBuilder MIB;
1184 MachineOperand &PairedRegOp = RtMI == &*Paired ? RegOp0 : RegOp1;
1186 if (RegOp0.
isUse()) {
1187 if (!MergeForward) {
1198 for (
auto It = std::next(
I); It != Paired && PairedRegOp.
isKill(); ++It)
1199 if (It->readsRegister(PairedRegOp.
getReg(),
TRI))
1207 for (MachineInstr &
MI :
1208 make_range(std::next(
I->getIterator()), Paired->getIterator()))
1225 .setMIFlags(
I->mergeFlagsWith(*Paired));
1230 dbgs() <<
"Creating pair load/store. Replacing instructions:\n ");
1235 if (SExtIdx != -1) {
1240 MachineOperand &DstMO = MIB->
getOperand(SExtIdx);
1245 Register DstRegW =
TRI->getSubReg(DstRegX, AArch64::sub_32);
1254 MachineInstrBuilder MIBKill =
1255 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(TargetOpcode::KILL), DstRegW)
1257 .
addReg(DstRegX, RegState::Define);
1260 MachineInstrBuilder MIBSXTW =
1261 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(AArch64::SBFMXri), DstRegX)
1301 if (
I->peekDebugInstrNum()) {
1309 unsigned NewInstrNum;
1310 if (DstRegX ==
I->getOperand(0).getReg()) {
1319 if (Paired->peekDebugInstrNum()) {
1327 unsigned NewInstrNum;
1328 if (DstRegX == Paired->getOperand(0).getReg()) {
1341 }
else if (
Opc == AArch64::LDR_ZXI ||
Opc == AArch64::STR_ZXI) {
1347 AArch64::ZPRRegClass.contains(MOp1.
getReg()) &&
"Invalid register.");
1348 MOp0.
setReg(AArch64::Q0 + (MOp0.
getReg() - AArch64::Z0));
1349 MOp1.
setReg(AArch64::Q0 + (MOp1.
getReg() - AArch64::Z0));
1380 if (
I->peekDebugInstrNum()) {
1385 if (Paired->peekDebugInstrNum()) {
1405 SmallSetVector<Register, 4>
Ops;
1406 for (
const MachineOperand &MO :
1408 if (MO.isReg() && MO.isImplicit() && MO.isDef())
1409 Ops.insert(MO.getReg());
1410 for (
const MachineOperand &MO :
1412 if (MO.isReg() && MO.isImplicit() && MO.isDef())
1413 Ops.insert(MO.getReg());
1415 MIB.addDef(
Op, RegState::Implicit);
1417 CopyImplicitOps(
I, Paired);
1420 I->eraseFromParent();
1421 Paired->eraseFromParent();
1430 next_nodbg(LoadI, LoadI->getParent()->end());
1432 int LoadSize =
TII->getMemScale(*LoadI);
1433 int StoreSize =
TII->getMemScale(*StoreI);
1437 bool IsStoreXReg =
TRI->getRegClass(AArch64::GPR64RegClassID)->contains(StRt);
1440 TRI->getRegClass(AArch64::GPR32RegClassID)->contains(StRt)) &&
1441 "Unexpected RegClass");
1443 MachineInstr *BitExtMI;
1444 if (LoadSize == StoreSize && (LoadSize == 4 || LoadSize == 8)) {
1447 if (StRt == LdRt && LoadSize == 8) {
1448 for (MachineInstr &
MI :
make_range(StoreI->getIterator(),
1449 LoadI->getIterator())) {
1450 if (
MI.killsRegister(StRt,
TRI)) {
1451 MI.clearRegisterKills(StRt,
TRI);
1458 LoadI->eraseFromParent();
1463 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1464 TII->get(IsStoreXReg ? AArch64::ORRXrs : AArch64::ORRWrs), LdRt)
1465 .
addReg(IsStoreXReg ? AArch64::XZR : AArch64::WZR)
1474 bool IsUnscaled =
TII->hasUnscaledLdStOffset(*LoadI);
1475 assert(IsUnscaled ==
TII->hasUnscaledLdStOffset(*StoreI) &&
1476 "Unsupported ld/st match");
1477 assert(LoadSize <= StoreSize &&
"Invalid load size");
1478 int UnscaledLdOffset =
1482 int UnscaledStOffset =
1486 int Width = LoadSize * 8;
1489 LdRt, AArch64::sub_32, &AArch64::GPR64RegClass))
1492 assert((UnscaledLdOffset >= UnscaledStOffset &&
1493 (UnscaledLdOffset + LoadSize) <= UnscaledStOffset + StoreSize) &&
1496 int Immr = 8 * (UnscaledLdOffset - UnscaledStOffset);
1497 int Imms = Immr + Width - 1;
1498 if (UnscaledLdOffset == UnscaledStOffset) {
1499 uint32_t AndMaskEncoded = ((IsStoreXReg ? 1 : 0) << 12)
1505 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1506 TII->get(IsStoreXReg ? AArch64::ANDXri : AArch64::ANDWri),
1511 }
else if (IsStoreXReg && Imms == 31) {
1514 assert(Immr <= Imms &&
"Expected LSR alias of UBFM");
1515 BitExtMI =
BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1516 TII->get(AArch64::UBFMWri),
1517 TRI->getSubReg(DestReg, AArch64::sub_32))
1518 .
addReg(
TRI->getSubReg(StRt, AArch64::sub_32))
1524 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1525 TII->get(IsStoreXReg ? AArch64::UBFMXri : AArch64::UBFMWri),
1535 for (MachineInstr &
MI :
make_range(StoreI->getIterator(),
1537 if (
MI.killsRegister(StRt,
TRI)) {
1538 MI.clearRegisterKills(StRt,
TRI);
1553 LoadI->eraseFromParent();
1563 if (
Offset % OffsetStride)
1575 return (Num + PowOf2 - 1) & ~(PowOf2 - 1);
1592bool AArch64LoadStoreOpt::findMatchingStore(
1597 MachineInstr &LoadMI = *
I;
1607 ModifiedRegUnits.
clear();
1608 UsedRegUnits.
clear();
1613 MachineInstr &
MI = *
MBBI;
1617 if (!
MI.isTransient())
1643 if (!ModifiedRegUnits.
available(BaseReg))
1656 LdStPairFlags &Flags,
1659 if (
MI.hasOrderedMemoryRef() ||
TII->isLdStPairSuppressed(
MI))
1664 !
TII->isLdStPairSuppressed(FirstMI) &&
1665 "FirstMI shouldn't get here if either of these checks are true.");
1669 MI.getMF()->needsWinCFI())
1673 unsigned OpcB =
MI.getOpcode();
1681 if (OpcA == AArch64::LDR_ZXI || OpcA == AArch64::STR_ZXI ||
1682 OpcB == AArch64::LDR_ZXI || OpcB == AArch64::STR_ZXI)
1690 bool IsValidLdStrOpc, PairIsValidLdStrOpc;
1692 assert(IsValidLdStrOpc &&
1693 "Given Opc should be a Load or Store with an immediate");
1696 Flags.setSExtIdx(NonSExtOpc == OpcA ? 1 : 0);
1702 if (!PairIsValidLdStrOpc)
1707 if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
1710 TII->getMemScale(FirstMI) ==
TII->getMemScale(
MI);
1719 return TII->hasUnscaledLdStOffset(OpcA) !=
TII->hasUnscaledLdStOffset(OpcB) &&
1728 auto *RegClass =
TRI->getMinimalPhysRegClass(MOP.
getReg());
1735 if (RegClass->HasDisjunctSubRegs && RegClass->CoveredBySubRegs &&
1736 (
TRI->getSubRegisterClass(RegClass, AArch64::dsub0) ||
1737 TRI->getSubRegisterClass(RegClass, AArch64::qsub0) ||
1738 TRI->getSubRegisterClass(RegClass, AArch64::zsub0))) {
1741 <<
" Cannot rename operands with multiple disjunct subregisters ("
1752 return TRI->isSuperOrSubRegisterEq(
MI.getOperand(0).getReg(),
1775 return MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
1776 MOP.isImplicit() && MOP.isKill() &&
1777 TRI->regsOverlap(RegToRename, MOP.getReg());
1783 bool FoundDef =
false;
1814 if (
MI.isPseudo()) {
1815 LLVM_DEBUG(
dbgs() <<
" Cannot rename pseudo/bundle instruction\n");
1819 for (
auto &MOP :
MI.operands()) {
1821 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1831 for (
auto &MOP :
MI.operands()) {
1833 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1846 const AArch64Options &CLOpts =
1849 CLOpts.load_store_scan_limit, CheckMIs))
1853 LLVM_DEBUG(
dbgs() <<
" Did not find definition for register in BB\n");
1881 LLVM_DEBUG(dbgs() <<
"Checking " << MI);
1883 if (MI.getFlag(MachineInstr::FrameSetup)) {
1884 LLVM_DEBUG(dbgs() <<
" Cannot rename framesetup instructions "
1889 for (
auto &MOP :
MI.operands()) {
1890 if (!MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1891 !TRI->regsOverlap(MOP.getReg(), RegToRename))
1893 if (!canRenameMOP(MI, MOP, TRI)) {
1894 LLVM_DEBUG(dbgs() <<
" Cannot rename " << MOP <<
" in " << MI);
1920 auto AnySubOrSuperRegCalleePreserved = [&MF,
TRI](
MCPhysReg PR) {
1921 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1923 return TRI->isCalleeSavedPhysReg(SubOrSuper, MF);
1929 auto CanBeUsedForAllClasses = [&RequiredClasses,
TRI](
MCPhysReg PR) {
1932 TRI->sub_and_superregs_inclusive(PR),
1933 [
C](
MCPhysReg SubOrSuper) { return C->contains(SubOrSuper); });
1937 auto *RegClass =
TRI->getMinimalPhysRegClass(
Reg);
1940 !
RegInfo.isReserved(PR) && !AnySubOrSuperRegCalleePreserved(PR) &&
1941 CanBeUsedForAllClasses(PR)) {
1949 <<
TRI->getRegClassName(RegClass) <<
"\n");
1950 return std::nullopt;
1961 std::optional<MCPhysReg> RenameReg;
1970 const bool IsLoad = FirstMI.
mayLoad();
1972 if (!MaybeCanRename) {
1975 RequiredClasses,
TRI)};
1981 if (*MaybeCanRename) {
1983 RequiredClasses,
TRI);
1992 LdStPairFlags &Flags,
unsigned Limit,
1993 bool FindNarrowMerge) {
1996 MachineInstr &FirstMI = *
I;
2000 bool IsUnscaled =
TII->hasUnscaledLdStOffset(FirstMI);
2004 int OffsetStride = IsUnscaled ?
TII->getMemScale(FirstMI) : 1;
2007 std::optional<bool> MaybeCanRename;
2008 if (!Subtarget->
getCLOpts().load_store_renaming)
2009 MaybeCanRename = {
false};
2011 SmallPtrSet<const TargetRegisterClass *, 5> RequiredClasses;
2012 LiveRegUnits UsedInBetween;
2015 Flags.clearRenameReg();
2019 ModifiedRegUnits.
clear();
2020 UsedRegUnits.
clear();
2023 SmallVector<MachineInstr *, 4> MemInsns;
2028 MachineInstr &
MI = *
MBBI;
2035 if (!
MI.isTransient())
2038 Flags.setSExtIdx(-1);
2041 assert(
MI.mayLoadOrStore() &&
"Expected memory operation.");
2050 bool MIIsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2051 if (IsUnscaled != MIIsUnscaled) {
2055 int MemSize =
TII->getMemScale(
MI);
2059 if (MIOffset % MemSize) {
2065 MIOffset /= MemSize;
2067 MIOffset *= MemSize;
2073 if (BaseReg == MIBaseReg) {
2079 bool IsOutOfBounds = MIOffset !=
TII->getMemScale(
MI);
2080 bool IsBaseRegUsed = !UsedRegUnits.
available(
2082 bool IsBaseRegModified = !ModifiedRegUnits.
available(
2087 bool IsMIRegTheSame =
2090 if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified ||
2098 if ((
Offset != MIOffset + OffsetStride) &&
2099 (
Offset + OffsetStride != MIOffset)) {
2108 if (FindNarrowMerge) {
2113 if ((!IsUnscaled &&
alignTo(MinOffset, 2) != MinOffset) ||
2130 <<
"keep looking.\n");
2136 if (IsUnscaled && (
alignTo(MinOffset, OffsetStride) != MinOffset)) {
2141 <<
"Offset doesn't fit due to alignment requirements, "
2142 <<
"keep looking.\n");
2153 if (!ModifiedRegUnits.
available(BaseReg))
2156 const bool SameLoadReg =
MayLoad &&
TRI->isSuperOrSubRegisterEq(
2163 bool RtNotModified =
2165 bool RtNotUsed = !(
MI.mayLoad() && !SameLoadReg &&
2168 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 2nd into 1st insn:\n"
2170 << (RtNotModified ?
"true" :
"false") <<
"\n"
2172 << (RtNotUsed ?
"true" :
"false") <<
"\n");
2174 if (RtNotModified && RtNotUsed && !
mayAlias(
MI, MemInsns, AA)) {
2179 std::optional<MCPhysReg> RenameReg =
2181 Reg, DefinedInBB, UsedInBetween,
2182 RequiredClasses,
TRI);
2188 <<
"keep looking.\n");
2191 Flags.setRenameReg(*RenameReg);
2194 Flags.setMergeForward(
false);
2196 Flags.clearRenameReg();
2207 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 1st into 2nd insn:\n"
2209 <<
"' not modified: "
2210 << (RtNotModified ?
"true" :
"false") <<
"\n");
2212 if (RtNotModified && !
mayAlias(FirstMI, MemInsns, AA)) {
2214 Flags.setMergeForward(
true);
2215 Flags.clearRenameReg();
2220 MaybeCanRename, FirstMI,
MI,
Reg, DefinedInBB, UsedInBetween,
2221 RequiredClasses,
TRI);
2223 Flags.setMergeForward(
true);
2224 Flags.setRenameReg(*RenameReg);
2228 LLVM_DEBUG(
dbgs() <<
"Unable to combine these instructions due to "
2229 <<
"interference in between, keep looking.\n");
2245 if (!ModifiedRegUnits.
available(BaseReg)) {
2251 if (
MI.mayLoadOrStore())
2259 assert((
MI.getOpcode() == AArch64::SUBXri ||
2260 MI.getOpcode() == AArch64::ADDXri) &&
2261 "Expected a register update instruction");
2262 auto End =
MI.getParent()->end();
2263 if (MaybeCFI ==
End ||
2264 MaybeCFI->getOpcode() != TargetOpcode::CFI_INSTRUCTION ||
2267 MI.getOperand(0).getReg() != AArch64::SP)
2271 unsigned CFIIndex = MaybeCFI->getOperand(0).getCFIIndex();
2282std::optional<MachineBasicBlock::iterator> AArch64LoadStoreOpt::mergeUpdateInsn(
2284 bool IsForward,
bool IsPreIdx,
bool MergeEither) {
2285 assert((Update->getOpcode() == AArch64::ADDXri ||
2286 Update->getOpcode() == AArch64::SUBXri) &&
2287 "Unexpected base register update instruction to merge!");
2303 if (std::any_of(std::next(CFI),
I, [](
const auto &Insn) {
2304 return Insn.getOpcode() == TargetOpcode::CFI_INSTRUCTION;
2306 return std::nullopt;
2308 MachineBasicBlock *
MBB = InsertPt->getParent();
2317 if (NextI == Update)
2320 int Value = Update->getOperand(2).getImm();
2322 "Can't merge 1 << 12 offset into pre-/post-indexed load / store");
2323 if (Update->getOpcode() == AArch64::SUBXri)
2328 MachineInstrBuilder MIB;
2329 int Scale, MinOffset, MaxOffset;
2333 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2335 .
add(Update->getOperand(0))
2343 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2345 .
add(Update->getOperand(0))
2370 I->eraseFromParent();
2371 Update->eraseFromParent();
2379 unsigned Offset,
int Scale) {
2380 assert((Update->getOpcode() == AArch64::MOVKWi) &&
2381 "Unexpected const mov instruction to merge!");
2385 MachineInstr &MemMI = *
I;
2386 unsigned Mask = (1 << 12) * Scale - 1;
2391 MachineInstrBuilder AddMIB, MemMIB;
2395 BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(AArch64::ADDXri))
2403 MemMIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2411 ++NumConstOffsetFolded;
2426 I->eraseFromParent();
2427 PrevI->eraseFromParent();
2428 Update->eraseFromParent();
2433bool AArch64LoadStoreOpt::isMatchingUpdateInsn(MachineInstr &MemMI,
2435 unsigned BaseReg,
int Offset) {
2436 switch (
MI.getOpcode()) {
2439 case AArch64::SUBXri:
2440 case AArch64::ADDXri:
2443 if (!
MI.getOperand(2).isImm())
2451 if (
MI.getOperand(0).getReg() != BaseReg ||
2452 MI.getOperand(1).getReg() != BaseReg)
2455 int UpdateOffset =
MI.getOperand(2).getImm();
2456 if (
MI.getOpcode() == AArch64::SUBXri)
2457 UpdateOffset = -UpdateOffset;
2461 int Scale, MinOffset, MaxOffset;
2463 if (UpdateOffset % Scale != 0)
2467 int ScaledOffset = UpdateOffset / Scale;
2468 if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset)
2480bool AArch64LoadStoreOpt::isMatchingMovConstInsn(MachineInstr &MemMI,
2486 if (
MI.getOpcode() == AArch64::MOVKWi &&
2487 TRI->isSuperOrSubRegisterEq(IndexReg,
MI.getOperand(1).getReg())) {
2496 MachineInstr &MovzMI = *
MBBI;
2498 if (MovzMI.
getOpcode() == AArch64::MOVZWi &&
2501 unsigned High =
MI.getOperand(2).getImm() <<
MI.getOperand(3).getImm();
2504 return Offset >> 24 == 0;
2513 MachineInstr &MemMI = *
I;
2518 TII->getMemScale(MemMI);
2523 if (MIUnscaledOffset != UnscaledOffset)
2534 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2536 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2543 ModifiedRegUnits.
clear();
2544 UsedRegUnits.
clear();
2550 const bool BaseRegSP =
BaseReg == AArch64::SP;
2551 if (BaseRegSP &&
I->getMF()->needsWinCFI()) {
2559 MachineBasicBlock *CurMBB =
I->getParent();
2566 MachineInstr &
MI = *
MBBI;
2570 if (!
MI.isTransient())
2574 if (isMatchingUpdateInsn(*
I,
MI, BaseReg, UnscaledOffset))
2585 if (!ModifiedRegUnits.
available(BaseReg) ||
2587 (BaseRegSP &&
MBBI->mayLoadOrStore()))
2591 if (!VisitSucc || Limit <=
Count)
2596 MachineBasicBlock *SuccToVisit =
nullptr;
2597 unsigned LiveSuccCount = 0;
2598 for (MachineBasicBlock *Succ : CurMBB->
successors()) {
2599 for (MCRegAliasIterator AI(BaseReg,
TRI,
true); AI.isValid(); ++AI) {
2600 if (Succ->isLiveIn(*AI)) {
2601 if (LiveSuccCount++)
2603 if (Succ->pred_size() == 1)
2611 CurMBB = SuccToVisit;
2622 MachineInstr &MemMI = *
I;
2641 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i)
2642 if (DestReg[i] == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg[i]))
2646 const bool BaseRegSP =
BaseReg == AArch64::SP;
2647 if (BaseRegSP &&
I->getMF()->needsWinCFI()) {
2654 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
2655 unsigned RedZoneSize =
2660 ModifiedRegUnits.
clear();
2661 UsedRegUnits.
clear();
2663 bool MemAccessBeforeSPPreInc =
false;
2667 MachineInstr &
MI = *
MBBI;
2671 if (!
MI.isTransient())
2675 if (isMatchingUpdateInsn(*
I,
MI, BaseReg,
Offset)) {
2678 if (MemAccessBeforeSPPreInc &&
MBBI->getOperand(2).getImm() > RedZoneSize)
2688 if (!ModifiedRegUnits.
available(BaseReg) ||
2696 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
2697 (DestReg[0].isValid() && !(ModifiedRegUnits.
available(DestReg[0]) &&
2699 (DestReg[1].isValid() && !(ModifiedRegUnits.
available(DestReg[1]) &&
2701 MergeEither =
false;
2706 if (BaseRegSP &&
MBBI->mayLoadOrStore())
2707 MemAccessBeforeSPPreInc =
true;
2713AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
2717 MachineInstr &MemMI = *
I;
2736 ModifiedRegUnits.
clear();
2737 UsedRegUnits.
clear();
2741 MachineInstr &
MI = *
MBBI;
2745 if (!
MI.isTransient())
2749 if (isMatchingMovConstInsn(*
I,
MI, IndexReg,
Offset)) {
2758 if (!ModifiedRegUnits.
available(IndexReg) ||
2766bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
2768 MachineInstr &
MI = *
MBBI;
2770 if (
MI.hasOrderedMemoryRef())
2783 if (findMatchingStore(
MBBI, Subtarget->
getCLOpts().load_store_scan_limit,
2785 ++NumLoadsFromStoresPromoted;
2789 MBBI = promoteLoadFromStore(
MBBI, StoreI);
2796bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
2799 MachineInstr &
MI = *
MBBI;
2802 if (!
TII->isCandidateToMergeOrPair(
MI))
2806 LdStPairFlags
Flags;
2811 ++NumZeroStoresPromoted;
2815 MBBI = mergeNarrowZeroStores(
MBBI, MergeMI, Flags);
2824 MachineInstr &
MI = *
MBBI;
2827 if (!
TII->isCandidateToMergeOrPair(
MI))
2831 if (
MI.mayLoad() && Subtarget->hasDisableLdp())
2835 if (
MI.mayStore() && Subtarget->hasDisableStp())
2841 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2843 int OffsetStride = IsUnscaled ?
TII->getMemScale(
MI) : 1;
2851 LdStPairFlags
Flags;
2861 auto Prev = std::prev(
MBBI);
2864 MachineMemOperand *MemOp =
2865 MI.memoperands_empty() ? nullptr :
MI.memoperands().front();
2870 if ((
MI.mayLoad() && Subtarget->hasLdpAlignedOnly()) ||
2871 (
MI.mayStore() && Subtarget->hasStpAlignedOnly())) {
2873 if (!MemOp || !MemOp->getMemoryType().isValid()) {
2874 NumFailedAlignmentCheck++;
2880 uint64_t MemAlignment = MemOp->getAlign().value();
2882 Align(MemOp->getSize().getValue().getKnownMinValue()).value();
2884 if (MemAlignment < 2 * TypeAlignment) {
2885 NumFailedAlignmentCheck++;
2891 if (
TII->hasUnscaledLdStOffset(
MI))
2892 ++NumUnscaledPairCreated;
2894 MBBI = mergePairedInsns(
MBBI, Paired, Flags);
2897 for (
auto I = std::next(Prev);
I !=
MBBI;
I++)
2903bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
2905 MachineInstr &
MI = *
MBBI;
2914 if (
MBBI->hasOrderedMemoryRef() &&
2924 Update = findMatchingUpdateInsnForward(
2928 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2937 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2946 Update = findMatchingUpdateInsnBackward(
2947 MBBI, Subtarget->
getCLOpts().update_scan_limit, MergeEither);
2950 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
true,
2951 true, MergeEither)) {
2960 int UnscaledOffset =
2968 Update = findMatchingUpdateInsnForward(
2969 MBBI, UnscaledOffset, Subtarget->
getCLOpts().update_scan_limit);
2972 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2985 MachineInstr &
MI = *
MBBI;
2990 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
3001 Update = findMatchingConstOffsetBackward(
3003 if (Update !=
E && (
Offset & (Scale - 1)) == 0) {
3015 switch (GPRStoreOpc) {
3017 case AArch64::STRBBui:
3018 return AArch64::STRBui;
3019 case AArch64::STRHHui:
3020 return AArch64::STRHui;
3021 case AArch64::STRWui:
3022 return AArch64::STRSui;
3023 case AArch64::STRXui:
3024 return AArch64::STRDui;
3026 case AArch64::STURBBi:
3027 return AArch64::STURBi;
3028 case AArch64::STURHHi:
3029 return AArch64::STURHi;
3030 case AArch64::STURWi:
3031 return AArch64::STURSi;
3032 case AArch64::STURXi:
3033 return AArch64::STURDi;
3035 case AArch64::STRBBroW:
3036 return AArch64::STRBroW;
3037 case AArch64::STRBBroX:
3038 return AArch64::STRBroX;
3039 case AArch64::STRHHroW:
3040 return AArch64::STRHroW;
3041 case AArch64::STRHHroX:
3042 return AArch64::STRHroX;
3043 case AArch64::STRWroW:
3044 return AArch64::STRSroW;
3045 case AArch64::STRWroX:
3046 return AArch64::STRSroX;
3047 case AArch64::STRXroW:
3048 return AArch64::STRDroW;
3049 case AArch64::STRXroX:
3050 return AArch64::STRDroX;
3060 case AArch64::UMOVvi8_idx0:
3061 return AArch64::bsub;
3062 case AArch64::UMOVvi16_idx0:
3063 return AArch64::hsub;
3064 case AArch64::UMOVvi32_idx0:
3065 return AArch64::ssub;
3066 case AArch64::UMOVvi64_idx0:
3067 return AArch64::dsub;
3073bool AArch64LoadStoreOpt::tryToReplaceUMOVStore(
3075 MachineInstr &StoreMI = *
MBBI;
3098 MachineInstr *UMOVMI =
nullptr;
3100 unsigned SubRegIdx = 0;
3102 for (
auto It =
MBBI; It !=
B;) {
3103 MachineInstr &
MI = *--It;
3104 if (
MI.isDebugInstr())
3108 if (
MI.readsRegister(StoreValReg,
TRI))
3110 if (
MI.modifiesRegister(StoreValReg,
TRI)) {
3123 TRI->getRegSizeInBits(*
TRI->getMinimalPhysRegClass(FPRReg)))
3132 if (It->modifiesRegister(VecReg,
TRI))
3134 if (!VecRegKilled && It->killsRegister(VecReg,
TRI))
3135 VecRegKilled =
true;
3142 It->clearRegisterKills(VecReg,
TRI);
3144 LLVM_DEBUG(
dbgs() <<
"Folding UMOV + store: " << *UMOVMI <<
" + "
3156 ++NumUMOVFoldedToFPRStore;
3160bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &
MBB,
3161 bool EnableNarrowZeroStOpt) {
3193 if (EnableNarrowZeroStOpt)
3217 DefinedInBB.
clear();
3226 if (
TII->isPairableLdStInst(*
MBBI) && tryToPairLdStInst(
MBBI))
3270 if (tryToReplaceUMOVStore(
MBBI))
3292 bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
3293 for (
auto &
MBB : Fn) {
3311bool AArch64LoadStoreOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
3314 AArch64LoadStoreOpt Impl;
3315 Impl.AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
3316 return Impl.runOnMachineFunction(MF);
3322 return new AArch64LoadStoreOptLegacy();
3328 AArch64LoadStoreOpt Impl;
3332 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()
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