28#define DEBUG_TYPE "rematerializer"
44 if ((SR.LaneMask & Mask).none())
46 if (!SR.liveAt(UseIdx))
64 if (
Reg.isPhysical()) {
95 RematOrder.
insert(RootIdx);
103 if (RematOrder.
contains(Dep.RegIdx))
106 RematOrder.
insert(Dep.RegIdx);
108 }
while (!DepDAG.
empty());
118 LastNewIdx = rematerializeReg(RegIdx, InsertPos, std::move(Dependencies));
126 auto Remats = Rematerializations.find(RootIdx);
127 if (Remats == Rematerializations.end())
135 for (
RegisterIdx RematRegIdx : Remats->getSecond()) {
136 for (
const auto &[UseRegion, RegionUsers] : Regs[RematRegIdx].
Uses)
139 Rematerializations.erase(RootIdx);
147 "cannot rollback dead register");
150 for (
const auto &[UseRegion, RegionUsers] : Regs[RematIdx].
Uses)
155 if (
getReg(RootIdx).isAlive())
157 assert(Revivable.contains(RootIdx) &&
"not revivable");
163 ReviveOrder.
insert(RootIdx);
175 assert(Revivable.contains(Dep.
RegIdx) &&
"not revivable");
182 LISUpdates.insert(Dep.
RegIdx);
184 }
while (!DepDAG.
empty());
188 Reg &ReviveReg = Regs[RegIdx];
189 assert(Rematerializations.contains(RegIdx) &&
"no remats");
190 RegisterIdx RematIdx = *Rematerializations.at(RegIdx).begin();
192 for (
const auto &[MOIdx,
Reg] : Revivable.at(RegIdx))
194 Revivable.erase(RegIdx);
195 LISUpdates.insert(RegIdx);
198 dbgs() <<
"** Revived " <<
printID(RegIdx) <<
" @ ";
199 LIS.getInstructionIndex(*ReviveReg.
DefMI).print(
dbgs());
207 transferUserImpl(FromRegIdx, ToRegIdx, UserMI);
208 unsigned UserRegion = MIRegion.at(&UserMI);
209 Regs[FromRegIdx].eraseUser(&UserMI, UserRegion);
210 Regs[ToRegIdx].addUser(&UserMI, UserRegion);
211 deleteRegIfUnused(FromRegIdx);
216 unsigned UseRegion) {
217 auto &FromRegUsers = Regs[FromRegIdx].Uses;
218 auto UsesIt = FromRegUsers.find(UseRegion);
219 if (UsesIt == FromRegUsers.end())
224 transferUserImpl(FromRegIdx, ToRegIdx, *UserMI);
225 Regs[ToRegIdx].addUsers(RegionUsers, UseRegion);
226 FromRegUsers.erase(UseRegion);
227 deleteRegIfUnused(FromRegIdx);
230void Rematerializer::transferUserImpl(
RegisterIdx FromRegIdx,
236 assert(FromRegIdx != ToRegIdx &&
"identical registers");
238 "unrelated registers");
245 LISUpdates.insert(FromRegIdx);
246 LISUpdates.insert(ToRegIdx);
252 for (Reg::Dependency &Dep : Regs[UserRegIdx].Dependencies) {
253 if (Dep.RegIdx == FromRegIdx) {
254 Dep.RegIdx = ToRegIdx;
266 assert((UpdateReg.
DefMI || Revivable.contains(RegIdx)) &&
"dead reg");
269 if (LIS.hasInterval(DefReg))
270 LIS.removeInterval(DefReg);
271 LIS.createAndComputeVirtRegInterval(DefReg);
274 dbgs() <<
"Re-computed interval for " <<
printID(RegIdx) <<
": ";
275 LIS.getInterval(DefReg).print(
dbgs());
282 if (!SeenUnrematRegs.
insert(UnrematReg).second)
284 LIS.removeInterval(UnrematReg);
285 LIS.createAndComputeVirtRegInterval(UnrematReg);
287 dbgs() <<
" Re-computed interval for register "
298 for (
auto &[RegIdx,
_] : Revivable)
309 LaneBitmask Mask = SubIdx ? TRI.getSubRegIndexLaneMask(SubIdx)
310 : MRI.getMaxLaneMaskForVReg(
Reg);
325 if (It == Rematerializations.end())
327 const RematsOf &Remats = It->getSecond();
332 const Reg &RematReg =
getReg(RematRegIdx);
337 if (RematRegSlot < Before &&
338 (BestRegIdx ==
NoReg || RematRegSlot > BestSlot)) {
339 BestSlot = RematRegSlot;
340 BestRegIdx = RematRegIdx;
346void Rematerializer::deleteRegIfUnused(
RegisterIdx RootIdx) {
354 DeleteOrder.
insert(RootIdx);
358 for (
const Reg::Dependency &Dep : DeleteReg.Dependencies) {
360 Reg &DepReg = Regs[Dep.RegIdx];
361 DepReg.eraseUser(DeleteReg.DefMI, DeleteReg.DefRegion);
362 if (DepReg.Uses.empty()) {
363 DeleteOrder.
insert(Dep.RegIdx);
367 }
while (!DepDAG.
empty());
370 Reg &DeleteReg = Regs[RegIdx];
371 LIS.removeInterval(DeleteReg.getDefReg());
372 LISUpdates.erase(RegIdx);
374 if (SupportRollback && !IsRematerializedReg) {
379 DenseMap<unsigned, Register> &RegMap =
380 Revivable.try_emplace(RegIdx).first->getSecond();
381 for (
auto [Idx, MO] :
enumerate(DeleteReg.DefMI->operands())) {
382 if (MO.isReg() && MO.readsReg()) {
383 RegMap.
insert({Idx, MO.getReg()});
387 DeleteReg.DefMI->setDesc(TII.get(TargetOpcode::DBG_VALUE));
391 if (IsRematerializedReg) {
393 RematsOf &OriginRemats = Rematerializations.at(
getOriginOf(RegIdx));
394 assert(OriginRemats.contains(RegIdx) &&
"broken remat<->origin link");
395 OriginRemats.erase(RegIdx);
396 if (OriginRemats.empty())
397 Rematerializations.erase(RegIdx);
403void Rematerializer::deleteReg(
RegisterIdx RegIdx) {
404 Reg &DeleteReg = Regs[RegIdx];
405 assert(DeleteReg.DefMI &&
"register was already deleted");
409 if (RegionBegin == DeleteReg.DefMI)
411 LIS.RemoveMachineInstrFromMaps(*DeleteReg.DefMI);
412 DeleteReg.DefMI->eraseFromParent();
413 MIRegion.erase(DeleteReg.DefMI);
414 DeleteReg.DefMI =
nullptr;
420 : Regions(Regions), MRI(MF.getRegInfo()), LIS(LIS),
421 TII(*MF.getSubtarget().getInstrInfo()), TRI(TII.getRegisterInfo()) {
422#ifdef EXPENSIVE_CHECKS
425 for (
const auto &[RegionBegin, RegionEnd] : Regions) {
426 assert(RegionBegin != RegionEnd &&
"empty region");
427 for (
auto MI = RegionBegin;
MI != RegionEnd; ++
MI) {
428 bool IsNewMI = SeenMIs.
insert(&*
MI).second;
429 assert(IsNewMI &&
"overlapping regions");
430 assert(!
MI->isTerminator() &&
"terminator in region");
432 if (RegionEnd != RegionBegin->getParent()->end()) {
433 bool IsNewMI = SeenMIs.
insert(&*RegionEnd).second;
434 assert(IsNewMI &&
"overlapping regions (upper bound)");
442 UnrematableOprds.clear();
444 Rematerializations.clear();
449 this->SupportRollback = SupportRollback;
454 for (
unsigned I = 0, E = Regions.size();
I < E; ++
I) {
458 assert(!MIRegion.contains(&*
MI) &&
"regions should not intersect");
459 MIRegion.insert({&*
MI,
I});
465 assert(!MIRegion.contains(RegionTerm) &&
"regions should not intersect");
466 MIRegion.insert({RegionTerm,
I});
470 const unsigned NumVirtRegs = MRI.getNumVirtRegs();
472 for (
unsigned I = 0, E = NumVirtRegs;
I != E; ++
I) {
474 addRegIfRematerializable(
I, SeenRegs);
476 assert(Regs.size() == UnrematableOprds.size());
482 return !Regs.empty();
485void Rematerializer::addRegIfRematerializable(
unsigned VirtRegIdx,
487 assert(!SeenRegs[VirtRegIdx] &&
"register already seen");
489 SeenRegs.
set(VirtRegIdx);
495 if (!isMIRematerializable(
DefMI))
498 if (DefRegion == MIRegion.
end())
502 RematReg.DefMI = &
DefMI;
503 RematReg.DefRegion = DefRegion->second;
504 unsigned SubIdx =
DefMI.getOperand(0).getSubReg();
505 RematReg.Mask = SubIdx ?
TRI.getSubRegIndexLaneMask(SubIdx)
506 :
MRI.getMaxLaneMaskForVReg(DefReg);
512 if (
auto UseRegion = MIRegion.
find(&
UseMI); UseRegion != MIRegion.
end())
513 RematReg.addUser(&
UseMI, UseRegion->second);
517 if (RematReg.Uses.empty())
524 for (
const auto &[MOIdx, MO] :
enumerate(RematReg.DefMI->operands())) {
526 if (!DepReg || !AllDepRegs.
insert(DepReg).second)
529 if (!SeenRegs[DepRegIdx])
530 addRegIfRematerializable(DepRegIdx, SeenRegs);
531 if (
auto DepIt = RegToIdx.find(DepReg); DepIt != RegToIdx.end())
532 RematReg.Dependencies.push_back(Reg::Dependency(MOIdx, DepIt->second));
538 RegToIdx.
insert({DefReg, Regs.size()});
539 Regs.push_back(RematReg);
540 UnrematableOprds.push_back(UnrematDeps);
543bool Rematerializer::isMIRematerializable(
const MachineInstr &
MI)
const {
544 if (!TII.isReMaterializable(
MI))
547 assert(
MI.getOperand(0).getReg().isVirtual() &&
"should be virtual");
548 assert(MRI.hasOneDef(
MI.getOperand(0).getReg()) &&
"should have single def");
550 for (
const MachineOperand &MO :
MI.all_uses()) {
554 if (MRI.isConstantPhysReg(MO.
getReg()) || TII.isIgnorableUse(MO))
564 if (!
MI.getNumOperands() || !
MI.getOperand(0).isReg() ||
565 MI.getOperand(0).readsReg())
568 auto UserRegIt = RegToIdx.find(
Reg);
569 if (UserRegIt == RegToIdx.end())
571 return UserRegIt->second;
577 unsigned UseRegion = MIRegion.at(&*InsertPos);
580 Reg &NewReg = Regs.emplace_back();
581 Reg &FromReg = Regs[RegIdx];
582 NewReg.Mask = FromReg.Mask;
583 NewReg.DefRegion = UseRegion;
584 NewReg.Dependencies = std::move(Dependencies);
591 Origins.push_back(OriginIdx);
592 Rematerializations[OriginIdx].insert(NewRegIdx);
596 Register NewDefReg = MRI.cloneVirtualRegister(FromReg.getDefReg());
597 TII.reMaterialize(*InsertPos->getParent(), InsertPos, NewDefReg, 0,
599 NewReg.DefMI = &*std::prev(InsertPos);
600 RegToIdx.insert({NewDefReg, NewRegIdx});
605 Bounds.first = NewReg.DefMI;
606 LIS.InsertMachineInstrInMaps(*NewReg.DefMI);
607 MIRegion.emplace_or_assign(NewReg.DefMI, UseRegion);
608 LISUpdates.insert(NewRegIdx);
612 auto ZipedDeps =
zip_equal(FromReg.Dependencies, NewReg.Dependencies);
613 for (
const auto &[OldDep, NewDep] : ZipedDeps) {
614 assert(OldDep.MOIdx == NewDep.MOIdx &&
"operand mismatch");
616 <<
printID(OldDep.RegIdx) <<
" -> "
617 <<
printID(NewDep.RegIdx) <<
'\n');
619 Reg &NewDepReg = Regs[NewDep.RegIdx];
620 if (OldDep.RegIdx != NewDep.RegIdx) {
621 Register OldDefReg = FromReg.DefMI->getOperand(OldDep.MOIdx).getReg();
622 NewReg.DefMI->substituteRegister(OldDefReg, NewDepReg.getDefReg(), 0,
624 LISUpdates.insert(OldDep.RegIdx);
626 NewDepReg.addUser(NewReg.DefMI, UseRegion);
627 LISUpdates.insert(NewDep.RegIdx);
631 dbgs() <<
"** Rematerialized " <<
printID(RegIdx) <<
" as "
637std::pair<MachineInstr *, MachineInstr *>
640 auto It =
Uses.find(UseRegion);
641 if (It ==
Uses.end())
642 return {
nullptr,
nullptr};
648 SlotIndex FirstIndex = LIS.getInstructionIndex(*FirstMI),
649 LastIndex = FirstIndex;
651 while (++
User != UserEnd) {
653 if (UserIndex < FirstIndex) {
654 FirstIndex = UserIndex;
656 }
else if (UserIndex > LastIndex) {
657 LastIndex = UserIndex;
662 return {FirstMI, LastMI};
669void Rematerializer::Reg::addUsers(
const RegionUsers &NewUsers,
678 if (RUsers.size() == 1)
687 std::function<void(
RegisterIdx,
unsigned)> WalkTree =
692 WalkTree(Dep.RegIdx,
Depth + 1);
694 WalkTree(RootIdx, 0);
699 sort(Regs, [](
const auto &LHS,
const auto &RHS) {
700 return LHS.second > RHS.second;
703 OS <<
printID(RootIdx) <<
" has " << Regs.size() - 1 <<
" dependencies\n";
704 for (
const auto &[RegIdx,
Depth] : Regs) {
715 OS <<
'(' << RegIdx <<
'/';
716 if (!PrintReg.
DefMI) {
727 bool SkipRegions)
const {
732 if (!PrintReg.
Uses.empty()) {
733 assert(PrintReg.
DefMI &&
"dead register cannot have uses");
738 for (
const auto [
I, Bounds] :
enumerate(Regions)) {
739 if (Bounds.first == Bounds.second)
741 if (!PrintReg.
Uses.contains(
I) &&
742 LI.
liveAt(LIS.getInstructionIndex(*Bounds.first)) &&
743 LI.
liveAt(LIS.getInstructionIndex(*std::prev(Bounds.second))
745 OS << (
First ?
" - " :
",") <<
I;
749 OS << (
First ?
" --> " :
" -> ");
752 auto It = PrintReg.
Uses.begin();
754 while (++It != PrintReg.
Uses.end())
755 OS <<
"," << It->first;
763 LIS.getInstructionIndex(*PrintReg.
DefMI).print(OS);
782 OS <<
"(-/-)[" << MIRegion.at(
MI) <<
']';
784 MI->print(OS,
true,
false,
787 LIS.getInstructionIndex(*MI).print(
dbgs());
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
iv Induction Variable Users
Register const TargetRegisterInfo * TRI
This file implements a map that provides insertion order iteration.
Promote Memory to Register
Rematerializer::RegisterIdx RegisterIdx
static Register getRegDependency(const MachineOperand &MO)
If MO is a virtual read register, returns it.
static bool isIdenticalAtUse(const VNInfo &OVNI, LaneBitmask Mask, SlotIndex UseIdx, const LiveInterval &LI)
Checks whether the value in LI at UseIdx is identical to OVNI (this implies it is also live there).
MIR-level target-independent rematerialization helpers.
Remove Loads Into Fake Uses
This file implements a set that has insertion order iteration characteristics.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
ValueT & at(const_arg_type_t< KeyT > Val)
at - Return the entry for the specified key, or abort if no such entry exists.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > emplace_or_assign(const KeyT &Key, Ts &&...Args)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
A live range for subregisters.
LiveInterval - This class represents the liveness of a register, or stack slot.
bool hasSubRanges() const
Returns true if subregister liveness information is available.
iterator_range< subrange_iterator > subranges()
bool liveAt(SlotIndex index) const
VNInfo * getVNInfoAt(SlotIndex Idx) const
getVNInfoAt - Return the VNInfo that is live at Idx, or NULL.
MachineInstrBundleIterator< MachineInstr > iterator
Representation of each machine instruction.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI void substituteRegister(Register FromReg, Register ToReg, unsigned SubIdx, const TargetRegisterInfo &RegInfo)
Replace all occurrences of FromReg with ToReg:SubIdx, properly composing subreg indices where necessa...
LLVM_ABI void print(raw_ostream &OS, bool IsStandalone=true, bool SkipOpers=false, bool SkipDebugLoc=false, bool AddNewLine=true, const TargetInstrInfo *TII=nullptr) const
Print this MI to OS.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
bool readsReg() const
readsReg - Returns true if this operand reads the previous value of its register.
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.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
Simple wrapper around std::function<void(raw_ostream&)>.
RegionT * getParent() const
Get the parent of the Region.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
unsigned virtRegIndex() const
Convert a virtual register number to a 0-based index.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Printable printDependencyDAG(RegisterIdx RootIdx) const
RegisterIdx getOriginOrSelf(RegisterIdx RegIdx) const
If RegIdx is a rematerialization, returns its origin's index.
static constexpr unsigned NoReg
Error value for register indices.
Printable printID(RegisterIdx RegIdx) const
void rollbackRematsOf(RegisterIdx RootIdx)
Rolls back all rematerializations of original register RootIdx, transfering all their users back to i...
unsigned getNumRegs() const
RegisterIdx rematerializeToPos(RegisterIdx RootIdx, MachineBasicBlock::iterator InsertPos, DependencyReuseInfo &DRI)
Rematerializes register RootIdx before position InsertPos and returns the new register's index.
void transferUser(RegisterIdx FromRegIdx, RegisterIdx ToRegIdx, MachineInstr &UserMI)
Transfers user UserMI from register FromRegIdx to ToRegIdx, the latter of which must be a remateriali...
RegisterIdx getOriginOf(RegisterIdx RematRegIdx) const
Returns the origin index of rematerializable register RegIdx.
const Reg & getReg(RegisterIdx RegIdx) const
void updateLiveIntervals()
Recomputes all live intervals that have changed as a result of previous rematerializations/rollbacks.
RegisterIdx rematerializeToRegion(RegisterIdx RootIdx, unsigned UseRegion, DependencyReuseInfo &DRI)
Rematerializes register RootIdx just before its first user inside region UseRegion,...
std::pair< MachineBasicBlock::iterator, MachineBasicBlock::iterator > RegionBoundaries
A region's boundaries i.e.
bool analyze(bool SupportRollback)
Goes through the whole MF and identifies all rematerializable registers.
void rollback(RegisterIdx RematIdx)
Rolls back register RematIdx (which must be a rematerialization) transfering all its users back to it...
unsigned RegisterIdx
Index type for rematerializable registers.
void reviveRegIfDead(RegisterIdx RootIdx)
Revives original register RootIdx at its original position in the MIR if it was fully rematerialized ...
bool isMOIdenticalAtUses(MachineOperand &MO, ArrayRef< SlotIndex > Uses) const
Determines whether (sub-)register operand MO has the same value at all Uses as at MO.
void transferRegionUsers(RegisterIdx FromRegIdx, RegisterIdx ToRegIdx, unsigned UseRegion)
Transfers all users of register FromRegIdx in region UseRegion to ToRegIdx, the latter of which must ...
void commitRematerializations()
Deletes unused rematerialized registers that were left in the MIR to support rollback.
Rematerializer(MachineFunction &MF, SmallVectorImpl< RegionBoundaries > &Regions, LiveIntervals &LIS)
Simply initializes some internal state, does not identify rematerialization candidates.
ArrayRef< unsigned > getUnrematableOprds(unsigned RegIdx) const
Returns operand indices corresponding to unrematerializable operands for any register RegIdx.
Printable printUser(const MachineInstr *MI) const
bool isRematerializedRegister(RegisterIdx RegIdx) const
Whether register RegIdx is a rematerialization of some original register.
Printable printRematReg(RegisterIdx RegIdx, bool SkipRegions=false) const
Printable printRegUsers(RegisterIdx RegIdx) const
RegisterIdx findRematInRegion(RegisterIdx RegIdx, unsigned Region, SlotIndex Before) const
Finds the closest rematerialization of register RegIdx in region Region that exists before slot Befor...
bool contains(const_arg_type key) const
Check if the SetVector contains the given key.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SlotIndex - An opaque wrapper around machine indexes.
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
Implements a dense probed hash-table based set with some number of buckets stored inline.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A Use represents the edge between a Value definition and its users.
VNInfo - Value Number Information.
std::pair< iterator, bool > insert(const ValueT &V)
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
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.
When rematerializating a register (called the "root" register in this context) to a given position,...
SmallDenseMap< RegisterIdx, RegisterIdx, 4 > DependencyMap
Keys and values are rematerializable register indices.
A read register operand of DefMI that is rematerializable (according to the rematerializer).
RegisterIdx RegIdx
The corresponding register's index in the rematerializer.
A rematerializable register defined by a single machine instruction.
MachineInstr * DefMI
Single MI defining the rematerializable register.
SmallVector< Dependency, 2 > Dependencies
This register's rematerializable dependencies, one per unique rematerializable register operand.
std::pair< MachineInstr *, MachineInstr * > getRegionUseBounds(unsigned UseRegion, const LiveIntervals &LIS) const
Returns the first and last user of the register in region UseRegion.
unsigned DefRegion
Defining region of DefMI.
SmallDenseMap< unsigned, RegionUsers, 2 > Uses
Uses of the register, mapped by region.
Register getDefReg() const
Returns the rematerializable register from its defining instruction.
SmallDenseSet< MachineInstr *, 4 > RegionUsers