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))
1661 LdStPairFlags &Flags,
1664 if (
MI.hasOrderedMemoryRef() ||
TII->isLdStPairSuppressed(
MI))
1669 !
TII->isLdStPairSuppressed(FirstMI) &&
1670 "FirstMI shouldn't get here if either of these checks are true.");
1677 unsigned OpcB =
MI.getOpcode();
1685 if (OpcA == AArch64::LDR_ZXI || OpcA == AArch64::STR_ZXI ||
1686 OpcB == AArch64::LDR_ZXI || OpcB == AArch64::STR_ZXI)
1694 bool IsValidLdStrOpc, PairIsValidLdStrOpc;
1696 assert(IsValidLdStrOpc &&
1697 "Given Opc should be a Load or Store with an immediate");
1700 Flags.setSExtIdx(NonSExtOpc == OpcA ? 1 : 0);
1706 if (!PairIsValidLdStrOpc)
1711 if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
1714 TII->getMemScale(FirstMI) ==
TII->getMemScale(
MI);
1723 return TII->hasUnscaledLdStOffset(OpcA) !=
TII->hasUnscaledLdStOffset(OpcB) &&
1732 auto *RegClass =
TRI->getMinimalPhysRegClass(MOP.
getReg());
1739 if (RegClass->HasDisjunctSubRegs && RegClass->CoveredBySubRegs &&
1740 (
TRI->getSubRegisterClass(RegClass, AArch64::dsub0) ||
1741 TRI->getSubRegisterClass(RegClass, AArch64::qsub0) ||
1742 TRI->getSubRegisterClass(RegClass, AArch64::zsub0))) {
1745 <<
" Cannot rename operands with multiple disjunct subregisters ("
1756 return TRI->isSuperOrSubRegisterEq(
MI.getOperand(0).getReg(),
1779 return MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
1780 MOP.isImplicit() && MOP.isKill() &&
1781 TRI->regsOverlap(RegToRename, MOP.getReg());
1787 bool FoundDef =
false;
1818 if (
MI.isPseudo()) {
1819 LLVM_DEBUG(
dbgs() <<
" Cannot rename pseudo/bundle instruction\n");
1823 for (
auto &MOP :
MI.operands()) {
1825 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1835 for (
auto &MOP :
MI.operands()) {
1837 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1850 const AArch64Options &CLOpts =
1853 CLOpts.load_store_scan_limit, CheckMIs))
1857 LLVM_DEBUG(
dbgs() <<
" Did not find definition for register in BB\n");
1885 LLVM_DEBUG(dbgs() <<
"Checking " << MI);
1887 if (MI.getFlag(MachineInstr::FrameSetup)) {
1888 LLVM_DEBUG(dbgs() <<
" Cannot rename framesetup instructions "
1893 for (
auto &MOP :
MI.operands()) {
1894 if (!MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1895 !TRI->regsOverlap(MOP.getReg(), RegToRename))
1897 if (!canRenameMOP(MI, MOP, TRI)) {
1898 LLVM_DEBUG(dbgs() <<
" Cannot rename " << MOP <<
" in " << MI);
1924 auto AnySubOrSuperRegCalleePreserved = [&MF,
TRI](
MCPhysReg PR) {
1925 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1927 return TRI->isCalleeSavedPhysReg(SubOrSuper, MF);
1933 auto CanBeUsedForAllClasses = [&RequiredClasses,
TRI](
MCPhysReg PR) {
1936 TRI->sub_and_superregs_inclusive(PR),
1937 [
C](
MCPhysReg SubOrSuper) { return C->contains(SubOrSuper); });
1941 auto *RegClass =
TRI->getMinimalPhysRegClass(
Reg);
1944 !
RegInfo.isReserved(PR) && !AnySubOrSuperRegCalleePreserved(PR) &&
1945 CanBeUsedForAllClasses(PR)) {
1953 <<
TRI->getRegClassName(RegClass) <<
"\n");
1954 return std::nullopt;
1965 std::optional<MCPhysReg> RenameReg;
1974 const bool IsLoad = FirstMI.
mayLoad();
1976 if (!MaybeCanRename) {
1979 RequiredClasses,
TRI)};
1985 if (*MaybeCanRename) {
1987 RequiredClasses,
TRI);
1996 LdStPairFlags &Flags,
unsigned Limit,
1997 bool FindNarrowMerge) {
2000 MachineInstr &FirstMI = *
I;
2004 bool IsUnscaled =
TII->hasUnscaledLdStOffset(FirstMI);
2008 int OffsetStride = IsUnscaled ?
TII->getMemScale(FirstMI) : 1;
2011 std::optional<bool> MaybeCanRename;
2012 if (!Subtarget->
getCLOpts().load_store_renaming)
2013 MaybeCanRename = {
false};
2015 SmallPtrSet<const TargetRegisterClass *, 5> RequiredClasses;
2016 LiveRegUnits UsedInBetween;
2019 Flags.clearRenameReg();
2023 ModifiedRegUnits.
clear();
2024 UsedRegUnits.
clear();
2027 SmallVector<MachineInstr *, 4> MemInsns;
2032 MachineInstr &
MI = *
MBBI;
2039 if (!
MI.isTransient())
2042 Flags.setSExtIdx(-1);
2045 assert(
MI.mayLoadOrStore() &&
"Expected memory operation.");
2054 bool MIIsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2055 if (IsUnscaled != MIIsUnscaled) {
2059 int MemSize =
TII->getMemScale(
MI);
2063 if (MIOffset % MemSize) {
2069 MIOffset /= MemSize;
2071 MIOffset *= MemSize;
2077 if (BaseReg == MIBaseReg) {
2083 bool IsOutOfBounds = MIOffset !=
TII->getMemScale(
MI);
2084 bool IsBaseRegUsed = !UsedRegUnits.
available(
2086 bool IsBaseRegModified = !ModifiedRegUnits.
available(
2091 bool IsMIRegTheSame =
2094 if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified ||
2102 if ((
Offset != MIOffset + OffsetStride) &&
2103 (
Offset + OffsetStride != MIOffset)) {
2112 if (FindNarrowMerge) {
2117 if ((!IsUnscaled &&
alignTo(MinOffset, 2) != MinOffset) ||
2134 <<
"keep looking.\n");
2140 if (IsUnscaled && (
alignTo(MinOffset, OffsetStride) != MinOffset)) {
2145 <<
"Offset doesn't fit due to alignment requirements, "
2146 <<
"keep looking.\n");
2157 if (!ModifiedRegUnits.
available(BaseReg))
2160 const bool SameLoadReg =
MayLoad &&
TRI->isSuperOrSubRegisterEq(
2167 bool RtNotModified =
2169 bool RtNotUsed = !(
MI.mayLoad() && !SameLoadReg &&
2172 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 2nd into 1st insn:\n"
2174 << (RtNotModified ?
"true" :
"false") <<
"\n"
2176 << (RtNotUsed ?
"true" :
"false") <<
"\n");
2178 if (RtNotModified && RtNotUsed && !
mayAlias(
MI, MemInsns, AA)) {
2183 std::optional<MCPhysReg> RenameReg =
2185 Reg, DefinedInBB, UsedInBetween,
2186 RequiredClasses,
TRI);
2192 <<
"keep looking.\n");
2195 Flags.setRenameReg(*RenameReg);
2198 Flags.setMergeForward(
false);
2200 Flags.clearRenameReg();
2211 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 1st into 2nd insn:\n"
2213 <<
"' not modified: "
2214 << (RtNotModified ?
"true" :
"false") <<
"\n");
2216 if (RtNotModified && !
mayAlias(FirstMI, MemInsns, AA)) {
2218 Flags.setMergeForward(
true);
2219 Flags.clearRenameReg();
2224 MaybeCanRename, FirstMI,
MI,
Reg, DefinedInBB, UsedInBetween,
2225 RequiredClasses,
TRI);
2227 Flags.setMergeForward(
true);
2228 Flags.setRenameReg(*RenameReg);
2232 LLVM_DEBUG(
dbgs() <<
"Unable to combine these instructions due to "
2233 <<
"interference in between, keep looking.\n");
2249 if (!ModifiedRegUnits.
available(BaseReg)) {
2255 if (
MI.mayLoadOrStore())
2263 assert((
MI.getOpcode() == AArch64::SUBXri ||
2264 MI.getOpcode() == AArch64::ADDXri) &&
2265 "Expected a register update instruction");
2266 auto End =
MI.getParent()->end();
2267 if (MaybeCFI == End ||
2268 MaybeCFI->getOpcode() != TargetOpcode::CFI_INSTRUCTION ||
2271 MI.getOperand(0).getReg() != AArch64::SP)
2275 unsigned CFIIndex = MaybeCFI->getOperand(0).getCFIIndex();
2286std::optional<MachineBasicBlock::iterator> AArch64LoadStoreOpt::mergeUpdateInsn(
2288 bool IsForward,
bool IsPreIdx,
bool MergeEither) {
2289 assert((Update->getOpcode() == AArch64::ADDXri ||
2290 Update->getOpcode() == AArch64::SUBXri) &&
2291 "Unexpected base register update instruction to merge!");
2307 if (std::any_of(std::next(CFI),
I, [](
const auto &Insn) {
2308 return Insn.getOpcode() == TargetOpcode::CFI_INSTRUCTION;
2310 return std::nullopt;
2312 MachineBasicBlock *
MBB = InsertPt->getParent();
2321 if (NextI == Update)
2324 int Value = Update->getOperand(2).getImm();
2326 "Can't merge 1 << 12 offset into pre-/post-indexed load / store");
2327 if (Update->getOpcode() == AArch64::SUBXri)
2332 MachineInstrBuilder MIB;
2333 int Scale, MinOffset, MaxOffset;
2337 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2339 .
add(Update->getOperand(0))
2347 MIB =
BuildMI(*InsertPt->getParent(), InsertPt, InsertPt->getDebugLoc(),
2349 .
add(Update->getOperand(0))
2374 I->eraseFromParent();
2375 Update->eraseFromParent();
2383 unsigned Offset,
int Scale) {
2384 assert((Update->getOpcode() == AArch64::MOVKWi) &&
2385 "Unexpected const mov instruction to merge!");
2389 MachineInstr &MemMI = *
I;
2390 unsigned Mask = (1 << 12) * Scale - 1;
2395 MachineInstrBuilder AddMIB, MemMIB;
2399 BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(AArch64::ADDXri))
2407 MemMIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2415 ++NumConstOffsetFolded;
2430 I->eraseFromParent();
2431 PrevI->eraseFromParent();
2432 Update->eraseFromParent();
2437bool AArch64LoadStoreOpt::isMatchingUpdateInsn(MachineInstr &MemMI,
2439 unsigned BaseReg,
int Offset) {
2440 switch (
MI.getOpcode()) {
2443 case AArch64::SUBXri:
2444 case AArch64::ADDXri:
2447 if (!
MI.getOperand(2).isImm())
2455 if (
MI.getOperand(0).getReg() != BaseReg ||
2456 MI.getOperand(1).getReg() != BaseReg)
2459 int UpdateOffset =
MI.getOperand(2).getImm();
2460 if (
MI.getOpcode() == AArch64::SUBXri)
2461 UpdateOffset = -UpdateOffset;
2465 int Scale, MinOffset, MaxOffset;
2467 if (UpdateOffset % Scale != 0)
2471 int ScaledOffset = UpdateOffset / Scale;
2472 if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset)
2484bool AArch64LoadStoreOpt::isMatchingMovConstInsn(MachineInstr &MemMI,
2490 if (
MI.getOpcode() == AArch64::MOVKWi &&
2491 TRI->isSuperOrSubRegisterEq(IndexReg,
MI.getOperand(1).getReg())) {
2500 MachineInstr &MovzMI = *
MBBI;
2502 if (MovzMI.
getOpcode() == AArch64::MOVZWi &&
2505 unsigned High =
MI.getOperand(2).getImm() <<
MI.getOperand(3).getImm();
2508 return Offset >> 24 == 0;
2517 MachineInstr &MemMI = *
I;
2522 TII->getMemScale(MemMI);
2527 if (MIUnscaledOffset != UnscaledOffset)
2538 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2540 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2547 ModifiedRegUnits.
clear();
2548 UsedRegUnits.
clear();
2554 const bool BaseRegSP =
BaseReg == AArch64::SP;
2563 MachineBasicBlock *CurMBB =
I->getParent();
2570 MachineInstr &
MI = *
MBBI;
2574 if (!
MI.isTransient())
2578 if (isMatchingUpdateInsn(*
I,
MI, BaseReg, UnscaledOffset))
2589 if (!ModifiedRegUnits.
available(BaseReg) ||
2591 (BaseRegSP &&
MBBI->mayLoadOrStore()))
2595 if (!VisitSucc || Limit <=
Count)
2600 MachineBasicBlock *SuccToVisit =
nullptr;
2601 unsigned LiveSuccCount = 0;
2602 for (MachineBasicBlock *Succ : CurMBB->
successors()) {
2603 for (MCRegAliasIterator AI(BaseReg,
TRI,
true); AI.isValid(); ++AI) {
2604 if (Succ->isLiveIn(*AI)) {
2605 if (LiveSuccCount++)
2607 if (Succ->pred_size() == 1)
2615 CurMBB = SuccToVisit;
2626 MachineInstr &MemMI = *
I;
2645 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i)
2646 if (DestReg[i] == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg[i]))
2650 const bool BaseRegSP =
BaseReg == AArch64::SP;
2658 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
2659 unsigned RedZoneSize =
2664 ModifiedRegUnits.
clear();
2665 UsedRegUnits.
clear();
2667 bool MemAccessBeforeSPPreInc =
false;
2671 MachineInstr &
MI = *
MBBI;
2675 if (!
MI.isTransient())
2679 if (isMatchingUpdateInsn(*
I,
MI, BaseReg,
Offset)) {
2682 if (MemAccessBeforeSPPreInc &&
MBBI->getOperand(2).getImm() > RedZoneSize)
2692 if (!ModifiedRegUnits.
available(BaseReg) ||
2700 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
2701 (DestReg[0].isValid() && !(ModifiedRegUnits.
available(DestReg[0]) &&
2703 (DestReg[1].isValid() && !(ModifiedRegUnits.
available(DestReg[1]) &&
2705 MergeEither =
false;
2710 if (BaseRegSP &&
MBBI->mayLoadOrStore())
2711 MemAccessBeforeSPPreInc =
true;
2717AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
2721 MachineInstr &MemMI = *
I;
2740 ModifiedRegUnits.
clear();
2741 UsedRegUnits.
clear();
2745 MachineInstr &
MI = *
MBBI;
2749 if (!
MI.isTransient())
2753 if (isMatchingMovConstInsn(*
I,
MI, IndexReg,
Offset)) {
2762 if (!ModifiedRegUnits.
available(IndexReg) ||
2770bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
2772 MachineInstr &
MI = *
MBBI;
2774 if (
MI.hasOrderedMemoryRef())
2787 if (findMatchingStore(
MBBI, Subtarget->
getCLOpts().load_store_scan_limit,
2789 ++NumLoadsFromStoresPromoted;
2793 MBBI = promoteLoadFromStore(
MBBI, StoreI);
2800bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
2803 MachineInstr &
MI = *
MBBI;
2806 if (!
TII->isCandidateToMergeOrPair(
MI))
2810 LdStPairFlags
Flags;
2815 ++NumZeroStoresPromoted;
2819 MBBI = mergeNarrowZeroStores(
MBBI, MergeMI, Flags);
2828 MachineInstr &
MI = *
MBBI;
2831 if (!
TII->isCandidateToMergeOrPair(
MI))
2835 if (
MI.mayLoad() && Subtarget->hasDisableLdp())
2839 if (
MI.mayStore() && Subtarget->hasDisableStp())
2845 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2847 int OffsetStride = IsUnscaled ?
TII->getMemScale(
MI) : 1;
2855 LdStPairFlags
Flags;
2865 auto Prev = std::prev(
MBBI);
2868 MachineMemOperand *MemOp =
2869 MI.memoperands_empty() ? nullptr :
MI.memoperands().front();
2874 if ((
MI.mayLoad() && Subtarget->hasLdpAlignedOnly()) ||
2875 (
MI.mayStore() && Subtarget->hasStpAlignedOnly())) {
2877 if (!MemOp || !MemOp->getMemoryType().isValid()) {
2878 NumFailedAlignmentCheck++;
2884 uint64_t MemAlignment = MemOp->getAlign().value();
2886 Align(MemOp->getSize().getValue().getKnownMinValue()).value();
2888 if (MemAlignment < 2 * TypeAlignment) {
2889 NumFailedAlignmentCheck++;
2895 if (
TII->hasUnscaledLdStOffset(
MI))
2896 ++NumUnscaledPairCreated;
2898 MBBI = mergePairedInsns(
MBBI, Paired, Flags);
2901 for (
auto I = std::next(Prev);
I !=
MBBI;
I++)
2907bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
2909 MachineInstr &
MI = *
MBBI;
2918 if (
MBBI->hasOrderedMemoryRef() &&
2928 Update = findMatchingUpdateInsnForward(
2932 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2941 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2950 Update = findMatchingUpdateInsnBackward(
2951 MBBI, Subtarget->
getCLOpts().update_scan_limit, MergeEither);
2954 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
true,
2955 true, MergeEither)) {
2964 int UnscaledOffset =
2972 Update = findMatchingUpdateInsnForward(
2973 MBBI, UnscaledOffset, Subtarget->
getCLOpts().update_scan_limit);
2976 if (
auto NextI = mergeUpdateInsn(
MBBI, Update,
false,
2989 MachineInstr &
MI = *
MBBI;
2994 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
3005 Update = findMatchingConstOffsetBackward(
3007 if (Update !=
E && (
Offset & (Scale - 1)) == 0) {
3019 switch (GPRStoreOpc) {
3021 case AArch64::STRBBui:
3022 return AArch64::STRBui;
3023 case AArch64::STRHHui:
3024 return AArch64::STRHui;
3025 case AArch64::STRWui:
3026 return AArch64::STRSui;
3027 case AArch64::STRXui:
3028 return AArch64::STRDui;
3030 case AArch64::STURBBi:
3031 return AArch64::STURBi;
3032 case AArch64::STURHHi:
3033 return AArch64::STURHi;
3034 case AArch64::STURWi:
3035 return AArch64::STURSi;
3036 case AArch64::STURXi:
3037 return AArch64::STURDi;
3039 case AArch64::STRBBroW:
3040 return AArch64::STRBroW;
3041 case AArch64::STRBBroX:
3042 return AArch64::STRBroX;
3043 case AArch64::STRHHroW:
3044 return AArch64::STRHroW;
3045 case AArch64::STRHHroX:
3046 return AArch64::STRHroX;
3047 case AArch64::STRWroW:
3048 return AArch64::STRSroW;
3049 case AArch64::STRWroX:
3050 return AArch64::STRSroX;
3051 case AArch64::STRXroW:
3052 return AArch64::STRDroW;
3053 case AArch64::STRXroX:
3054 return AArch64::STRDroX;
3064 case AArch64::UMOVvi8_idx0:
3065 return AArch64::bsub;
3066 case AArch64::UMOVvi16_idx0:
3067 return AArch64::hsub;
3068 case AArch64::UMOVvi32_idx0:
3069 return AArch64::ssub;
3070 case AArch64::UMOVvi64_idx0:
3071 return AArch64::dsub;
3077bool AArch64LoadStoreOpt::tryToReplaceUMOVStore(
3079 MachineInstr &StoreMI = *
MBBI;
3102 MachineInstr *UMOVMI =
nullptr;
3104 unsigned SubRegIdx = 0;
3106 for (
auto It =
MBBI; It !=
B;) {
3107 MachineInstr &
MI = *--It;
3108 if (
MI.isDebugInstr())
3112 if (
MI.readsRegister(StoreValReg,
TRI))
3114 if (
MI.modifiesRegister(StoreValReg,
TRI)) {
3127 TRI->getRegSizeInBits(*
TRI->getMinimalPhysRegClass(FPRReg)))
3136 if (It->modifiesRegister(VecReg,
TRI))
3138 if (!VecRegKilled && It->killsRegister(VecReg,
TRI))
3139 VecRegKilled =
true;
3146 It->clearRegisterKills(VecReg,
TRI);
3148 LLVM_DEBUG(
dbgs() <<
"Folding UMOV + store: " << *UMOVMI <<
" + "
3160 ++NumUMOVFoldedToFPRStore;
3164bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &
MBB,
3165 bool EnableNarrowZeroStOpt) {
3197 if (EnableNarrowZeroStOpt)
3221 DefinedInBB.
clear();
3230 if (
TII->isPairableLdStInst(*
MBBI) && tryToPairLdStInst(
MBBI))
3274 if (tryToReplaceUMOVStore(
MBBI))
3296 bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
3297 for (
auto &
MBB : Fn) {
3315bool AArch64LoadStoreOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
3318 AArch64LoadStoreOpt Impl;
3319 Impl.AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
3320 return Impl.runOnMachineFunction(MF);
3326 return new AArch64LoadStoreOptLegacy();
3332 AArch64LoadStoreOpt Impl;
3336 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 needsWinCFI(const MachineFunction *MF)
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.
bool needsUnwindTableEntry() const
True if this function needs an unwind table.
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.
bool usesWindowsCFI() const
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 TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
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.
const MCAsmInfo & getMCAsmInfo() const
Return target specific asm information.
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
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