80#define DEBUG_TYPE "machine-cp"
82STATISTIC(NumDeletes,
"Number of dead copies deleted");
83STATISTIC(NumCopyForwards,
"Number of copy uses forwarded");
84STATISTIC(NumCopyBackwardPropagated,
"Number of copy defs backward propagated");
85STATISTIC(SpillageChainsLength,
"Length of spillage chains");
86STATISTIC(NumSpillageChains,
"Number of spillage chains");
88 "Controls which register COPYs are forwarded");
100 "MachineCopyPropagation should be run after register allocation!");
108 return asPhysMCReg(DSP.
Source);
110std::pair<MCRegister, MCRegister> getDstSrcMCRegs(
const DestSourcePair &DSP) {
111 return {getDstMCReg(DSP), getSrcMCReg(DSP)};
118 return TII.isCopyInstr(
MI);
128 MachineInstr *MI =
nullptr;
129 MachineInstr *LastSeenUseInCopy =
nullptr;
130 SmallPtrSet<MachineInstr *, 4> SrcUsers;
135 DenseMap<MCRegUnit, CopyInfo> Copies;
140 DenseMap<const uint32_t *, BitVector> RegMaskToPreservedRegUnits;
144 BitVector &getPreservedRegUnits(
const MachineOperand &RegMaskOp,
145 const TargetRegisterInfo &
TRI) {
146 const uint32_t *RegMask = RegMaskOp.
getRegMask();
147 auto [It,
Inserted] = RegMaskToPreservedRegUnits.try_emplace(RegMask);
150 BitVector &PreservedRegUnits = It->second;
152 PreservedRegUnits.
resize(
TRI.getNumRegUnits());
153 for (
unsigned SafeReg = 0,
E =
TRI.getNumRegs(); SafeReg <
E; ++SafeReg)
155 for (MCRegUnit SafeUnit :
TRI.regunits(SafeReg))
156 PreservedRegUnits.
set(
static_cast<unsigned>(SafeUnit));
158 return PreservedRegUnits;
164 const TargetRegisterInfo &
TRI) {
165 for (MCRegister
Reg : Regs) {
167 for (MCRegUnit Unit :
TRI.regunits(
Reg)) {
168 auto CI = Copies.find(Unit);
169 if (CI != Copies.end())
170 CI->second.Avail =
false;
176 void invalidateRegister(MCRegister
Reg,
const TargetRegisterInfo &
TRI,
177 const TargetInstrInfo &
TII,
bool UseCopyInstr) {
182 SmallSet<MCRegUnit, 8> RegUnitsToInvalidate;
183 auto InvalidateCopy = [&](MachineInstr *
MI) {
184 DestSourcePair CopyOperands = *isCopyInstr(*
MI,
TII, UseCopyInstr);
185 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
186 auto DstUnits =
TRI.regunits(Dst);
187 auto SrcUnits =
TRI.regunits(Src);
192 for (MCRegUnit Unit :
TRI.regunits(
Reg)) {
193 auto I = Copies.find(Unit);
194 if (
I != Copies.end()) {
195 if (MachineInstr *
MI =
I->second.MI)
197 if (MachineInstr *
MI =
I->second.LastSeenUseInCopy)
201 for (MCRegUnit Unit : RegUnitsToInvalidate)
206 void clobberRegUnit(MCRegUnit Unit,
const TargetRegisterInfo &
TRI,
207 const TargetInstrInfo &
TII,
bool UseCopyInstr) {
208 auto I = Copies.find(Unit);
209 if (
I != Copies.end()) {
212 markRegsUnavailable(
I->second.DefRegs,
TRI);
215 if (MachineInstr *
MI =
I->second.MI) {
216 DestSourcePair CopyOperands = *isCopyInstr(*
MI,
TII, UseCopyInstr);
217 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
219 markRegsUnavailable(Dst,
TRI);
233 for (MCRegUnit SrcUnit :
TRI.regunits(Src)) {
234 auto SrcCopy = Copies.find(SrcUnit);
235 if (SrcCopy != Copies.end() && SrcCopy->second.LastSeenUseInCopy) {
239 for (
auto Itr = SrcCopy->second.DefRegs.begin();
240 Itr != SrcCopy->second.DefRegs.end(); Itr++) {
242 SrcCopy->second.DefRegs.erase(Itr);
248 if (SrcCopy->second.DefRegs.empty() && !SrcCopy->second.MI) {
249 Copies.erase(SrcCopy);
263 void clobberRegister(MCRegister
Reg,
const TargetRegisterInfo &
TRI,
264 const TargetInstrInfo &
TII,
bool UseCopyInstr) {
265 for (MCRegUnit Unit :
TRI.regunits(
Reg)) {
266 clobberRegUnit(Unit,
TRI,
TII, UseCopyInstr);
273 bool trackSrcUsers(MCRegister
Reg, MachineInstr &
MI,
274 const TargetRegisterInfo &
TRI,
const TargetInstrInfo &
TII,
276 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
277 MachineInstr *AvailCopy = findCopyDefViaUnit(RU,
TRI);
281 DestSourcePair CopyOperands = *isCopyInstr(*AvailCopy,
TII, UseCopyInstr);
282 MCRegister Src = getSrcMCReg(CopyOperands);
288 auto I = Copies.find(RU);
289 if (
I == Copies.end())
292 I->second.SrcUsers.insert(&
MI);
297 SmallPtrSet<MachineInstr *, 4> getSrcUsers(MCRegister
Reg,
298 const TargetRegisterInfo &
TRI) {
299 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
300 auto I = Copies.find(RU);
301 if (
I == Copies.end())
303 return I->second.SrcUsers;
307 void trackCopy(MachineInstr *
MI,
const TargetRegisterInfo &
TRI,
308 const TargetInstrInfo &
TII,
bool UseCopyInstr) {
309 DestSourcePair CopyOperands = *isCopyInstr(*
MI,
TII, UseCopyInstr);
310 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
313 for (MCRegUnit Unit :
TRI.regunits(Dst))
314 Copies[
Unit] = {
MI,
nullptr, {}, {},
true};
318 for (MCRegUnit Unit :
TRI.regunits(Src)) {
321 Copy.DefRegs.push_back(Dst);
322 Copy.LastSeenUseInCopy =
MI;
326 bool hasAnyCopies() {
327 return !Copies.empty();
330 MachineInstr *findCopyForUnit(MCRegUnit RegUnit,
331 const TargetRegisterInfo &
TRI,
332 bool MustBeAvailable =
false) {
333 auto CI = Copies.find(RegUnit);
334 if (CI == Copies.end())
336 if (MustBeAvailable && !CI->second.Avail)
338 return CI->second.MI;
341 MachineInstr *findCopyDefViaUnit(MCRegUnit RegUnit,
342 const TargetRegisterInfo &
TRI) {
343 auto CI = Copies.find(RegUnit);
344 if (CI == Copies.end())
346 if (CI->second.DefRegs.size() != 1)
348 MCRegUnit RU = *
TRI.regunits(CI->second.DefRegs[0]).begin();
349 return findCopyForUnit(RU,
TRI,
true);
352 MachineInstr *findAvailBackwardCopy(MachineInstr &
I, MCRegister
Reg,
353 const TargetRegisterInfo &
TRI,
354 const TargetInstrInfo &
TII,
356 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
357 MachineInstr *AvailCopy = findCopyDefViaUnit(RU,
TRI);
362 DestSourcePair CopyOperands = *isCopyInstr(*AvailCopy,
TII, UseCopyInstr);
363 auto [AvailDst, AvailSrc] = getDstSrcMCRegs(CopyOperands);
364 if (!
TRI.isSubRegisterEq(AvailSrc,
Reg))
367 for (
const MachineInstr &
MI :
369 for (
const MachineOperand &MO :
MI.operands())
372 if (MO.clobbersPhysReg(AvailSrc) || MO.clobbersPhysReg(AvailDst))
378 MachineInstr *findAvailCopy(MachineInstr &DestCopy, MCRegister
Reg,
379 const TargetRegisterInfo &
TRI,
380 const TargetInstrInfo &
TII,
bool UseCopyInstr) {
383 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
384 MachineInstr *AvailCopy =
385 findCopyForUnit(RU,
TRI,
true);
390 DestSourcePair CopyOperands = *isCopyInstr(*AvailCopy,
TII, UseCopyInstr);
391 auto [AvailDst, AvailSrc] = getDstSrcMCRegs(CopyOperands);
392 if (!
TRI.isSubRegisterEq(AvailDst,
Reg))
397 for (
const MachineInstr &
MI :
399 for (
const MachineOperand &MO :
MI.operands())
401 if (MO.clobbersPhysReg(AvailSrc) || MO.clobbersPhysReg(AvailDst))
408 MachineInstr *findLastSeenDefInCopy(
const MachineInstr &Current,
410 const TargetRegisterInfo &
TRI,
411 const TargetInstrInfo &
TII,
413 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
414 auto CI = Copies.find(RU);
415 if (CI == Copies.end() || !CI->second.Avail)
418 MachineInstr *DefCopy = CI->second.MI;
419 DestSourcePair CopyOperands = *isCopyInstr(*DefCopy,
TII, UseCopyInstr);
420 MCRegister Dst = getDstMCReg(CopyOperands);
421 if (!
TRI.isSubRegisterEq(Dst,
Reg))
424 for (
const MachineInstr &
MI :
425 make_range(
static_cast<const MachineInstr *
>(DefCopy)->getIterator(),
427 for (
const MachineOperand &MO :
MI.operands())
429 if (MO.clobbersPhysReg(Dst)) {
439 MachineInstr *findLastSeenUseInCopy(MCRegister
Reg,
440 const TargetRegisterInfo &
TRI) {
441 MCRegUnit RU = *
TRI.regunits(
Reg).begin();
442 auto CI = Copies.find(RU);
443 if (CI == Copies.end())
445 return CI->second.LastSeenUseInCopy;
453class MachineCopyPropagation {
454 const TargetRegisterInfo *TRI =
nullptr;
455 const TargetInstrInfo *TII =
nullptr;
456 const MachineRegisterInfo *MRI =
nullptr;
462 MachineCopyPropagation(
bool CopyInstr =
false)
465 bool run(MachineFunction &MF);
468 typedef enum { DebugUse =
false, RegularUse =
true } DebugType;
471 void readSuccessorLiveIns(
const MachineBasicBlock &
MBB);
472 void forwardCopyPropagateBlock(MachineBasicBlock &
MBB);
473 void backwardCopyPropagateBlock(MachineBasicBlock &
MBB);
474 void eliminateSpillageCopies(MachineBasicBlock &
MBB);
475 bool eraseIfRedundant(MachineInstr &Copy, MCRegister Dst, MCRegister Src);
476 void forwardUses(MachineInstr &
MI);
477 void propagateDefs(MachineInstr &
MI);
478 bool isForwardableRegClassCopy(
const MachineInstr &Copy,
479 const MachineInstr &UseI,
unsigned UseIdx);
480 bool isBackwardPropagatableRegClassCopy(
const MachineInstr &Copy,
481 const MachineInstr &UseI,
483 bool isBackwardPropagatableCopy(
const MachineInstr &Copy,
484 const DestSourcePair &CopyOperands);
487 bool isNeverRedundant(MCRegister CopyOperand) {
491 return MRI->isReserved(CopyOperand);
495 bool isNeverRedundant(
const MachineInstr &Copy) {
499 bool hasImplicitOverlap(
const MachineInstr &
MI,
const MachineOperand &Use);
500 bool hasOverlappingMultipleDef(
const MachineInstr &
MI,
501 const MachineOperand &MODef, MCRegister Def);
502 bool canUpdateSrcUsers(
const MachineInstr &Copy,
503 const MachineOperand &CopySrc);
506 SmallSetVector<MachineInstr *, 8> MaybeDeadCopies;
509 DenseMap<MachineInstr *, SmallPtrSet<MachineInstr *, 2>> CopyDbgUsers;
513 bool Changed =
false;
522 MachineCopyPropagationLegacy(
bool UseCopyInstr =
false)
523 : MachineFunctionPass(ID), UseCopyInstr(UseCopyInstr) {}
525 void getAnalysisUsage(AnalysisUsage &AU)
const override {
530 bool runOnMachineFunction(MachineFunction &MF)
override;
532 MachineFunctionProperties getRequiredProperties()
const override {
533 return MachineFunctionProperties().setNoVRegs();
539char MachineCopyPropagationLegacy::ID = 0;
544 "Machine Copy Propagation Pass",
false,
false)
551 for (MCRegUnit Unit :
TRI->regunits(
Reg)) {
552 if (MachineInstr *Copy = Tracker.findCopyForUnit(Unit, *TRI)) {
553 if (DT == RegularUse) {
554 LLVM_DEBUG(dbgs() <<
"MCP: Copy is used - not dead: "; Copy->dump());
555 MaybeDeadCopies.remove(Copy);
557 CopyDbgUsers[Copy].insert(&Reader);
563void MachineCopyPropagation::readSuccessorLiveIns(
565 if (MaybeDeadCopies.empty())
570 for (
const auto &LI : Succ->liveins()) {
571 for (MCRegUnitMaskIterator
U(LI.PhysReg,
TRI);
U.isValid(); ++U) {
573 if ((Mask & LI.LaneMask).any()) {
574 if (MachineInstr *Copy = Tracker.findCopyForUnit(Unit, *
TRI))
575 MaybeDeadCopies.remove(Copy);
593 auto [PreviousDst, PreviousSrc] = getDstSrcMCRegs(CopyOperands);
594 if (Src == PreviousSrc && Dst == PreviousDst)
596 if (!
TRI->isSubRegister(PreviousSrc, Src))
598 unsigned SubIdx =
TRI->getSubRegIndex(PreviousSrc, Src);
599 return SubIdx ==
TRI->getSubRegIndex(PreviousDst, Dst);
605bool MachineCopyPropagation::eraseIfRedundant(MachineInstr &Copy,
606 MCRegister Dst, MCRegister Src) {
607 if (isNeverRedundant(Copy) || isNeverRedundant(Src) || isNeverRedundant(Dst))
611 MachineInstr *PrevCopy =
612 Tracker.findAvailCopy(Copy, Dst, *
TRI, *
TII, UseCopyInstr);
616 DestSourcePair PrevCopyOperands = *isCopyInstr(*PrevCopy, *
TII, UseCopyInstr);
627 DestSourcePair CopyOperands = *isCopyInstr(Copy, *
TII, UseCopyInstr);
629 MCRegister CopyDst = getDstMCReg(CopyOperands);
630 assert(CopyDst == Src || CopyDst == Dst);
631 for (MachineInstr &
MI :
633 MI.clearRegisterKills(CopyDst,
TRI);
641 Copy.eraseFromParent();
647bool MachineCopyPropagation::isBackwardPropagatableRegClassCopy(
648 const MachineInstr &Copy,
const MachineInstr &UseI,
unsigned UseIdx) {
649 DestSourcePair CopyOperands = *isCopyInstr(Copy, *
TII, UseCopyInstr);
650 MCRegister Dst = getDstMCReg(CopyOperands);
652 if (
const TargetRegisterClass *URC =
654 return URC->contains(Dst);
661bool MachineCopyPropagation::isBackwardPropagatableCopy(
662 const MachineInstr &Copy,
const DestSourcePair &CopyOperands) {
663 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
668 if (isNeverRedundant(Copy) || isNeverRedundant(Dst) || isNeverRedundant(Src))
677bool MachineCopyPropagation::isForwardableRegClassCopy(
const MachineInstr &Copy,
678 const MachineInstr &UseI,
680 DestSourcePair CopyOperands = *isCopyInstr(Copy, *
TII, UseCopyInstr);
681 MCRegister CopySrc = getSrcMCReg(CopyOperands);
685 if (
const TargetRegisterClass *URC =
687 return URC->contains(CopySrc);
689 std::optional<DestSourcePair> UseICopyOperands =
690 isCopyInstr(UseI, *
TII, UseCopyInstr);
691 if (!UseICopyOperands)
714 MCRegister UseDst = getDstMCReg(*UseICopyOperands);
716 bool IsCrossClass =
false;
717 for (
const TargetRegisterClass *RC :
TRI->regclasses()) {
718 if (RC->contains(CopySrc) && RC->contains(UseDst)) {
720 if (
TRI->getCrossCopyRegClass(RC) != RC) {
732 MCRegister CopyDst = getDstMCReg(CopyOperands);
733 for (
const TargetRegisterClass *RC :
TRI->regclasses()) {
734 if (RC->contains(CopySrc) && RC->contains(CopyDst) &&
735 TRI->getCrossCopyRegClass(RC) != RC)
749bool MachineCopyPropagation::hasImplicitOverlap(
const MachineInstr &
MI,
750 const MachineOperand &Use) {
751 for (
const MachineOperand &MIUse :
MI.uses())
752 if (&MIUse != &Use && MIUse.isReg() && MIUse.isImplicit() &&
753 MIUse.isUse() &&
TRI->regsOverlap(
Use.getReg(), MIUse.getReg()))
763bool MachineCopyPropagation::hasOverlappingMultipleDef(
764 const MachineInstr &
MI,
const MachineOperand &MODef, MCRegister Def) {
765 for (
const MachineOperand &MIDef :
MI.all_defs()) {
766 if ((&MIDef != &MODef) && MIDef.isReg() &&
767 TRI->regsOverlap(Def, MIDef.getReg()))
776bool MachineCopyPropagation::canUpdateSrcUsers(
const MachineInstr &Copy,
777 const MachineOperand &CopySrc) {
778 assert(CopySrc.
isReg() &&
"Expected a register operand");
779 for (
auto *SrcUser : Tracker.getSrcUsers(CopySrc.
getReg(), *
TRI)) {
780 if (hasImplicitOverlap(*SrcUser, CopySrc))
783 for (MachineOperand &MO : SrcUser->uses()) {
784 if (!MO.isReg() || !MO.isUse() || MO.getReg() != CopySrc.
getReg())
786 if (MO.isTied() || !MO.isRenamable() ||
787 !isBackwardPropagatableRegClassCopy(Copy, *SrcUser,
797void MachineCopyPropagation::forwardUses(MachineInstr &
MI) {
798 if (!Tracker.hasAnyCopies())
804 for (
unsigned OpIdx = 0, OpEnd =
MI.getNumOperands();
OpIdx < OpEnd;
806 MachineOperand &MOUse =
MI.getOperand(
OpIdx);
826 *
TRI, *
TII, UseCopyInstr);
830 DestSourcePair CopyOperands = *isCopyInstr(*Copy, *
TII, UseCopyInstr);
831 auto [CopyDst, CopySrc] = getDstSrcMCRegs(CopyOperands);
832 const MachineOperand &CopySrcOperand = *CopyOperands.
Source;
834 MCRegister ForwardedReg = CopySrc;
837 if (MOUse.
getReg() != CopyDst) {
838 unsigned SubRegIdx =
TRI->getSubRegIndex(CopyDst, MOUse.
getReg());
840 "MI source is not a sub-register of Copy destination");
841 ForwardedReg =
TRI->getSubReg(CopySrc, SubRegIdx);
842 if (!ForwardedReg ||
TRI->isArtificial(ForwardedReg)) {
843 LLVM_DEBUG(
dbgs() <<
"MCP: Copy source does not have sub-register "
844 <<
TRI->getSubRegIndexName(SubRegIdx) <<
'\n');
853 if (!isForwardableRegClassCopy(*Copy,
MI,
OpIdx))
856 if (hasImplicitOverlap(
MI, MOUse))
862 if (isCopyInstr(
MI, *
TII, UseCopyInstr) &&
863 MI.modifiesRegister(CopySrc,
TRI) &&
864 !
MI.definesRegister(CopySrc,
nullptr)) {
870 LLVM_DEBUG(
dbgs() <<
"MCP: Skipping forwarding due to debug counter:\n "
877 <<
"\n in " <<
MI <<
" from " << *Copy);
879 MOUse.
setReg(ForwardedReg);
888 for (MachineInstr &KMI :
890 KMI.clearRegisterKills(CopySrc,
TRI);
897void MachineCopyPropagation::forwardCopyPropagateBlock(MachineBasicBlock &
MBB) {
903 std::optional<DestSourcePair> CopyOperands =
904 isCopyInstr(
MI, *
TII, UseCopyInstr);
906 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
907 if (!
TRI->regsOverlap(Dst, Src)) {
923 if (eraseIfRedundant(
MI, Dst, Src) || eraseIfRedundant(
MI, Src, Dst))
929 for (
const MachineOperand &MO :
MI.operands())
930 if (MO.isReg() && MO.isEarlyClobber()) {
937 Tracker.clobberRegister(
Reg, *
TRI, *
TII, UseCopyInstr);
944 if (
TII->simplifyInstruction(
MI)) {
949 CopyOperands = isCopyInstr(
MI, *
TII, UseCopyInstr);
951 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
952 if (!
TRI->regsOverlap(Dst, Src)) {
955 if (!isNeverRedundant(
MI) && !isNeverRedundant(Dst))
956 MaybeDeadCopies.insert(&
MI);
961 const MachineOperand *RegMask =
nullptr;
962 for (
const MachineOperand &MO :
MI.operands()) {
972 "MachineCopyPropagation should be run after register allocation!");
974 if (MO.isDef() && !MO.isEarlyClobber()) {
980 }
else if (MO.readsReg()) {
989 BitVector &PreservedRegUnits =
990 Tracker.getPreservedRegUnits(*RegMask, *
TRI);
993 for (SmallSetVector<MachineInstr *, 8>::iterator DI =
994 MaybeDeadCopies.begin();
995 DI != MaybeDeadCopies.end();) {
996 MachineInstr *MaybeDead = *DI;
997 std::optional<DestSourcePair> CopyOperands =
998 isCopyInstr(*MaybeDead, *
TII, UseCopyInstr);
999 MCRegister
Reg = CopyOperands->Destination->getReg().asMCReg();
1000 assert(!isNeverRedundant(*MaybeDead) && !isNeverRedundant(
Reg));
1009 bool MIRefedinCopyInfo =
false;
1010 for (MCRegUnit RegUnit :
TRI->regunits(
Reg)) {
1011 if (!PreservedRegUnits.
test(
static_cast<unsigned>(RegUnit)))
1012 Tracker.clobberRegUnit(RegUnit, *
TRI, *
TII, UseCopyInstr);
1014 if (MaybeDead == Tracker.findCopyForUnit(RegUnit, *
TRI)) {
1015 MIRefedinCopyInfo =
true;
1022 DI = MaybeDeadCopies.erase(DI);
1025 if (MIRefedinCopyInfo)
1028 LLVM_DEBUG(
dbgs() <<
"MCP: Removing copy due to regmask clobbering: "
1038 for (MCRegister
Reg : Defs)
1039 Tracker.clobberRegister(
Reg, *
TRI, *
TII, UseCopyInstr);
1042 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
1043 if (!
TRI->regsOverlap(Dst, Src)) {
1044 Tracker.trackCopy(&
MI, *
TRI, *
TII, UseCopyInstr);
1054 readSuccessorLiveIns(
MBB);
1060 for (MachineInstr *MaybeDead : MaybeDeadCopies) {
1061 LLVM_DEBUG(
dbgs() <<
"MCP: Removing copy due to no live-out succ: ";
1064 DestSourcePair CopyOperands =
1065 *isCopyInstr(*MaybeDead, *
TII, UseCopyInstr);
1067 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
1068 assert(!isNeverRedundant(*MaybeDead) && !isNeverRedundant(Dst));
1071 const auto &DbgUsers = CopyDbgUsers[MaybeDead];
1082 MaybeDeadCopies.clear();
1083 CopyDbgUsers.clear();
1087void MachineCopyPropagation::propagateDefs(MachineInstr &
MI) {
1088 if (!Tracker.hasAnyCopies())
1091 for (
unsigned OpIdx = 0, OpEnd =
MI.getNumOperands();
OpIdx != OpEnd;
1093 MachineOperand &MODef =
MI.getOperand(
OpIdx);
1109 MachineInstr *
Copy = Tracker.findAvailBackwardCopy(
1114 DestSourcePair CopyOperands = *isCopyInstr(*Copy, *
TII, UseCopyInstr);
1115 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
1117 if (MODef.
getReg() != Src)
1120 if (!isBackwardPropagatableRegClassCopy(*Copy,
MI,
OpIdx))
1123 if (hasImplicitOverlap(
MI, MODef))
1126 if (hasOverlappingMultipleDef(
MI, MODef, Dst))
1129 if (!canUpdateSrcUsers(*Copy, *CopyOperands.
Source))
1134 <<
MI <<
" from " << *Copy);
1139 for (
auto *SrcUser : Tracker.getSrcUsers(Src, *
TRI)) {
1140 for (MachineOperand &MO : SrcUser->uses()) {
1141 if (!MO.isReg() || !MO.isUse() || MO.getReg() != Src)
1149 MaybeDeadCopies.insert(Copy);
1151 ++NumCopyBackwardPropagated;
1155void MachineCopyPropagation::backwardCopyPropagateBlock(
1156 MachineBasicBlock &
MBB) {
1162 std::optional<DestSourcePair> CopyOperands =
1163 isCopyInstr(
MI, *
TII, UseCopyInstr);
1164 if (CopyOperands &&
MI.getNumImplicitOperands() == 0) {
1165 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
1167 if (!
TRI->regsOverlap(Dst, Src)) {
1170 if (isBackwardPropagatableCopy(
MI, *CopyOperands)) {
1171 Tracker.invalidateRegister(Src, *
TRI, *
TII, UseCopyInstr);
1172 Tracker.invalidateRegister(Dst, *
TRI, *
TII, UseCopyInstr);
1173 Tracker.trackCopy(&
MI, *
TRI, *
TII, UseCopyInstr);
1180 for (
const MachineOperand &MO :
MI.operands())
1181 if (MO.isReg() && MO.isEarlyClobber()) {
1185 Tracker.invalidateRegister(
Reg, *
TRI, *
TII, UseCopyInstr);
1189 for (
const MachineOperand &MO :
MI.operands()) {
1197 Tracker.invalidateRegister(MO.getReg().asMCReg(), *
TRI, *
TII,
1200 if (MO.readsReg()) {
1205 for (MCRegUnit Unit :
TRI->regunits(MO.getReg().asMCReg())) {
1206 if (
auto *Copy = Tracker.findCopyDefViaUnit(Unit, *
TRI)) {
1207 CopyDbgUsers[
Copy].insert(&
MI);
1210 }
else if (!Tracker.trackSrcUsers(MO.getReg().asMCReg(),
MI, *
TRI, *
TII,
1213 Tracker.invalidateRegister(MO.getReg().asMCReg(), *
TRI, *
TII,
1220 for (
auto *Copy : MaybeDeadCopies) {
1221 DestSourcePair CopyOperands = *isCopyInstr(*Copy, *
TII, UseCopyInstr);
1222 auto [Dst, Src] = getDstSrcMCRegs(CopyOperands);
1223 const auto &DbgUsers = CopyDbgUsers[
Copy];
1228 Copy->eraseFromParent();
1232 MaybeDeadCopies.clear();
1233 CopyDbgUsers.clear();
1241 auto &SC = SpillChain[Leader];
1242 auto &RC = ReloadChain[Leader];
1243 for (
auto I = SC.rbegin(),
E = SC.rend();
I !=
E; ++
I)
1287void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &
MBB) {
1290 DenseMap<MachineInstr *, MachineInstr *> ChainLeader;
1295 DenseMap<MachineInstr *, SmallVector<MachineInstr *>> SpillChain, ReloadChain;
1298 DenseSet<const MachineInstr *> CopySourceInvalid;
1300 auto TryFoldSpillageCopies =
1301 [&,
this](
const SmallVectorImpl<MachineInstr *> &SC,
1302 const SmallVectorImpl<MachineInstr *> &RC) {
1303 assert(SC.
size() == RC.size() &&
"Spill-reload should be paired");
1318 for (
const MachineInstr *Spill :
drop_begin(SC))
1319 if (CopySourceInvalid.
count(Spill))
1322 for (
const MachineInstr *Reload :
drop_end(RC))
1323 if (CopySourceInvalid.
count(Reload))
1327 for (
const TargetRegisterClass *RC :
TRI->regclasses()) {
1328 if (RC->contains(Dst) && RC->contains(Src))
1334 auto UpdateReg = [](MachineInstr *
MI,
const MachineOperand *Old,
1335 const MachineOperand *
New) {
1336 for (MachineOperand &MO :
MI->operands()) {
1338 MO.setReg(
New->getReg());
1342 DestSourcePair InnerMostSpillCopy =
1343 *isCopyInstr(*SC[0], *
TII, UseCopyInstr);
1344 DestSourcePair OuterMostSpillCopy =
1345 *isCopyInstr(*SC.
back(), *
TII, UseCopyInstr);
1346 DestSourcePair InnerMostReloadCopy =
1347 *isCopyInstr(*RC[0], *
TII, UseCopyInstr);
1348 DestSourcePair OuterMostReloadCopy =
1349 *isCopyInstr(*RC.back(), *
TII, UseCopyInstr);
1350 if (!CheckCopyConstraint(getSrcMCReg(OuterMostSpillCopy),
1351 getSrcMCReg(InnerMostSpillCopy)) ||
1352 !CheckCopyConstraint(getDstMCReg(InnerMostReloadCopy),
1353 getDstMCReg(OuterMostReloadCopy)))
1356 SpillageChainsLength += SC.
size() + RC.size();
1357 NumSpillageChains += 1;
1359 OuterMostSpillCopy.
Source);
1360 UpdateReg(RC[0], InnerMostReloadCopy.
Source,
1363 for (
size_t I = 1;
I < SC.
size() - 1; ++
I) {
1364 SC[
I]->eraseFromParent();
1365 RC[
I]->eraseFromParent();
1370 auto IsFoldableCopy = [
this](
const MachineInstr &MaybeCopy) {
1371 if (MaybeCopy.getNumImplicitOperands() > 0)
1373 std::optional<DestSourcePair> CopyOperands =
1374 isCopyInstr(MaybeCopy, *
TII, UseCopyInstr);
1377 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
1378 return Src && Dst && !
TRI->regsOverlap(Src, Dst) &&
1379 CopyOperands->Source->isRenamable() &&
1380 CopyOperands->Destination->isRenamable();
1383 auto IsSpillReloadPair = [&,
this](
const MachineInstr &
Spill,
1384 const MachineInstr &Reload) {
1385 if (!IsFoldableCopy(Spill) || !IsFoldableCopy(Reload))
1387 std::optional<DestSourcePair> SpillCopy =
1388 isCopyInstr(Spill, *
TII, UseCopyInstr);
1389 std::optional<DestSourcePair> ReloadCopy =
1390 isCopyInstr(Reload, *
TII, UseCopyInstr);
1391 if (!SpillCopy || !ReloadCopy)
1393 return getSrcMCReg(*SpillCopy) == getDstMCReg(*ReloadCopy) &&
1394 getDstMCReg(*SpillCopy) == getSrcMCReg(*ReloadCopy);
1397 auto IsChainedCopy = [&,
this](
const MachineInstr &Prev,
1398 const MachineInstr &Current) {
1399 if (!IsFoldableCopy(Prev) || !IsFoldableCopy(Current))
1401 std::optional<DestSourcePair> PrevCopy =
1402 isCopyInstr(Prev, *
TII, UseCopyInstr);
1403 std::optional<DestSourcePair> CurrentCopy =
1404 isCopyInstr(Current, *
TII, UseCopyInstr);
1405 if (!PrevCopy || !CurrentCopy)
1407 return getSrcMCReg(*PrevCopy) == getDstMCReg(*CurrentCopy);
1411 std::optional<DestSourcePair> CopyOperands =
1412 isCopyInstr(
MI, *
TII, UseCopyInstr);
1415 SmallSet<Register, 8> RegsToClobber;
1416 if (!CopyOperands) {
1417 for (
const MachineOperand &MO :
MI.operands()) {
1423 MachineInstr *LastUseCopy =
1430 CopySourceInvalid.
insert(LastUseCopy);
1444 Tracker.clobberRegister(
Reg, *
TRI, *
TII, UseCopyInstr);
1451 auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
1453 LLVM_DEBUG(
dbgs() <<
"MCP: Searching paired spill for reload: ");
1455 MachineInstr *MaybeSpill =
1456 Tracker.findLastSeenDefInCopy(
MI, Src, *
TRI, *
TII, UseCopyInstr);
1457 bool MaybeSpillIsChained = ChainLeader.
count(MaybeSpill);
1458 if (!MaybeSpillIsChained && MaybeSpill &&
1459 IsSpillReloadPair(*MaybeSpill,
MI)) {
1494 MachineInstr *MaybePrevReload = Tracker.findLastSeenUseInCopy(Dst, *
TRI);
1495 auto Leader = ChainLeader.
find(MaybePrevReload);
1496 MachineInstr *
L =
nullptr;
1497 if (Leader == ChainLeader.
end() ||
1498 (MaybePrevReload && !IsChainedCopy(*MaybePrevReload,
MI))) {
1501 "SpillChain should not have contained newly found chain");
1503 assert(MaybePrevReload &&
1504 "Found a valid leader through nullptr should not happend");
1507 "Existing chain's length should be larger than zero");
1510 "Newly found paired spill-reload should not belong to any chain "
1512 ChainLeader.
insert({MaybeSpill,
L});
1514 SpillChain[
L].push_back(MaybeSpill);
1515 ReloadChain[
L].push_back(&
MI);
1518 }
else if (MaybeSpill && !MaybeSpillIsChained) {
1535 Tracker.clobberRegister(Src, *
TRI, *
TII, UseCopyInstr);
1539 Tracker.trackCopy(&
MI, *
TRI, *
TII, UseCopyInstr);
1542 for (
auto I = SpillChain.
begin(),
E = SpillChain.
end();
I !=
E; ++
I) {
1543 auto &SC =
I->second;
1545 "Reload chain of the same leader should exist");
1546 auto &RC = ReloadChain[
I->first];
1547 TryFoldSpillageCopies(SC, RC);
1550 MaybeDeadCopies.clear();
1551 CopyDbgUsers.clear();
1555bool MachineCopyPropagationLegacy::runOnMachineFunction(MachineFunction &MF) {
1559 return MachineCopyPropagation(UseCopyInstr).run(MF);
1566 if (!MachineCopyPropagation(UseCopyInstr).
run(MF))
1574 bool IsSpillageCopyElimEnabled =
false;
1577 IsSpillageCopyElimEnabled =
1581 IsSpillageCopyElimEnabled =
true;
1584 IsSpillageCopyElimEnabled =
false;
1595 if (IsSpillageCopyElimEnabled)
1596 eliminateSpillageCopies(
MBB);
1597 backwardCopyPropagateBlock(
MBB);
1598 forwardCopyPropagateBlock(
MBB);
1604MachineFunctionPass *
1606 return new MachineCopyPropagationLegacy(UseCopyInstr);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines the DenseMap class.
const HexagonInstrInfo * TII
static cl::opt< cl::boolOrDefault > EnableSpillageCopyElimination("enable-spill-copy-elim", cl::Hidden)
static void printSpillReloadChain(DenseMap< MachineInstr *, SmallVector< MachineInstr * > > &SpillChain, DenseMap< MachineInstr *, SmallVector< MachineInstr * > > &ReloadChain, MachineInstr *Leader)
static bool isNopCopy(const MachineInstr &PreviousCopy, MCRegister Src, MCRegister Dst, const TargetRegisterInfo *TRI, const TargetInstrInfo *TII, bool UseCopyInstr)
Return true if PreviousCopy did copy register Src to register Dst.
static cl::opt< bool > MCPUseCopyInstr("mcp-use-is-copy-instr", cl::init(false), cl::Hidden)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallSet class.
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)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
bool test(unsigned Idx) const
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Represents analyses that only rely on functions' control flow.
static bool shouldExecute(CounterInfo &Counter)
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Wrapper class representing physical registers. Should be passed by value.
An RAII based helper class to modify MachineFunctionProperties when running pass.
iterator_range< succ_iterator > successors()
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
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.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI const TargetRegisterClass * getRegClassConstraint(unsigned OpIdx, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI) const
Compute the static register class constraint for operand OpIdx.
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
LLVM_ABI void setIsRenamable(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.
LLVM_ABI bool isRenamable() const
isRenamable - Returns true if this register may be renamed, i.e.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static bool clobbersPhysReg(const uint32_t *RegMask, MCRegister PhysReg)
clobbersPhysReg - Returns true if this RegMask clobbers PhysReg.
const uint32_t * getRegMask() const
getRegMask - Returns a bit mask of registers preserved by this RegMask operand.
bool tracksLiveness() const
tracksLiveness - Returns true when tracking register liveness accurately.
bool isReserved(MCRegister PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.
LLVM_ABI bool isConstantPhysReg(MCRegister PhysReg) const
Returns true if PhysReg is unallocatable and constant throughout the function.
void updateDbgUsersToReg(MCRegister OldReg, MCRegister NewReg, ArrayRef< MachineInstr * > Users) const
updateDbgUsersToReg - Update a collection of debug instructions to refer to the designated register.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
void insert_range(Range &&R)
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual bool enableSpillageCopyElimination() const
Enable spillage copy elimination in MachineCopyPropagation pass.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
reverse_self_iterator getReverseIterator()
self_iterator getIterator()
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
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.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
Value * readRegister(IRBuilder<> &IRB, StringRef Name)
NodeAddr< UseNode * > Use
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI MachineFunctionPass * createMachineCopyPropagationPass(bool UseCopyInstr)
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.
LLVM_ABI char & MachineCopyPropagationID
MachineCopyPropagation - This pass performs copy propagation on machine instructions.
const MachineOperand * Source
const MachineOperand * Destination