57#define DEBUG_TYPE "aarch64-ldst-opt"
59STATISTIC(NumPairCreated,
"Number of load/store pair instructions generated");
60STATISTIC(NumPostFolded,
"Number of post-index updates folded");
61STATISTIC(NumPreFolded,
"Number of pre-index updates folded");
63 "Number of load/store from unscaled generated");
64STATISTIC(NumZeroStoresPromoted,
"Number of narrow zero stores promoted");
65STATISTIC(NumLoadsFromStoresPromoted,
"Number of loads from stores promoted");
68 "Controls which pairs are considered for renaming");
83#define AARCH64_LOAD_STORE_OPT_NAME "AArch64 load / store optimization pass"
87using LdStPairFlags =
struct LdStPairFlags {
91 bool MergeForward =
false;
102 std::optional<MCPhysReg> RenameReg;
104 LdStPairFlags() =
default;
106 void setMergeForward(
bool V =
true) { MergeForward = V; }
107 bool getMergeForward()
const {
return MergeForward; }
109 void setSExtIdx(
int V) { SExtIdx = V; }
110 int getSExtIdx()
const {
return SExtIdx; }
112 void setRenameReg(
MCPhysReg R) { RenameReg = R; }
113 void clearRenameReg() { RenameReg = std::nullopt; }
114 std::optional<MCPhysReg> getRenameReg()
const {
return RenameReg; }
142 LdStPairFlags &Flags,
144 bool FindNarrowMerge);
155 const LdStPairFlags &Flags);
161 const LdStPairFlags &Flags);
173 int UnscaledOffset,
unsigned Limit);
184 unsigned BaseReg,
int Offset);
209 MachineFunctionProperties::Property::NoVRegs);
215char AArch64LoadStoreOpt::ID = 0;
222static
bool isNarrowStore(
unsigned Opc) {
226 case AArch64::STRBBui:
227 case AArch64::STURBBi:
228 case AArch64::STRHHui:
229 case AArch64::STURHHi:
237 switch (
MI.getOpcode()) {
243 case AArch64::STZ2Gi:
249 bool *IsValidLdStrOpc =
nullptr) {
251 *IsValidLdStrOpc =
true;
255 *IsValidLdStrOpc =
false;
256 return std::numeric_limits<unsigned>::max();
257 case AArch64::STRDui:
258 case AArch64::STURDi:
259 case AArch64::STRDpre:
260 case AArch64::STRQui:
261 case AArch64::STURQi:
262 case AArch64::STRQpre:
263 case AArch64::STRBBui:
264 case AArch64::STURBBi:
265 case AArch64::STRHHui:
266 case AArch64::STURHHi:
267 case AArch64::STRWui:
268 case AArch64::STRWpre:
269 case AArch64::STURWi:
270 case AArch64::STRXui:
271 case AArch64::STRXpre:
272 case AArch64::STURXi:
273 case AArch64::LDRDui:
274 case AArch64::LDURDi:
275 case AArch64::LDRDpre:
276 case AArch64::LDRQui:
277 case AArch64::LDURQi:
278 case AArch64::LDRQpre:
279 case AArch64::LDRWui:
280 case AArch64::LDURWi:
281 case AArch64::LDRWpre:
282 case AArch64::LDRXui:
283 case AArch64::LDURXi:
284 case AArch64::LDRXpre:
285 case AArch64::STRSui:
286 case AArch64::STURSi:
287 case AArch64::STRSpre:
288 case AArch64::LDRSui:
289 case AArch64::LDURSi:
290 case AArch64::LDRSpre:
292 case AArch64::LDRSWui:
293 return AArch64::LDRWui;
294 case AArch64::LDURSWi:
295 return AArch64::LDURWi;
296 case AArch64::LDRSWpre:
297 return AArch64::LDRWpre;
305 case AArch64::STRBBui:
306 return AArch64::STRHHui;
307 case AArch64::STRHHui:
308 return AArch64::STRWui;
309 case AArch64::STURBBi:
310 return AArch64::STURHHi;
311 case AArch64::STURHHi:
312 return AArch64::STURWi;
313 case AArch64::STURWi:
314 return AArch64::STURXi;
315 case AArch64::STRWui:
316 return AArch64::STRXui;
324 case AArch64::STRSui:
325 case AArch64::STURSi:
326 return AArch64::STPSi;
327 case AArch64::STRSpre:
328 return AArch64::STPSpre;
329 case AArch64::STRDui:
330 case AArch64::STURDi:
331 return AArch64::STPDi;
332 case AArch64::STRDpre:
333 return AArch64::STPDpre;
334 case AArch64::STRQui:
335 case AArch64::STURQi:
336 return AArch64::STPQi;
337 case AArch64::STRQpre:
338 return AArch64::STPQpre;
339 case AArch64::STRWui:
340 case AArch64::STURWi:
341 return AArch64::STPWi;
342 case AArch64::STRWpre:
343 return AArch64::STPWpre;
344 case AArch64::STRXui:
345 case AArch64::STURXi:
346 return AArch64::STPXi;
347 case AArch64::STRXpre:
348 return AArch64::STPXpre;
349 case AArch64::LDRSui:
350 case AArch64::LDURSi:
351 return AArch64::LDPSi;
352 case AArch64::LDRSpre:
353 return AArch64::LDPSpre;
354 case AArch64::LDRDui:
355 case AArch64::LDURDi:
356 return AArch64::LDPDi;
357 case AArch64::LDRDpre:
358 return AArch64::LDPDpre;
359 case AArch64::LDRQui:
360 case AArch64::LDURQi:
361 return AArch64::LDPQi;
362 case AArch64::LDRQpre:
363 return AArch64::LDPQpre;
364 case AArch64::LDRWui:
365 case AArch64::LDURWi:
366 return AArch64::LDPWi;
367 case AArch64::LDRWpre:
368 return AArch64::LDPWpre;
369 case AArch64::LDRXui:
370 case AArch64::LDURXi:
371 return AArch64::LDPXi;
372 case AArch64::LDRXpre:
373 return AArch64::LDPXpre;
374 case AArch64::LDRSWui:
375 case AArch64::LDURSWi:
376 return AArch64::LDPSWi;
377 case AArch64::LDRSWpre:
378 return AArch64::LDPSWpre;
389 case AArch64::LDRBBui:
390 return StOpc == AArch64::STRBBui || StOpc == AArch64::STRHHui ||
391 StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
392 case AArch64::LDURBBi:
393 return StOpc == AArch64::STURBBi || StOpc == AArch64::STURHHi ||
394 StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
395 case AArch64::LDRHHui:
396 return StOpc == AArch64::STRHHui || StOpc == AArch64::STRWui ||
397 StOpc == AArch64::STRXui;
398 case AArch64::LDURHHi:
399 return StOpc == AArch64::STURHHi || StOpc == AArch64::STURWi ||
400 StOpc == AArch64::STURXi;
401 case AArch64::LDRWui:
402 return StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
403 case AArch64::LDURWi:
404 return StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
405 case AArch64::LDRXui:
406 return StOpc == AArch64::STRXui;
407 case AArch64::LDURXi:
408 return StOpc == AArch64::STURXi;
420 case AArch64::STRSui:
421 return AArch64::STRSpre;
422 case AArch64::STRDui:
423 return AArch64::STRDpre;
424 case AArch64::STRQui:
425 return AArch64::STRQpre;
426 case AArch64::STRBBui:
427 return AArch64::STRBBpre;
428 case AArch64::STRHHui:
429 return AArch64::STRHHpre;
430 case AArch64::STRWui:
431 return AArch64::STRWpre;
432 case AArch64::STRXui:
433 return AArch64::STRXpre;
434 case AArch64::LDRSui:
435 return AArch64::LDRSpre;
436 case AArch64::LDRDui:
437 return AArch64::LDRDpre;
438 case AArch64::LDRQui:
439 return AArch64::LDRQpre;
440 case AArch64::LDRBBui:
441 return AArch64::LDRBBpre;
442 case AArch64::LDRHHui:
443 return AArch64::LDRHHpre;
444 case AArch64::LDRWui:
445 return AArch64::LDRWpre;
446 case AArch64::LDRXui:
447 return AArch64::LDRXpre;
448 case AArch64::LDRSWui:
449 return AArch64::LDRSWpre;
451 return AArch64::LDPSpre;
452 case AArch64::LDPSWi:
453 return AArch64::LDPSWpre;
455 return AArch64::LDPDpre;
457 return AArch64::LDPQpre;
459 return AArch64::LDPWpre;
461 return AArch64::LDPXpre;
463 return AArch64::STPSpre;
465 return AArch64::STPDpre;
467 return AArch64::STPQpre;
469 return AArch64::STPWpre;
471 return AArch64::STPXpre;
473 return AArch64::STGPreIndex;
475 return AArch64::STZGPreIndex;
477 return AArch64::ST2GPreIndex;
478 case AArch64::STZ2Gi:
479 return AArch64::STZ2GPreIndex;
481 return AArch64::STGPpre;
489 case AArch64::STRSui:
490 case AArch64::STURSi:
491 return AArch64::STRSpost;
492 case AArch64::STRDui:
493 case AArch64::STURDi:
494 return AArch64::STRDpost;
495 case AArch64::STRQui:
496 case AArch64::STURQi:
497 return AArch64::STRQpost;
498 case AArch64::STRBBui:
499 return AArch64::STRBBpost;
500 case AArch64::STRHHui:
501 return AArch64::STRHHpost;
502 case AArch64::STRWui:
503 case AArch64::STURWi:
504 return AArch64::STRWpost;
505 case AArch64::STRXui:
506 case AArch64::STURXi:
507 return AArch64::STRXpost;
508 case AArch64::LDRSui:
509 case AArch64::LDURSi:
510 return AArch64::LDRSpost;
511 case AArch64::LDRDui:
512 case AArch64::LDURDi:
513 return AArch64::LDRDpost;
514 case AArch64::LDRQui:
515 case AArch64::LDURQi:
516 return AArch64::LDRQpost;
517 case AArch64::LDRBBui:
518 return AArch64::LDRBBpost;
519 case AArch64::LDRHHui:
520 return AArch64::LDRHHpost;
521 case AArch64::LDRWui:
522 case AArch64::LDURWi:
523 return AArch64::LDRWpost;
524 case AArch64::LDRXui:
525 case AArch64::LDURXi:
526 return AArch64::LDRXpost;
527 case AArch64::LDRSWui:
528 return AArch64::LDRSWpost;
530 return AArch64::LDPSpost;
531 case AArch64::LDPSWi:
532 return AArch64::LDPSWpost;
534 return AArch64::LDPDpost;
536 return AArch64::LDPQpost;
538 return AArch64::LDPWpost;
540 return AArch64::LDPXpost;
542 return AArch64::STPSpost;
544 return AArch64::STPDpost;
546 return AArch64::STPQpost;
548 return AArch64::STPWpost;
550 return AArch64::STPXpost;
552 return AArch64::STGPostIndex;
554 return AArch64::STZGPostIndex;
556 return AArch64::ST2GPostIndex;
557 case AArch64::STZ2Gi:
558 return AArch64::STZ2GPostIndex;
560 return AArch64::STGPpost;
567 unsigned OpcB =
MI.getOpcode();
572 case AArch64::STRSpre:
573 return (OpcB == AArch64::STRSui) || (OpcB == AArch64::STURSi);
574 case AArch64::STRDpre:
575 return (OpcB == AArch64::STRDui) || (OpcB == AArch64::STURDi);
576 case AArch64::STRQpre:
577 return (OpcB == AArch64::STRQui) || (OpcB == AArch64::STURQi);
578 case AArch64::STRWpre:
579 return (OpcB == AArch64::STRWui) || (OpcB == AArch64::STURWi);
580 case AArch64::STRXpre:
581 return (OpcB == AArch64::STRXui) || (OpcB == AArch64::STURXi);
582 case AArch64::LDRSpre:
583 return (OpcB == AArch64::LDRSui) || (OpcB == AArch64::LDURSi);
584 case AArch64::LDRDpre:
585 return (OpcB == AArch64::LDRDui) || (OpcB == AArch64::LDURDi);
586 case AArch64::LDRQpre:
587 return (OpcB == AArch64::LDRQui) || (OpcB == AArch64::LDURQi);
588 case AArch64::LDRWpre:
589 return (OpcB == AArch64::LDRWui) || (OpcB == AArch64::LDURWi);
590 case AArch64::LDRXpre:
591 return (OpcB == AArch64::LDRXui) || (OpcB == AArch64::LDURXi);
592 case AArch64::LDRSWpre:
593 return (OpcB == AArch64::LDRSWui) || (OpcB == AArch64::LDURSWi);
599 int &MinOffset,
int &MaxOffset) {
617 unsigned PairedRegOp = 0) {
618 assert(PairedRegOp < 2 &&
"Unexpected register operand idx.");
624 return MI.getOperand(
Idx);
633 int UnscaledStOffset =
637 int UnscaledLdOffset =
641 return (UnscaledStOffset <= UnscaledLdOffset) &&
642 (UnscaledLdOffset + LoadSize <= (UnscaledStOffset + StoreSize));
646 unsigned Opc =
MI.getOpcode();
647 return (Opc == AArch64::STRWui || Opc == AArch64::STURWi ||
648 isNarrowStore(Opc)) &&
653 switch (
MI.getOpcode()) {
657 case AArch64::LDRBBui:
658 case AArch64::LDRHHui:
659 case AArch64::LDRWui:
660 case AArch64::LDRXui:
662 case AArch64::LDURBBi:
663 case AArch64::LDURHHi:
664 case AArch64::LDURWi:
665 case AArch64::LDURXi:
671 unsigned Opc =
MI.getOpcode();
676 case AArch64::STRSui:
677 case AArch64::STRDui:
678 case AArch64::STRQui:
679 case AArch64::STRXui:
680 case AArch64::STRWui:
681 case AArch64::STRHHui:
682 case AArch64::STRBBui:
683 case AArch64::LDRSui:
684 case AArch64::LDRDui:
685 case AArch64::LDRQui:
686 case AArch64::LDRXui:
687 case AArch64::LDRWui:
688 case AArch64::LDRHHui:
689 case AArch64::LDRBBui:
693 case AArch64::STZ2Gi:
696 case AArch64::STURSi:
697 case AArch64::STURDi:
698 case AArch64::STURQi:
699 case AArch64::STURWi:
700 case AArch64::STURXi:
701 case AArch64::LDURSi:
702 case AArch64::LDURDi:
703 case AArch64::LDURQi:
704 case AArch64::LDURWi:
705 case AArch64::LDURXi:
708 case AArch64::LDPSWi:
729 const LdStPairFlags &Flags) {
731 "Expected promotable zero stores.");
739 if (NextI == MergeMI)
742 unsigned Opc =
I->getOpcode();
743 unsigned MergeMIOpc = MergeMI->getOpcode();
744 bool IsScaled = !
TII->hasUnscaledLdStOffset(Opc);
745 bool IsMergedMIScaled = !
TII->hasUnscaledLdStOffset(MergeMIOpc);
746 int OffsetStride = IsScaled ?
TII->getMemScale(*
I) : 1;
747 int MergeMIOffsetStride = IsMergedMIScaled ?
TII->getMemScale(*MergeMI) : 1;
749 bool MergeForward =
Flags.getMergeForward();
760 int64_t IOffsetInBytes =
762 int64_t MIOffsetInBytes =
767 if (IOffsetInBytes > MIOffsetInBytes)
768 OffsetImm = MIOffsetInBytes;
770 OffsetImm = IOffsetInBytes;
773 bool FinalIsScaled = !
TII->hasUnscaledLdStOffset(NewOpcode);
777 int NewOffsetStride = FinalIsScaled ?
TII->getMemScale(NewOpcode) : 1;
778 assert(((OffsetImm % NewOffsetStride) == 0) &&
779 "Offset should be a multiple of the store memory scale");
780 OffsetImm = OffsetImm / NewOffsetStride;
788 .
addReg(isNarrowStore(Opc) ? AArch64::WZR : AArch64::XZR)
792 .setMIFlags(
I->mergeFlagsWith(*MergeMI));
795 LLVM_DEBUG(
dbgs() <<
"Creating wider store. Replacing instructions:\n ");
804 I->eraseFromParent();
805 MergeMI->eraseFromParent();
815 auto MBB =
MI.getParent();
823 return MOP.isReg() && MOP.isDef() && !MOP.isDebug() && MOP.getReg() &&
824 TRI->regsOverlap(MOP.getReg(), DefReg);
838 if (MOP.isReg() && MOP.isKill())
842 if (MOP.isReg() && !MOP.isKill())
843 Units.
addReg(MOP.getReg());
849 const LdStPairFlags &Flags) {
859 int SExtIdx =
Flags.getSExtIdx();
862 bool IsUnscaled =
TII->hasUnscaledLdStOffset(Opc);
863 int OffsetStride = IsUnscaled ?
TII->getMemScale(*
I) : 1;
865 bool MergeForward =
Flags.getMergeForward();
867 std::optional<MCPhysReg> RenameReg =
Flags.getRenameReg();
868 if (MergeForward && RenameReg) {
870 DefinedInBB.addReg(*RenameReg);
874 auto GetMatchingSubReg = [
this,
876 for (
MCPhysReg SubOrSuper :
TRI->sub_and_superregs_inclusive(*RenameReg))
877 if (
TRI->getMinimalPhysRegClass(OriginalReg) ==
878 TRI->getMinimalPhysRegClass(SubOrSuper))
884 [
this, RegToRename, GetMatchingSubReg](
MachineInstr &
MI,
bool IsDef) {
886 bool SeenDef =
false;
887 for (
auto &MOP :
MI.operands()) {
890 if (MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
891 (!SeenDef || (MOP.isDef() && MOP.isImplicit())) &&
892 TRI->regsOverlap(MOP.getReg(), RegToRename)) {
893 assert((MOP.isImplicit() ||
894 (MOP.isRenamable() && !MOP.isEarlyClobber())) &&
895 "Need renamable operands");
896 MOP.setReg(GetMatchingSubReg(MOP.getReg()));
901 for (
auto &MOP :
MI.operands()) {
902 if (MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
903 TRI->regsOverlap(MOP.getReg(), RegToRename)) {
904 assert((MOP.isImplicit() ||
905 (MOP.isRenamable() && !MOP.isEarlyClobber())) &&
906 "Need renamable operands");
907 MOP.setReg(GetMatchingSubReg(MOP.getReg()));
922 std::next(
I), std::next(Paired)))
925 return !MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
927 !TRI->regsOverlap(MOP.getReg(), *RenameReg);
929 "Rename register used between paired instruction, trashing the "
945 bool PairedIsUnscaled =
TII->hasUnscaledLdStOffset(Paired->getOpcode());
946 if (IsUnscaled != PairedIsUnscaled) {
950 int MemSize =
TII->getMemScale(*Paired);
951 if (PairedIsUnscaled) {
954 assert(!(PairedOffset %
TII->getMemScale(*Paired)) &&
955 "Offset should be a multiple of the stride!");
956 PairedOffset /= MemSize;
958 PairedOffset *= MemSize;
966 if (
Offset == PairedOffset + OffsetStride &&
974 SExtIdx = (SExtIdx + 1) % 2;
982 assert(!(OffsetImm %
TII->getMemScale(*RtMI)) &&
983 "Unscaled offset cannot be scaled.");
984 OffsetImm /=
TII->getMemScale(*RtMI);
994 if (RegOp0.
isUse()) {
1009 MI.clearRegisterKills(Reg,
TRI);
1025 .setMIFlags(
I->mergeFlagsWith(*Paired));
1030 dbgs() <<
"Creating pair load/store. Replacing instructions:\n ");
1035 if (SExtIdx != -1) {
1045 Register DstRegW =
TRI->getSubReg(DstRegX, AArch64::sub_32);
1055 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(TargetOpcode::KILL), DstRegW)
1061 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(AArch64::SBFMXri), DstRegX)
1075 if (MOP.isReg() && MOP.isKill())
1076 DefinedInBB.addReg(MOP.getReg());
1079 I->eraseFromParent();
1080 Paired->eraseFromParent();
1089 next_nodbg(LoadI, LoadI->getParent()->end());
1091 int LoadSize =
TII->getMemScale(*LoadI);
1092 int StoreSize =
TII->getMemScale(*StoreI);
1096 bool IsStoreXReg =
TRI->getRegClass(AArch64::GPR64RegClassID)->contains(StRt);
1099 TRI->getRegClass(AArch64::GPR32RegClassID)->contains(StRt)) &&
1100 "Unexpected RegClass");
1103 if (LoadSize == StoreSize && (LoadSize == 4 || LoadSize == 8)) {
1106 if (StRt == LdRt && LoadSize == 8) {
1108 LoadI->getIterator())) {
1109 if (
MI.killsRegister(StRt,
TRI)) {
1110 MI.clearRegisterKills(StRt,
TRI);
1117 LoadI->eraseFromParent();
1122 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1123 TII->get(IsStoreXReg ? AArch64::ORRXrs : AArch64::ORRWrs), LdRt)
1124 .
addReg(IsStoreXReg ? AArch64::XZR : AArch64::WZR)
1131 if (!Subtarget->isLittleEndian())
1133 bool IsUnscaled =
TII->hasUnscaledLdStOffset(*LoadI);
1134 assert(IsUnscaled ==
TII->hasUnscaledLdStOffset(*StoreI) &&
1135 "Unsupported ld/st match");
1136 assert(LoadSize <= StoreSize &&
"Invalid load size");
1137 int UnscaledLdOffset =
1141 int UnscaledStOffset =
1145 int Width = LoadSize * 8;
1148 LdRt, AArch64::sub_32, &AArch64::GPR64RegClass))
1151 assert((UnscaledLdOffset >= UnscaledStOffset &&
1152 (UnscaledLdOffset + LoadSize) <= UnscaledStOffset + StoreSize) &&
1155 int Immr = 8 * (UnscaledLdOffset - UnscaledStOffset);
1156 int Imms = Immr +
Width - 1;
1157 if (UnscaledLdOffset == UnscaledStOffset) {
1158 uint32_t AndMaskEncoded = ((IsStoreXReg ? 1 : 0) << 12)
1164 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1165 TII->get(IsStoreXReg ? AArch64::ANDXri : AArch64::ANDWri),
1172 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1173 TII->get(IsStoreXReg ? AArch64::UBFMXri : AArch64::UBFMWri),
1185 if (
MI.killsRegister(StRt,
TRI)) {
1186 MI.clearRegisterKills(StRt,
TRI);
1201 LoadI->eraseFromParent();
1211 if (
Offset % OffsetStride)
1215 return Offset <= 63 && Offset >= -64;
1223 return (Num + PowOf2 - 1) & ~(PowOf2 - 1);
1236bool AArch64LoadStoreOpt::findMatchingStore(
1251 ModifiedRegUnits.clear();
1252 UsedRegUnits.clear();
1261 if (!
MI.isTransient())
1287 if (!ModifiedRegUnits.available(BaseReg))
1293 }
while (
MBBI !=
B && Count < Limit);
1305 LdStPairFlags &Flags,
1308 if (
MI.hasOrderedMemoryRef() ||
TII->isLdStPairSuppressed(
MI))
1313 !
TII->isLdStPairSuppressed(FirstMI) &&
1314 "FirstMI shouldn't get here if either of these checks are true.");
1321 unsigned OpcB =
MI.getOpcode();
1332 bool IsValidLdStrOpc, PairIsValidLdStrOpc;
1334 assert(IsValidLdStrOpc &&
1335 "Given Opc should be a Load or Store with an immediate");
1338 Flags.setSExtIdx(NonSExtOpc == (
unsigned)OpcA ? 1 : 0);
1344 if (!PairIsValidLdStrOpc)
1349 if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
1359 return TII->hasUnscaledLdStOffset(OpcA) !=
TII->hasUnscaledLdStOffset(OpcB) &&
1384 return MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
1385 MOP.isImplicit() && MOP.isKill() &&
1386 TRI->regsOverlap(RegToRename, MOP.getReg());
1388 LLVM_DEBUG(
dbgs() <<
" Operand not killed at " << FirstMI <<
"\n");
1393 auto *RegClass =
TRI->getMinimalPhysRegClass(MOP.
getReg());
1400 if (RegClass->HasDisjunctSubRegs) {
1403 <<
" Cannot rename operands with multiple disjunct subregisters ("
1412 bool FoundDef =
false;
1423 LLVM_DEBUG(
dbgs() <<
" Cannot rename framesetup instructions currently ("
1443 if (
MI.isPseudo()) {
1449 for (
auto &MOP :
MI.operands()) {
1451 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1453 if (!canRenameMOP(MOP)) {
1455 <<
" Cannot rename " << MOP <<
" in " <<
MI <<
"\n");
1462 for (
auto &MOP :
MI.operands()) {
1464 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1467 if (!canRenameMOP(MOP)) {
1469 <<
" Cannot rename " << MOP <<
" in " <<
MI <<
"\n");
1482 LLVM_DEBUG(
dbgs() <<
" Did not find definition for register in BB\n");
1503 auto AnySubOrSuperRegCalleePreserved = [&MF,
TRI](
MCPhysReg PR) {
1504 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1506 return TRI->isCalleeSavedPhysReg(SubOrSuper, MF);
1512 auto CanBeUsedForAllClasses = [&RequiredClasses,
TRI](
MCPhysReg PR) {
1514 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1516 return C == TRI->getMinimalPhysRegClass(SubOrSuper);
1521 auto *RegClass =
TRI->getMinimalPhysRegClass(Reg);
1524 !
RegInfo.isReserved(PR) && !AnySubOrSuperRegCalleePreserved(PR) &&
1525 CanBeUsedForAllClasses(PR)) {
1533 <<
TRI->getRegClassName(RegClass) <<
"\n");
1534 return std::nullopt;
1541 LdStPairFlags &Flags,
unsigned Limit,
1542 bool FindNarrowMerge) {
1550 bool IsUnscaled =
TII->hasUnscaledLdStOffset(FirstMI);
1554 int OffsetStride = IsUnscaled ?
TII->getMemScale(FirstMI) : 1;
1557 std::optional<bool> MaybeCanRename;
1559 MaybeCanRename = {
false};
1565 Flags.clearRenameReg();
1569 ModifiedRegUnits.clear();
1570 UsedRegUnits.clear();
1575 for (
unsigned Count = 0;
MBBI !=
E && Count < Limit;
1583 if (!
MI.isTransient())
1586 Flags.setSExtIdx(-1);
1589 assert(
MI.mayLoadOrStore() &&
"Expected memory operation.");
1598 bool MIIsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
1599 if (IsUnscaled != MIIsUnscaled) {
1603 int MemSize =
TII->getMemScale(
MI);
1607 if (MIOffset % MemSize) {
1613 MIOffset /= MemSize;
1615 MIOffset *= MemSize;
1621 if (BaseReg == MIBaseReg) {
1627 bool IsOutOfBounds = MIOffset !=
TII->getMemScale(
MI);
1628 bool IsBaseRegUsed = !UsedRegUnits.available(
1630 bool IsBaseRegModified = !ModifiedRegUnits.available(
1635 bool IsMIRegTheSame =
1638 if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified ||
1646 if ((
Offset != MIOffset + OffsetStride) &&
1647 (
Offset + OffsetStride != MIOffset)) {
1656 if (FindNarrowMerge) {
1661 if ((!IsUnscaled &&
alignTo(MinOffset, 2) != MinOffset) ||
1682 if (IsUnscaled && (
alignTo(MinOffset, OffsetStride) != MinOffset)) {
1707 if (!ModifiedRegUnits.available(BaseReg))
1719 Flags.setMergeForward(
false);
1720 Flags.clearRenameReg();
1730 !
mayAlias(FirstMI, MemInsns, AA)) {
1733 Flags.setMergeForward(
true);
1734 Flags.clearRenameReg();
1739 if (!MaybeCanRename)
1741 RequiredClasses,
TRI)};
1743 if (*MaybeCanRename) {
1744 std::optional<MCPhysReg> MaybeRenameReg =
1746 Reg, DefinedInBB, UsedInBetween,
1747 RequiredClasses,
TRI);
1748 if (MaybeRenameReg) {
1749 Flags.setRenameReg(*MaybeRenameReg);
1750 Flags.setMergeForward(
true);
1751 MBBIWithRenameReg =
MBBI;
1761 if (
Flags.getRenameReg())
1762 return MBBIWithRenameReg;
1774 if (!ModifiedRegUnits.available(BaseReg))
1778 if (
MI.mayLoadOrStore())
1786 auto End =
MI.getParent()->end();
1787 if (MaybeCFI ==
End ||
1788 MaybeCFI->getOpcode() != TargetOpcode::CFI_INSTRUCTION ||
1795 unsigned CFIIndex = MaybeCFI->getOperand(0).getCFIIndex();
1810 assert((Update->getOpcode() == AArch64::ADDXri ||
1811 Update->getOpcode() == AArch64::SUBXri) &&
1812 "Unexpected base register update instruction to merge!");
1824 if (NextI == Update)
1827 int Value = Update->getOperand(2).getImm();
1829 "Can't merge 1 << 12 offset into pre-/post-indexed load / store");
1830 if (Update->getOpcode() == AArch64::SUBXri)
1836 int Scale, MinOffset, MaxOffset;
1840 MIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
1849 MIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
1879 I->eraseFromParent();
1880 Update->eraseFromParent();
1885bool AArch64LoadStoreOpt::isMatchingUpdateInsn(
MachineInstr &MemMI,
1887 unsigned BaseReg,
int Offset) {
1888 switch (
MI.getOpcode()) {
1891 case AArch64::SUBXri:
1892 case AArch64::ADDXri:
1895 if (!
MI.getOperand(2).isImm())
1903 if (
MI.getOperand(0).getReg() != BaseReg ||
1904 MI.getOperand(1).getReg() != BaseReg)
1907 int UpdateOffset =
MI.getOperand(2).getImm();
1908 if (
MI.getOpcode() == AArch64::SUBXri)
1909 UpdateOffset = -UpdateOffset;
1913 int Scale, MinOffset, MaxOffset;
1915 if (UpdateOffset % Scale != 0)
1919 int ScaledOffset = UpdateOffset / Scale;
1920 if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset)
1940 TII->getMemScale(MemMI);
1945 if (MIUnscaledOffset != UnscaledOffset)
1956 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
1958 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
1965 ModifiedRegUnits.clear();
1966 UsedRegUnits.clear();
1972 const bool BaseRegSP = BaseReg == AArch64::SP;
1980 for (
unsigned Count = 0;
MBBI !=
E && Count < Limit;
1986 if (!
MI.isTransient())
1990 if (isMatchingUpdateInsn(*
I,
MI, BaseReg, UnscaledOffset))
2000 if (!ModifiedRegUnits.available(BaseReg) ||
2001 !UsedRegUnits.available(BaseReg) ||
2002 (BaseRegSP &&
MBBI->mayLoadOrStore()))
2027 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2029 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2034 const bool BaseRegSP = BaseReg == AArch64::SP;
2043 unsigned RedZoneSize =
2048 ModifiedRegUnits.clear();
2049 UsedRegUnits.clear();
2051 bool MemAcessBeforeSPPreInc =
false;
2058 if (!
MI.isTransient())
2062 if (isMatchingUpdateInsn(*
I,
MI, BaseReg,
Offset)) {
2065 if (MemAcessBeforeSPPreInc &&
MBBI->getOperand(2).getImm() > RedZoneSize)
2075 if (!ModifiedRegUnits.available(BaseReg) ||
2076 !UsedRegUnits.available(BaseReg))
2081 if (BaseRegSP &&
MBBI->mayLoadOrStore())
2082 MemAcessBeforeSPPreInc =
true;
2083 }
while (
MBBI !=
B && Count < Limit);
2087bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
2091 if (
MI.hasOrderedMemoryRef())
2105 ++NumLoadsFromStoresPromoted;
2109 MBBI = promoteLoadFromStore(
MBBI, StoreI);
2116bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
2122 if (!
TII->isCandidateToMergeOrPair(
MI))
2126 LdStPairFlags
Flags;
2130 ++NumZeroStoresPromoted;
2134 MBBI = mergeNarrowZeroStores(
MBBI, MergeMI, Flags);
2146 if (!
TII->isCandidateToMergeOrPair(
MI))
2150 if (
MI.mayLoad() && Subtarget->hasDisableLdp())
2154 if (
MI.mayStore() && Subtarget->hasDisableStp())
2160 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2162 int OffsetStride = IsUnscaled ?
TII->getMemScale(
MI) : 1;
2170 LdStPairFlags
Flags;
2175 if (
TII->hasUnscaledLdStOffset(
MI))
2176 ++NumUnscaledPairCreated;
2179 auto Prev = std::prev(
MBBI);
2184 MI.memoperands_empty() ? nullptr :
MI.memoperands().front();
2194 if (
MI.mayLoad() && Subtarget->hasLdpAlignedOnly() &&
MemOp &&
2195 MemAlignment < 2 * TypeAlignment)
2201 if (
MI.mayStore() && Subtarget->hasStpAlignedOnly() &&
MemOp &&
2202 MemAlignment < 2 * TypeAlignment)
2205 MBBI = mergePairedInsns(
MBBI, Paired, Flags);
2208 for (
auto I = std::next(Prev);
I !=
MBBI;
I++)
2216bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
2230 MBBI = mergeUpdateInsn(
MBBI, Update,
false);
2235 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2246 MBBI = mergeUpdateInsn(
MBBI, Update,
true);
2253 int UnscaledOffset =
2261 Update = findMatchingUpdateInsnForward(
MBBI, UnscaledOffset,
UpdateLimit);
2264 MBBI = mergeUpdateInsn(
MBBI, Update,
true);
2272 bool EnableNarrowZeroStOpt) {
2303 if (EnableNarrowZeroStOpt)
2320 DefinedInBB.
clear();
2321 DefinedInBB.addLiveIns(
MBB);
2329 if (
TII->isPairableLdStInst(*
MBBI) && tryToPairLdStInst(
MBBI))
2359 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
2364 ModifiedRegUnits.init(*
TRI);
2365 UsedRegUnits.init(*
TRI);
2366 DefinedInBB.init(*
TRI);
2369 bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
2370 for (
auto &
MBB : Fn) {
2391 return new AArch64LoadStoreOpt();
static cl::opt< bool > EnableRenaming("aarch64-load-store-renaming", cl::init(true), cl::Hidden)
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 bool isMergeableLdStUpdate(MachineInstr &MI)
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 mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
static cl::opt< unsigned > LdStLimit("aarch64-load-store-scan-limit", cl::init(20), cl::Hidden)
static unsigned getPreIndexedOpcode(unsigned Opc)
#define AARCH64_LOAD_STORE_OPT_NAME
static cl::opt< unsigned > UpdateLimit("aarch64-update-scan-limit", cl::init(100), cl::Hidden)
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 int alignTo(int Num, int PowOf2)
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 unsigned getPostIndexedOpcode(unsigned Opc)
static bool isLdOffsetInRangeOfSt(MachineInstr &LoadInst, MachineInstr &StoreInst, const AArch64InstrInfo *TII)
static bool isPreLdStPairCandidate(MachineInstr &FirstMI, MachineInstr &MI)
static void updateDefinedRegisters(MachineInstr &MI, LiveRegUnits &Units, const TargetRegisterInfo *TRI)
static bool canRenameUpToDef(MachineInstr &FirstMI, LiveRegUnits &UsedInBetween, SmallPtrSetImpl< const TargetRegisterClass * > &RequiredClasses, const TargetRegisterInfo *TRI)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, DomTreeUpdater *DTU)
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)
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
static const MachineOperand & getLdStOffsetOp(const MachineInstr &MI)
Returns the immediate offset 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.
const AArch64RegisterInfo * getRegisterInfo() const override
const AArch64InstrInfo * getInstrInfo() const override
const AArch64TargetLowering * getTargetLowering() const override
unsigned getRedZoneSize(const Function &F) const
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
static bool shouldExecute(unsigned CounterName)
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(MCPhysReg 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(MCPhysReg Reg)
Adds register units covered by physical register Reg.
void removeReg(MCPhysReg Reg)
Removes all register units covered by physical register Reg.
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
Wrapper class representing physical registers. Should be passed by value.
reverse_instr_iterator instr_rend()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
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 '...
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual MachineFunctionProperties getRequiredProperties() const
Properties which a MachineFunction may have at a given point in time.
MachineFunctionProperties & set(Property P)
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const LLVMTargetMachine & 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 & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool mayAlias(AAResults *AA, const MachineInstr &Other, bool UseTBAA) const
Returns true if this instruction's memory access aliases the memory access of Other.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
iterator_range< mop_iterator > operands()
bool hasOrderedMemoryRef() const
Return true if this instruction may have an ordered or volatile memory reference, or if the informati...
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
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.
void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
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.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - 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...
LLVM Value Representation.
self_iterator getIterator()
A range adaptor for a pair of iterators.
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.
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 ==...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ Define
Register definition.
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
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.
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.
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...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createAArch64LoadStoreOptimizationPass()
createAArch64LoadStoreOptimizationPass - returns an instance of the load / store optimization pass.
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
void initializeAArch64LoadStoreOptPass(PassRegistry &)
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
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.
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.