56#define DEBUG_TYPE "aarch64-ldst-opt"
58STATISTIC(NumPairCreated,
"Number of load/store pair instructions generated");
59STATISTIC(NumPostFolded,
"Number of post-index updates folded");
60STATISTIC(NumPreFolded,
"Number of pre-index updates folded");
62 "Number of load/store from unscaled generated");
63STATISTIC(NumZeroStoresPromoted,
"Number of narrow zero stores promoted");
64STATISTIC(NumLoadsFromStoresPromoted,
"Number of loads from stores promoted");
65STATISTIC(NumFailedAlignmentCheck,
"Number of load/store pair transformation "
66 "not passed the alignment check");
68 "Number of const offset of index address folded");
71 "Controls which pairs are considered for renaming");
91#define AARCH64_LOAD_STORE_OPT_NAME "AArch64 load / store optimization pass"
95using LdStPairFlags =
struct LdStPairFlags {
99 bool MergeForward =
false;
110 std::optional<MCPhysReg> RenameReg;
112 LdStPairFlags() =
default;
114 void setMergeForward(
bool V =
true) { MergeForward = V; }
115 bool getMergeForward()
const {
return MergeForward; }
117 void setSExtIdx(
int V) { SExtIdx = V; }
118 int getSExtIdx()
const {
return SExtIdx; }
120 void setRenameReg(
MCPhysReg R) { RenameReg = R; }
121 void clearRenameReg() { RenameReg = std::nullopt; }
122 std::optional<MCPhysReg> getRenameReg()
const {
return RenameReg; }
150 LdStPairFlags &Flags,
152 bool FindNarrowMerge);
163 const LdStPairFlags &Flags);
169 const LdStPairFlags &Flags);
181 int UnscaledOffset,
unsigned Limit);
199 unsigned BaseReg,
int Offset);
202 unsigned IndexReg,
unsigned &
Offset);
235 MachineFunctionProperties::Property::NoVRegs);
241char AArch64LoadStoreOpt::ID = 0;
248static
bool isNarrowStore(
unsigned Opc) {
252 case AArch64::STRBBui:
253 case AArch64::STURBBi:
254 case AArch64::STRHHui:
255 case AArch64::STURHHi:
263 switch (
MI.getOpcode()) {
269 case AArch64::STZ2Gi:
275 bool *IsValidLdStrOpc =
nullptr) {
277 *IsValidLdStrOpc =
true;
281 *IsValidLdStrOpc =
false;
282 return std::numeric_limits<unsigned>::max();
283 case AArch64::STRDui:
284 case AArch64::STURDi:
285 case AArch64::STRDpre:
286 case AArch64::STRQui:
287 case AArch64::STURQi:
288 case AArch64::STRQpre:
289 case AArch64::STRBBui:
290 case AArch64::STURBBi:
291 case AArch64::STRHHui:
292 case AArch64::STURHHi:
293 case AArch64::STRWui:
294 case AArch64::STRWpre:
295 case AArch64::STURWi:
296 case AArch64::STRXui:
297 case AArch64::STRXpre:
298 case AArch64::STURXi:
299 case AArch64::LDRDui:
300 case AArch64::LDURDi:
301 case AArch64::LDRDpre:
302 case AArch64::LDRQui:
303 case AArch64::LDURQi:
304 case AArch64::LDRQpre:
305 case AArch64::LDRWui:
306 case AArch64::LDURWi:
307 case AArch64::LDRWpre:
308 case AArch64::LDRXui:
309 case AArch64::LDURXi:
310 case AArch64::LDRXpre:
311 case AArch64::STRSui:
312 case AArch64::STURSi:
313 case AArch64::STRSpre:
314 case AArch64::LDRSui:
315 case AArch64::LDURSi:
316 case AArch64::LDRSpre:
318 case AArch64::LDRSWui:
319 return AArch64::LDRWui;
320 case AArch64::LDURSWi:
321 return AArch64::LDURWi;
322 case AArch64::LDRSWpre:
323 return AArch64::LDRWpre;
331 case AArch64::STRBBui:
332 return AArch64::STRHHui;
333 case AArch64::STRHHui:
334 return AArch64::STRWui;
335 case AArch64::STURBBi:
336 return AArch64::STURHHi;
337 case AArch64::STURHHi:
338 return AArch64::STURWi;
339 case AArch64::STURWi:
340 return AArch64::STURXi;
341 case AArch64::STRWui:
342 return AArch64::STRXui;
350 case AArch64::STRSui:
351 case AArch64::STURSi:
352 return AArch64::STPSi;
353 case AArch64::STRSpre:
354 return AArch64::STPSpre;
355 case AArch64::STRDui:
356 case AArch64::STURDi:
357 return AArch64::STPDi;
358 case AArch64::STRDpre:
359 return AArch64::STPDpre;
360 case AArch64::STRQui:
361 case AArch64::STURQi:
362 return AArch64::STPQi;
363 case AArch64::STRQpre:
364 return AArch64::STPQpre;
365 case AArch64::STRWui:
366 case AArch64::STURWi:
367 return AArch64::STPWi;
368 case AArch64::STRWpre:
369 return AArch64::STPWpre;
370 case AArch64::STRXui:
371 case AArch64::STURXi:
372 return AArch64::STPXi;
373 case AArch64::STRXpre:
374 return AArch64::STPXpre;
375 case AArch64::LDRSui:
376 case AArch64::LDURSi:
377 return AArch64::LDPSi;
378 case AArch64::LDRSpre:
379 return AArch64::LDPSpre;
380 case AArch64::LDRDui:
381 case AArch64::LDURDi:
382 return AArch64::LDPDi;
383 case AArch64::LDRDpre:
384 return AArch64::LDPDpre;
385 case AArch64::LDRQui:
386 case AArch64::LDURQi:
387 return AArch64::LDPQi;
388 case AArch64::LDRQpre:
389 return AArch64::LDPQpre;
390 case AArch64::LDRWui:
391 case AArch64::LDURWi:
392 return AArch64::LDPWi;
393 case AArch64::LDRWpre:
394 return AArch64::LDPWpre;
395 case AArch64::LDRXui:
396 case AArch64::LDURXi:
397 return AArch64::LDPXi;
398 case AArch64::LDRXpre:
399 return AArch64::LDPXpre;
400 case AArch64::LDRSWui:
401 case AArch64::LDURSWi:
402 return AArch64::LDPSWi;
403 case AArch64::LDRSWpre:
404 return AArch64::LDPSWpre;
415 case AArch64::LDRBBui:
416 return StOpc == AArch64::STRBBui || StOpc == AArch64::STRHHui ||
417 StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
418 case AArch64::LDURBBi:
419 return StOpc == AArch64::STURBBi || StOpc == AArch64::STURHHi ||
420 StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
421 case AArch64::LDRHHui:
422 return StOpc == AArch64::STRHHui || StOpc == AArch64::STRWui ||
423 StOpc == AArch64::STRXui;
424 case AArch64::LDURHHi:
425 return StOpc == AArch64::STURHHi || StOpc == AArch64::STURWi ||
426 StOpc == AArch64::STURXi;
427 case AArch64::LDRWui:
428 return StOpc == AArch64::STRWui || StOpc == AArch64::STRXui;
429 case AArch64::LDURWi:
430 return StOpc == AArch64::STURWi || StOpc == AArch64::STURXi;
431 case AArch64::LDRXui:
432 return StOpc == AArch64::STRXui;
433 case AArch64::LDURXi:
434 return StOpc == AArch64::STURXi;
446 case AArch64::STRSui:
447 return AArch64::STRSpre;
448 case AArch64::STRDui:
449 return AArch64::STRDpre;
450 case AArch64::STRQui:
451 return AArch64::STRQpre;
452 case AArch64::STRBBui:
453 return AArch64::STRBBpre;
454 case AArch64::STRHHui:
455 return AArch64::STRHHpre;
456 case AArch64::STRWui:
457 return AArch64::STRWpre;
458 case AArch64::STRXui:
459 return AArch64::STRXpre;
460 case AArch64::LDRSui:
461 return AArch64::LDRSpre;
462 case AArch64::LDRDui:
463 return AArch64::LDRDpre;
464 case AArch64::LDRQui:
465 return AArch64::LDRQpre;
466 case AArch64::LDRBBui:
467 return AArch64::LDRBBpre;
468 case AArch64::LDRHHui:
469 return AArch64::LDRHHpre;
470 case AArch64::LDRWui:
471 return AArch64::LDRWpre;
472 case AArch64::LDRXui:
473 return AArch64::LDRXpre;
474 case AArch64::LDRSWui:
475 return AArch64::LDRSWpre;
477 return AArch64::LDPSpre;
478 case AArch64::LDPSWi:
479 return AArch64::LDPSWpre;
481 return AArch64::LDPDpre;
483 return AArch64::LDPQpre;
485 return AArch64::LDPWpre;
487 return AArch64::LDPXpre;
489 return AArch64::STPSpre;
491 return AArch64::STPDpre;
493 return AArch64::STPQpre;
495 return AArch64::STPWpre;
497 return AArch64::STPXpre;
499 return AArch64::STGPreIndex;
501 return AArch64::STZGPreIndex;
503 return AArch64::ST2GPreIndex;
504 case AArch64::STZ2Gi:
505 return AArch64::STZ2GPreIndex;
507 return AArch64::STGPpre;
516 case AArch64::LDRBBroX:
517 return AArch64::LDRBBui;
525 case AArch64::STRSui:
526 case AArch64::STURSi:
527 return AArch64::STRSpost;
528 case AArch64::STRDui:
529 case AArch64::STURDi:
530 return AArch64::STRDpost;
531 case AArch64::STRQui:
532 case AArch64::STURQi:
533 return AArch64::STRQpost;
534 case AArch64::STRBBui:
535 return AArch64::STRBBpost;
536 case AArch64::STRHHui:
537 return AArch64::STRHHpost;
538 case AArch64::STRWui:
539 case AArch64::STURWi:
540 return AArch64::STRWpost;
541 case AArch64::STRXui:
542 case AArch64::STURXi:
543 return AArch64::STRXpost;
544 case AArch64::LDRSui:
545 case AArch64::LDURSi:
546 return AArch64::LDRSpost;
547 case AArch64::LDRDui:
548 case AArch64::LDURDi:
549 return AArch64::LDRDpost;
550 case AArch64::LDRQui:
551 case AArch64::LDURQi:
552 return AArch64::LDRQpost;
553 case AArch64::LDRBBui:
554 return AArch64::LDRBBpost;
555 case AArch64::LDRHHui:
556 return AArch64::LDRHHpost;
557 case AArch64::LDRWui:
558 case AArch64::LDURWi:
559 return AArch64::LDRWpost;
560 case AArch64::LDRXui:
561 case AArch64::LDURXi:
562 return AArch64::LDRXpost;
563 case AArch64::LDRSWui:
564 return AArch64::LDRSWpost;
566 return AArch64::LDPSpost;
567 case AArch64::LDPSWi:
568 return AArch64::LDPSWpost;
570 return AArch64::LDPDpost;
572 return AArch64::LDPQpost;
574 return AArch64::LDPWpost;
576 return AArch64::LDPXpost;
578 return AArch64::STPSpost;
580 return AArch64::STPDpost;
582 return AArch64::STPQpost;
584 return AArch64::STPWpost;
586 return AArch64::STPXpost;
588 return AArch64::STGPostIndex;
590 return AArch64::STZGPostIndex;
592 return AArch64::ST2GPostIndex;
593 case AArch64::STZ2Gi:
594 return AArch64::STZ2GPostIndex;
596 return AArch64::STGPpost;
603 unsigned OpcB =
MI.getOpcode();
608 case AArch64::STRSpre:
609 return (OpcB == AArch64::STRSui) || (OpcB == AArch64::STURSi);
610 case AArch64::STRDpre:
611 return (OpcB == AArch64::STRDui) || (OpcB == AArch64::STURDi);
612 case AArch64::STRQpre:
613 return (OpcB == AArch64::STRQui) || (OpcB == AArch64::STURQi);
614 case AArch64::STRWpre:
615 return (OpcB == AArch64::STRWui) || (OpcB == AArch64::STURWi);
616 case AArch64::STRXpre:
617 return (OpcB == AArch64::STRXui) || (OpcB == AArch64::STURXi);
618 case AArch64::LDRSpre:
619 return (OpcB == AArch64::LDRSui) || (OpcB == AArch64::LDURSi);
620 case AArch64::LDRDpre:
621 return (OpcB == AArch64::LDRDui) || (OpcB == AArch64::LDURDi);
622 case AArch64::LDRQpre:
623 return (OpcB == AArch64::LDRQui) || (OpcB == AArch64::LDURQi);
624 case AArch64::LDRWpre:
625 return (OpcB == AArch64::LDRWui) || (OpcB == AArch64::LDURWi);
626 case AArch64::LDRXpre:
627 return (OpcB == AArch64::LDRXui) || (OpcB == AArch64::LDURXi);
628 case AArch64::LDRSWpre:
629 return (OpcB == AArch64::LDRSWui) || (OpcB == AArch64::LDURSWi);
635 int &MinOffset,
int &MaxOffset) {
653 unsigned PairedRegOp = 0) {
654 assert(PairedRegOp < 2 &&
"Unexpected register operand idx.");
660 return MI.getOperand(
Idx);
669 int UnscaledStOffset =
673 int UnscaledLdOffset =
677 return (UnscaledStOffset <= UnscaledLdOffset) &&
678 (UnscaledLdOffset + LoadSize <= (UnscaledStOffset + StoreSize));
682 unsigned Opc =
MI.getOpcode();
683 return (Opc == AArch64::STRWui || Opc == AArch64::STURWi ||
684 isNarrowStore(Opc)) &&
689 switch (
MI.getOpcode()) {
693 case AArch64::LDRBBui:
694 case AArch64::LDRHHui:
695 case AArch64::LDRWui:
696 case AArch64::LDRXui:
698 case AArch64::LDURBBi:
699 case AArch64::LDURHHi:
700 case AArch64::LDURWi:
701 case AArch64::LDURXi:
707 unsigned Opc =
MI.getOpcode();
712 case AArch64::STRSui:
713 case AArch64::STRDui:
714 case AArch64::STRQui:
715 case AArch64::STRXui:
716 case AArch64::STRWui:
717 case AArch64::STRHHui:
718 case AArch64::STRBBui:
719 case AArch64::LDRSui:
720 case AArch64::LDRDui:
721 case AArch64::LDRQui:
722 case AArch64::LDRXui:
723 case AArch64::LDRWui:
724 case AArch64::LDRHHui:
725 case AArch64::LDRBBui:
729 case AArch64::STZ2Gi:
732 case AArch64::STURSi:
733 case AArch64::STURDi:
734 case AArch64::STURQi:
735 case AArch64::STURWi:
736 case AArch64::STURXi:
737 case AArch64::LDURSi:
738 case AArch64::LDURDi:
739 case AArch64::LDURQi:
740 case AArch64::LDURWi:
741 case AArch64::LDURXi:
744 case AArch64::LDPSWi:
764 unsigned Opc =
MI.getOpcode();
770 case AArch64::LDRBBroX:
780 case AArch64::ORRWrs:
781 case AArch64::ADDWri:
789 const LdStPairFlags &Flags) {
791 "Expected promotable zero stores.");
799 if (NextI == MergeMI)
802 unsigned Opc =
I->getOpcode();
803 unsigned MergeMIOpc = MergeMI->getOpcode();
804 bool IsScaled = !
TII->hasUnscaledLdStOffset(Opc);
805 bool IsMergedMIScaled = !
TII->hasUnscaledLdStOffset(MergeMIOpc);
806 int OffsetStride = IsScaled ?
TII->getMemScale(*
I) : 1;
807 int MergeMIOffsetStride = IsMergedMIScaled ?
TII->getMemScale(*MergeMI) : 1;
809 bool MergeForward =
Flags.getMergeForward();
820 int64_t IOffsetInBytes =
822 int64_t MIOffsetInBytes =
827 if (IOffsetInBytes > MIOffsetInBytes)
828 OffsetImm = MIOffsetInBytes;
830 OffsetImm = IOffsetInBytes;
833 bool FinalIsScaled = !
TII->hasUnscaledLdStOffset(NewOpcode);
837 int NewOffsetStride = FinalIsScaled ?
TII->getMemScale(NewOpcode) : 1;
838 assert(((OffsetImm % NewOffsetStride) == 0) &&
839 "Offset should be a multiple of the store memory scale");
840 OffsetImm = OffsetImm / NewOffsetStride;
848 .
addReg(isNarrowStore(Opc) ? AArch64::WZR : AArch64::XZR)
852 .setMIFlags(
I->mergeFlagsWith(*MergeMI));
855 LLVM_DEBUG(
dbgs() <<
"Creating wider store. Replacing instructions:\n ");
864 I->eraseFromParent();
865 MergeMI->eraseFromParent();
875 auto MBB =
MI.getParent();
883 return MOP.isReg() && MOP.isDef() && !MOP.isDebug() && MOP.getReg() &&
884 TRI->regsOverlap(MOP.getReg(), DefReg);
898 if (MOP.isReg() && MOP.isKill())
902 if (MOP.isReg() && !MOP.isKill())
903 Units.
addReg(MOP.getReg());
909 const LdStPairFlags &Flags) {
919 int SExtIdx =
Flags.getSExtIdx();
922 bool IsUnscaled =
TII->hasUnscaledLdStOffset(Opc);
923 int OffsetStride = IsUnscaled ?
TII->getMemScale(*
I) : 1;
925 bool MergeForward =
Flags.getMergeForward();
927 std::optional<MCPhysReg> RenameReg =
Flags.getRenameReg();
930 DefinedInBB.addReg(*RenameReg);
934 auto GetMatchingSubReg =
937 TRI->sub_and_superregs_inclusive(*RenameReg)) {
938 if (
C->contains(SubOrSuper))
945 [
this, RegToRename, GetMatchingSubReg, MergeForward](
MachineInstr &
MI,
948 bool SeenDef =
false;
949 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
954 (!MergeForward || !SeenDef ||
956 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
959 "Need renamable operands");
962 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
963 MatchingReg = GetMatchingSubReg(RC);
967 MatchingReg = GetMatchingSubReg(
968 TRI->getMinimalPhysRegClass(MOP.
getReg()));
975 for (
unsigned OpIdx = 0; OpIdx <
MI.getNumOperands(); ++OpIdx) {
978 TRI->regsOverlap(MOP.
getReg(), RegToRename)) {
981 "Need renamable operands");
984 MI.getRegClassConstraint(OpIdx,
TII,
TRI))
985 MatchingReg = GetMatchingSubReg(RC);
987 MatchingReg = GetMatchingSubReg(
988 TRI->getMinimalPhysRegClass(MOP.
getReg()));
989 assert(MatchingReg != AArch64::NoRegister &&
990 "Cannot find matching regs for renaming");
999 UINT32_MAX, UpdateMIs);
1012 RegToCheck = RegToRename;
1015 MergeForward ? std::next(
I) :
I,
1016 MergeForward ? std::next(Paired) : Paired))
1019 return !MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1021 !TRI->regsOverlap(MOP.getReg(), RegToCheck);
1023 "Rename register used between paired instruction, trashing the "
1039 bool PairedIsUnscaled =
TII->hasUnscaledLdStOffset(Paired->getOpcode());
1040 if (IsUnscaled != PairedIsUnscaled) {
1044 int MemSize =
TII->getMemScale(*Paired);
1045 if (PairedIsUnscaled) {
1048 assert(!(PairedOffset %
TII->getMemScale(*Paired)) &&
1049 "Offset should be a multiple of the stride!");
1050 PairedOffset /= MemSize;
1052 PairedOffset *= MemSize;
1060 if (
Offset == PairedOffset + OffsetStride &&
1068 SExtIdx = (SExtIdx + 1) % 2;
1076 assert(!(OffsetImm %
TII->getMemScale(*RtMI)) &&
1077 "Unscaled offset cannot be scaled.");
1078 OffsetImm /=
TII->getMemScale(*RtMI);
1087 MachineOperand &PairedRegOp = RtMI == &*Paired ? RegOp0 : RegOp1;
1089 if (RegOp0.
isUse()) {
1090 if (!MergeForward) {
1101 for (
auto It = std::next(
I); It != Paired && PairedRegOp.
isKill(); ++It)
1102 if (It->readsRegister(PairedRegOp.
getReg(),
TRI))
1111 MI.clearRegisterKills(Reg,
TRI);
1127 .setMIFlags(
I->mergeFlagsWith(*Paired));
1132 dbgs() <<
"Creating pair load/store. Replacing instructions:\n ");
1137 if (SExtIdx != -1) {
1147 Register DstRegW =
TRI->getSubReg(DstRegX, AArch64::sub_32);
1157 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(TargetOpcode::KILL), DstRegW)
1163 BuildMI(*
MBB, InsertionPoint,
DL,
TII->get(AArch64::SBFMXri), DstRegX)
1178 DefinedInBB.addReg(MOP.
getReg());
1181 I->eraseFromParent();
1182 Paired->eraseFromParent();
1191 next_nodbg(LoadI, LoadI->getParent()->end());
1193 int LoadSize =
TII->getMemScale(*LoadI);
1194 int StoreSize =
TII->getMemScale(*StoreI);
1198 bool IsStoreXReg =
TRI->getRegClass(AArch64::GPR64RegClassID)->contains(StRt);
1201 TRI->getRegClass(AArch64::GPR32RegClassID)->contains(StRt)) &&
1202 "Unexpected RegClass");
1205 if (LoadSize == StoreSize && (LoadSize == 4 || LoadSize == 8)) {
1208 if (StRt == LdRt && LoadSize == 8) {
1210 LoadI->getIterator())) {
1211 if (
MI.killsRegister(StRt,
TRI)) {
1212 MI.clearRegisterKills(StRt,
TRI);
1219 LoadI->eraseFromParent();
1224 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1225 TII->get(IsStoreXReg ? AArch64::ORRXrs : AArch64::ORRWrs), LdRt)
1226 .
addReg(IsStoreXReg ? AArch64::XZR : AArch64::WZR)
1233 if (!Subtarget->isLittleEndian())
1235 bool IsUnscaled =
TII->hasUnscaledLdStOffset(*LoadI);
1236 assert(IsUnscaled ==
TII->hasUnscaledLdStOffset(*StoreI) &&
1237 "Unsupported ld/st match");
1238 assert(LoadSize <= StoreSize &&
"Invalid load size");
1239 int UnscaledLdOffset =
1243 int UnscaledStOffset =
1247 int Width = LoadSize * 8;
1250 LdRt, AArch64::sub_32, &AArch64::GPR64RegClass))
1253 assert((UnscaledLdOffset >= UnscaledStOffset &&
1254 (UnscaledLdOffset + LoadSize) <= UnscaledStOffset + StoreSize) &&
1257 int Immr = 8 * (UnscaledLdOffset - UnscaledStOffset);
1258 int Imms = Immr + Width - 1;
1259 if (UnscaledLdOffset == UnscaledStOffset) {
1260 uint32_t AndMaskEncoded = ((IsStoreXReg ? 1 : 0) << 12)
1266 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1267 TII->get(IsStoreXReg ? AArch64::ANDXri : AArch64::ANDWri),
1274 BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(),
1275 TII->get(IsStoreXReg ? AArch64::UBFMXri : AArch64::UBFMWri),
1287 if (
MI.killsRegister(StRt,
TRI)) {
1288 MI.clearRegisterKills(StRt,
TRI);
1303 LoadI->eraseFromParent();
1313 if (
Offset % OffsetStride)
1317 return Offset <= 63 && Offset >= -64;
1325 return (Num + PowOf2 - 1) & ~(PowOf2 - 1);
1332 if (MIa.
mayAlias(AA, *MIb,
false)) {
1342bool AArch64LoadStoreOpt::findMatchingStore(
1357 ModifiedRegUnits.clear();
1358 UsedRegUnits.clear();
1367 if (!
MI.isTransient())
1393 if (!ModifiedRegUnits.available(BaseReg))
1399 }
while (
MBBI !=
B && Count < Limit);
1411 LdStPairFlags &Flags,
1414 if (
MI.hasOrderedMemoryRef() ||
TII->isLdStPairSuppressed(
MI))
1419 !
TII->isLdStPairSuppressed(FirstMI) &&
1420 "FirstMI shouldn't get here if either of these checks are true.");
1427 unsigned OpcB =
MI.getOpcode();
1438 bool IsValidLdStrOpc, PairIsValidLdStrOpc;
1440 assert(IsValidLdStrOpc &&
1441 "Given Opc should be a Load or Store with an immediate");
1444 Flags.setSExtIdx(NonSExtOpc == (
unsigned)OpcA ? 1 : 0);
1450 if (!PairIsValidLdStrOpc)
1455 if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
1465 return TII->hasUnscaledLdStOffset(OpcA) !=
TII->hasUnscaledLdStOffset(OpcB) &&
1474 auto *RegClass =
TRI->getMinimalPhysRegClass(MOP.
getReg());
1481 if (RegClass->HasDisjunctSubRegs) {
1484 <<
" Cannot rename operands with multiple disjunct subregisters ("
1495 return TRI->isSuperOrSubRegisterEq(
1518 return MOP.isReg() && !MOP.isDebug() && MOP.getReg() &&
1519 MOP.isImplicit() && MOP.isKill() &&
1520 TRI->regsOverlap(RegToRename, MOP.getReg());
1526 bool FoundDef =
false;
1557 if (
MI.isPseudo()) {
1558 LLVM_DEBUG(
dbgs() <<
" Cannot rename pseudo/bundle instruction\n");
1562 for (
auto &MOP :
MI.operands()) {
1564 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1574 for (
auto &MOP :
MI.operands()) {
1576 !
TRI->regsOverlap(MOP.
getReg(), RegToRename))
1593 LLVM_DEBUG(
dbgs() <<
" Did not find definition for register in BB\n");
1621 LLVM_DEBUG(dbgs() <<
"Checking " << MI);
1623 if (MI.getFlag(MachineInstr::FrameSetup)) {
1624 LLVM_DEBUG(dbgs() <<
" Cannot rename framesetup instructions "
1629 for (
auto &MOP :
MI.operands()) {
1630 if (!MOP.isReg() || MOP.isDebug() || !MOP.getReg() ||
1631 !TRI->regsOverlap(MOP.getReg(), RegToRename))
1633 if (!canRenameMOP(MOP, TRI)) {
1634 LLVM_DEBUG(dbgs() <<
" Cannot rename " << MOP <<
" in " << MI);
1660 auto AnySubOrSuperRegCalleePreserved = [&MF,
TRI](
MCPhysReg PR) {
1661 return any_of(
TRI->sub_and_superregs_inclusive(PR),
1663 return TRI->isCalleeSavedPhysReg(SubOrSuper, MF);
1669 auto CanBeUsedForAllClasses = [&RequiredClasses,
TRI](
MCPhysReg PR) {
1672 TRI->sub_and_superregs_inclusive(PR),
1673 [
C](
MCPhysReg SubOrSuper) { return C->contains(SubOrSuper); });
1677 auto *RegClass =
TRI->getMinimalPhysRegClass(Reg);
1680 !
RegInfo.isReserved(PR) && !AnySubOrSuperRegCalleePreserved(PR) &&
1681 CanBeUsedForAllClasses(PR)) {
1689 <<
TRI->getRegClassName(RegClass) <<
"\n");
1690 return std::nullopt;
1701 std::optional<MCPhysReg> RenameReg;
1710 const bool IsLoad = FirstMI.
mayLoad();
1712 if (!MaybeCanRename) {
1715 RequiredClasses,
TRI)};
1721 if (*MaybeCanRename) {
1723 RequiredClasses,
TRI);
1732 LdStPairFlags &Flags,
unsigned Limit,
1733 bool FindNarrowMerge) {
1741 bool IsUnscaled =
TII->hasUnscaledLdStOffset(FirstMI);
1745 int OffsetStride = IsUnscaled ?
TII->getMemScale(FirstMI) : 1;
1748 std::optional<bool> MaybeCanRename;
1750 MaybeCanRename = {
false};
1756 Flags.clearRenameReg();
1760 ModifiedRegUnits.clear();
1761 UsedRegUnits.clear();
1767 for (
unsigned Count = 0;
MBBI != E && Count < Limit;
1776 if (!
MI.isTransient())
1779 Flags.setSExtIdx(-1);
1782 assert(
MI.mayLoadOrStore() &&
"Expected memory operation.");
1791 bool MIIsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
1792 if (IsUnscaled != MIIsUnscaled) {
1796 int MemSize =
TII->getMemScale(
MI);
1800 if (MIOffset % MemSize) {
1806 MIOffset /= MemSize;
1808 MIOffset *= MemSize;
1814 if (BaseReg == MIBaseReg) {
1820 bool IsOutOfBounds = MIOffset !=
TII->getMemScale(
MI);
1821 bool IsBaseRegUsed = !UsedRegUnits.available(
1823 bool IsBaseRegModified = !ModifiedRegUnits.available(
1828 bool IsMIRegTheSame =
1831 if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified ||
1839 if ((
Offset != MIOffset + OffsetStride) &&
1840 (
Offset + OffsetStride != MIOffset)) {
1849 if (FindNarrowMerge) {
1854 if ((!IsUnscaled &&
alignTo(MinOffset, 2) != MinOffset) ||
1871 <<
"keep looking.\n");
1877 if (IsUnscaled && (
alignTo(MinOffset, OffsetStride) != MinOffset)) {
1882 <<
"Offset doesn't fit due to alignment requirements, "
1883 <<
"keep looking.\n");
1894 if (!ModifiedRegUnits.available(BaseReg))
1897 const bool SameLoadReg =
MayLoad &&
TRI->isSuperOrSubRegisterEq(
1904 bool RtNotModified =
1906 bool RtNotUsed = !(
MI.mayLoad() && !SameLoadReg &&
1909 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 2nd into 1st insn:\n"
1911 << (RtNotModified ?
"true" :
"false") <<
"\n"
1913 << (RtNotUsed ?
"true" :
"false") <<
"\n");
1915 if (RtNotModified && RtNotUsed && !
mayAlias(
MI, MemInsns, AA)) {
1920 std::optional<MCPhysReg> RenameReg =
1922 Reg, DefinedInBB, UsedInBetween,
1923 RequiredClasses,
TRI);
1929 <<
"keep looking.\n");
1932 Flags.setRenameReg(*RenameReg);
1935 Flags.setMergeForward(
false);
1937 Flags.clearRenameReg();
1948 LLVM_DEBUG(
dbgs() <<
"Checking, can combine 1st into 2nd insn:\n"
1950 <<
"' not modified: "
1951 << (RtNotModified ?
"true" :
"false") <<
"\n");
1953 if (RtNotModified && !
mayAlias(FirstMI, MemInsns, AA)) {
1955 Flags.setMergeForward(
true);
1956 Flags.clearRenameReg();
1961 MaybeCanRename, FirstMI,
MI, Reg, DefinedInBB, UsedInBetween,
1962 RequiredClasses,
TRI);
1964 Flags.setMergeForward(
true);
1965 Flags.setRenameReg(*RenameReg);
1966 MBBIWithRenameReg =
MBBI;
1969 LLVM_DEBUG(
dbgs() <<
"Unable to combine these instructions due to "
1970 <<
"interference in between, keep looking.\n");
1974 if (
Flags.getRenameReg())
1975 return MBBIWithRenameReg;
1989 if (!ModifiedRegUnits.available(BaseReg)) {
1995 if (
MI.mayLoadOrStore())
2003 assert((
MI.getOpcode() == AArch64::SUBXri ||
2004 MI.getOpcode() == AArch64::ADDXri) &&
2005 "Expected a register update instruction");
2006 auto End =
MI.getParent()->end();
2007 if (MaybeCFI ==
End ||
2008 MaybeCFI->getOpcode() != TargetOpcode::CFI_INSTRUCTION ||
2011 MI.getOperand(0).getReg() != AArch64::SP)
2015 unsigned CFIIndex = MaybeCFI->getOperand(0).getCFIIndex();
2030 assert((Update->getOpcode() == AArch64::ADDXri ||
2031 Update->getOpcode() == AArch64::SUBXri) &&
2032 "Unexpected base register update instruction to merge!");
2044 if (NextI == Update)
2047 int Value = Update->getOperand(2).getImm();
2049 "Can't merge 1 << 12 offset into pre-/post-indexed load / store");
2050 if (Update->getOpcode() == AArch64::SUBXri)
2056 int Scale, MinOffset, MaxOffset;
2060 MIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2061 .
add(Update->getOperand(0))
2069 MIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2070 .
add(Update->getOperand(0))
2099 I->eraseFromParent();
2100 Update->eraseFromParent();
2108 unsigned Offset,
int Scale) {
2109 assert((Update->getOpcode() == AArch64::MOVKWi) &&
2110 "Unexpected const mov instruction to merge!");
2115 unsigned Mask = (1 << 12) * Scale - 1;
2124 BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(AArch64::ADDXri))
2132 MemMIB =
BuildMI(*
I->getParent(),
I,
I->getDebugLoc(),
TII->get(NewOpc))
2140 ++NumConstOffsetFolded;
2155 I->eraseFromParent();
2156 PrevI->eraseFromParent();
2157 Update->eraseFromParent();
2162bool AArch64LoadStoreOpt::isMatchingUpdateInsn(
MachineInstr &MemMI,
2164 unsigned BaseReg,
int Offset) {
2165 switch (
MI.getOpcode()) {
2168 case AArch64::SUBXri:
2169 case AArch64::ADDXri:
2172 if (!
MI.getOperand(2).isImm())
2180 if (
MI.getOperand(0).getReg() != BaseReg ||
2181 MI.getOperand(1).getReg() != BaseReg)
2184 int UpdateOffset =
MI.getOperand(2).getImm();
2185 if (
MI.getOpcode() == AArch64::SUBXri)
2186 UpdateOffset = -UpdateOffset;
2190 int Scale, MinOffset, MaxOffset;
2192 if (UpdateOffset % Scale != 0)
2196 int ScaledOffset = UpdateOffset / Scale;
2197 if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset)
2209bool AArch64LoadStoreOpt::isMatchingMovConstInsn(
MachineInstr &MemMI,
2215 if (
MI.getOpcode() == AArch64::MOVKWi &&
2216 TRI->isSuperOrSubRegisterEq(IndexReg,
MI.getOperand(1).getReg())) {
2226 if (MovzMI.
getOpcode() == AArch64::MOVZWi) {
2228 unsigned High =
MI.getOperand(2).getImm() <<
MI.getOperand(3).getImm();
2231 return Offset >> 24 == 0;
2245 TII->getMemScale(MemMI);
2250 if (MIUnscaledOffset != UnscaledOffset)
2261 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2263 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2270 ModifiedRegUnits.clear();
2271 UsedRegUnits.clear();
2277 const bool BaseRegSP = BaseReg == AArch64::SP;
2285 for (
unsigned Count = 0;
MBBI != E && Count < Limit;
2291 if (!
MI.isTransient())
2295 if (isMatchingUpdateInsn(*
I,
MI, BaseReg, UnscaledOffset))
2305 if (!ModifiedRegUnits.available(BaseReg) ||
2306 !UsedRegUnits.available(BaseReg) ||
2307 (BaseRegSP &&
MBBI->mayLoadOrStore()))
2332 for (
unsigned i = 0, e = IsPairedInsn ? 2 : 1; i !=
e; ++i) {
2334 if (DestReg == BaseReg ||
TRI->isSubRegister(BaseReg, DestReg))
2339 const bool BaseRegSP = BaseReg == AArch64::SP;
2348 unsigned RedZoneSize =
2353 ModifiedRegUnits.clear();
2354 UsedRegUnits.clear();
2356 bool MemAcessBeforeSPPreInc =
false;
2363 if (!
MI.isTransient())
2367 if (isMatchingUpdateInsn(*
I,
MI, BaseReg,
Offset)) {
2370 if (MemAcessBeforeSPPreInc &&
MBBI->getOperand(2).getImm() > RedZoneSize)
2380 if (!ModifiedRegUnits.available(BaseReg) ||
2381 !UsedRegUnits.available(BaseReg))
2386 if (BaseRegSP &&
MBBI->mayLoadOrStore())
2387 MemAcessBeforeSPPreInc =
true;
2388 }
while (
MBBI !=
B && Count < Limit);
2393AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
2416 ModifiedRegUnits.clear();
2417 UsedRegUnits.clear();
2425 if (!
MI.isTransient())
2429 if (isMatchingMovConstInsn(*
I,
MI, IndexReg,
Offset)) {
2438 if (!ModifiedRegUnits.available(IndexReg) ||
2439 !UsedRegUnits.available(IndexReg))
2442 }
while (
MBBI !=
B && Count < Limit);
2446bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
2450 if (
MI.hasOrderedMemoryRef())
2464 ++NumLoadsFromStoresPromoted;
2468 MBBI = promoteLoadFromStore(
MBBI, StoreI);
2475bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
2481 if (!
TII->isCandidateToMergeOrPair(
MI))
2485 LdStPairFlags
Flags;
2489 ++NumZeroStoresPromoted;
2493 MBBI = mergeNarrowZeroStores(
MBBI, MergeMI, Flags);
2505 if (!
TII->isCandidateToMergeOrPair(
MI))
2509 if (
MI.mayLoad() && Subtarget->hasDisableLdp())
2513 if (
MI.mayStore() && Subtarget->hasDisableStp())
2519 bool IsUnscaled =
TII->hasUnscaledLdStOffset(
MI);
2521 int OffsetStride = IsUnscaled ?
TII->getMemScale(
MI) : 1;
2529 LdStPairFlags
Flags;
2535 auto Prev = std::prev(
MBBI);
2540 MI.memoperands_empty() ? nullptr :
MI.memoperands().front();
2545 if ((
MI.mayLoad() && Subtarget->hasLdpAlignedOnly()) ||
2546 (
MI.mayStore() && Subtarget->hasStpAlignedOnly())) {
2548 if (!
MemOp || !
MemOp->getMemoryType().isValid()) {
2549 NumFailedAlignmentCheck++;
2558 if (MemAlignment < 2 * TypeAlignment) {
2559 NumFailedAlignmentCheck++;
2565 if (
TII->hasUnscaledLdStOffset(
MI))
2566 ++NumUnscaledPairCreated;
2568 MBBI = mergePairedInsns(
MBBI, Paired, Flags);
2571 for (
auto I = std::next(Prev);
I !=
MBBI;
I++)
2579bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
2593 MBBI = mergeUpdateInsn(
MBBI, Update,
false);
2598 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2609 MBBI = mergeUpdateInsn(
MBBI, Update,
true);
2616 int UnscaledOffset =
2624 Update = findMatchingUpdateInsnForward(
MBBI, UnscaledOffset,
UpdateLimit);
2627 MBBI = mergeUpdateInsn(
MBBI, Update,
true);
2641 if (
TII->hasUnscaledLdStOffset(
MI.getOpcode()))
2653 if (Update != E && (
Offset & (Scale - 1)) == 0) {
2663 bool EnableNarrowZeroStOpt) {
2694 if (EnableNarrowZeroStOpt)
2711 DefinedInBB.
clear();
2712 DefinedInBB.addLiveIns(
MBB);
2720 if (
TII->isPairableLdStInst(*
MBBI) && tryToPairLdStInst(
MBBI))
2766 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
2771 ModifiedRegUnits.init(*
TRI);
2772 UsedRegUnits.init(*
TRI);
2773 DefinedInBB.init(*
TRI);
2776 bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
2777 for (
auto &
MBB : Fn) {
2798 return new AArch64LoadStoreOpt();
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
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 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 cl::opt< unsigned > LdStLimit("aarch64-load-store-scan-limit", cl::init(20), cl::Hidden)
static bool canRenameMOP(const MachineOperand &MOP, const TargetRegisterInfo *TRI)
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 bool isRewritableImplicitDef(unsigned Opc)
static unsigned getPostIndexedOpcode(unsigned Opc)
static cl::opt< unsigned > LdStConstLimit("aarch64-load-store-const-scan-limit", cl::init(10), cl::Hidden)
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)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-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 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.
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 & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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.
bool isPseudo(QueryType Type=IgnoreBundle) const
Return true if this is a pseudo instruction that doesn't correspond to a real machine instruction.
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.
void setIsKill(bool Val=true)
bool isRenamable() const
isRenamable - Returns true if this register may be renamed, i.e.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
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 ==...
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.
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.
@ 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.
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.