From: Jakob Stoklund Olesen Date: Wed, 20 Oct 2010 22:00:51 +0000 (+0000) Subject: Move some of the InlineSpiller rematerialization code into LiveRangeEdit. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=080c316ff8a066cd164d9a8f92df509d8cb63110;p=oota-llvm.git Move some of the InlineSpiller rematerialization code into LiveRangeEdit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116951 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp index 94a40c4b3e7..81b30a48917 100644 --- a/lib/CodeGen/InlineSpiller.cpp +++ b/lib/CodeGen/InlineSpiller.cpp @@ -49,10 +49,7 @@ class InlineSpiller : public Spiller { const TargetRegisterClass *rc_; int stackSlot_; - // Values of the current interval that can potentially remat. - SmallPtrSet reMattable_; - - // Values in reMattable_ that failed to remat at some point. + // Values that failed to remat at some point. SmallPtrSet usedValues_; ~InlineSpiller() {} @@ -136,6 +133,7 @@ bool InlineSpiller::split() { bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { SlotIndex UseIdx = lis_.getInstructionIndex(MI).getUseIndex(); VNInfo *OrigVNI = edit_->getParent().getVNInfoAt(UseIdx); + if (!OrigVNI) { DEBUG(dbgs() << "\tadding flags: "); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { @@ -146,20 +144,17 @@ bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { DEBUG(dbgs() << UseIdx << '\t' << *MI); return true; } - if (!reMattable_.count(OrigVNI)) { - DEBUG(dbgs() << "\tusing non-remat valno " << OrigVNI->id << ": " - << UseIdx << '\t' << *MI); - return false; - } - MachineInstr *OrigMI = lis_.getInstructionFromIndex(OrigVNI->def); - if (!edit_->allUsesAvailableAt(OrigMI, OrigVNI->def, UseIdx, lis_)) { + + LiveRangeEdit::Remat RM = edit_->canRematerializeAt(OrigVNI, UseIdx, false, + lis_); + if (!RM) { usedValues_.insert(OrigVNI); DEBUG(dbgs() << "\tcannot remat for " << UseIdx << '\t' << *MI); return false; } - // If the instruction also writes edit_->getReg(), it had better not require the same - // register for uses and defs. + // If the instruction also writes edit_->getReg(), it had better not require + // the same register for uses and defs. bool Reads, Writes; SmallVector Ops; tie(Reads, Writes) = MI->readsWritesVirtualRegister(edit_->getReg(), &Ops); @@ -179,11 +174,9 @@ bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { NewLI.markNotSpillable(); // Finally we can rematerialize OrigMI before MI. - MachineBasicBlock &MBB = *MI->getParent(); - tii_.reMaterialize(MBB, MI, NewLI.reg, 0, OrigMI, tri_); - MachineBasicBlock::iterator RematMI = MI; - SlotIndex DefIdx = lis_.InsertMachineInstrInMaps(--RematMI).getDefIndex(); - DEBUG(dbgs() << "\tremat: " << DefIdx << '\t' << *RematMI); + SlotIndex DefIdx = edit_->rematerializeAt(*MI->getParent(), MI, NewLI.reg, RM, + lis_, tii_, tri_); + DEBUG(dbgs() << "\tremat: " << DefIdx << '\n'); // Replace operands for (unsigned i = 0, e = Ops.size(); i != e; ++i) { @@ -205,23 +198,11 @@ bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { /// and trim the live ranges after. void InlineSpiller::reMaterializeAll() { // Do a quick scan of the interval values to find if any are remattable. - reMattable_.clear(); - usedValues_.clear(); - for (LiveInterval::const_vni_iterator I = edit_->getParent().vni_begin(), - E = edit_->getParent().vni_end(); I != E; ++I) { - VNInfo *VNI = *I; - if (VNI->isUnused()) - continue; - MachineInstr *DefMI = lis_.getInstructionFromIndex(VNI->def); - if (!DefMI || !tii_.isTriviallyReMaterializable(DefMI)) - continue; - reMattable_.insert(VNI); - } - - // Often, no defs are remattable. - if (reMattable_.empty()) + if (!edit_->anyRematerializable(lis_, tii_, 0)) return; + usedValues_.clear(); + // Try to remat before all uses of edit_->getReg(). bool anyRemat = false; for (MachineRegisterInfo::use_nodbg_iterator @@ -234,10 +215,11 @@ void InlineSpiller::reMaterializeAll() { // Remove any values that were completely rematted. bool anyRemoved = false; - for (SmallPtrSet::iterator I = reMattable_.begin(), - E = reMattable_.end(); I != E; ++I) { + for (LiveInterval::vni_iterator I = edit_->getParent().vni_begin(), + E = edit_->getParent().vni_end(); I != E; ++I) { VNInfo *VNI = *I; - if (VNI->hasPHIKill() || usedValues_.count(VNI)) + if (VNI->hasPHIKill() || !edit_->didRematerialize(VNI) || + usedValues_.count(VNI)) continue; MachineInstr *DefMI = lis_.getInstructionFromIndex(VNI->def); DEBUG(dbgs() << "\tremoving dead def: " << VNI->def << '\t' << *DefMI); diff --git a/lib/CodeGen/LiveRangeEdit.cpp b/lib/CodeGen/LiveRangeEdit.cpp index 463ebcb4ae5..cc9c3a3c2f3 100644 --- a/lib/CodeGen/LiveRangeEdit.cpp +++ b/lib/CodeGen/LiveRangeEdit.cpp @@ -15,6 +15,7 @@ #include "VirtRegMap.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" using namespace llvm; @@ -38,6 +39,31 @@ LiveInterval &LiveRangeEdit::create(MachineRegisterInfo &mri, return li; } +void LiveRangeEdit::scanRemattable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa) { + for (LiveInterval::vni_iterator I = parent_.vni_begin(), + E = parent_.vni_end(); I != E; ++I) { + VNInfo *VNI = *I; + if (VNI->isUnused()) + continue; + MachineInstr *DefMI = lis.getInstructionFromIndex(VNI->def); + if (!DefMI) + continue; + if (tii.isTriviallyReMaterializable(DefMI, aa)) + remattable_.insert(VNI); + } + scannedRemattable_ = true; +} + +bool LiveRangeEdit::anyRematerializable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa) { + if (!scannedRemattable_) + scanRemattable(lis, tii, aa); + return !remattable_.empty(); +} + /// allUsesAvailableAt - Return true if all registers used by OrigMI at /// OrigIdx are also available with the same value at UseIdx. bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI, @@ -71,3 +97,47 @@ bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI, return true; } +LiveRangeEdit::Remat LiveRangeEdit::canRematerializeAt(VNInfo *ParentVNI, + SlotIndex UseIdx, + bool cheapAsAMove, + LiveIntervals &lis) { + assert(scannedRemattable_ && "Call anyRematerializable first"); + Remat RM = { 0, 0 }; + + // We could remat an undefined value as IMPLICIT_DEF, but all that should have + // been taken care of earlier. + if (!(RM.ParentVNI = parent_.getVNInfoAt(UseIdx))) + return RM; + + // Use scanRemattable info. + if (!remattable_.count(RM.ParentVNI)) + return RM; + + // No defining instruction. + MachineInstr *OrigMI = lis.getInstructionFromIndex(RM.ParentVNI->def); + assert(OrigMI && "Defining instruction for remattable value disappeared"); + + // If only cheap remats were requested, bail out early. + if (cheapAsAMove && !OrigMI->getDesc().isAsCheapAsAMove()) + return RM; + + // Verify that all used registers are available with the same values. + if (!allUsesAvailableAt(OrigMI, RM.ParentVNI->def, UseIdx, lis)) + return RM; + + RM.OrigMI = OrigMI; + return RM; +} + +SlotIndex LiveRangeEdit::rematerializeAt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, + const Remat &RM, + LiveIntervals &lis, + const TargetInstrInfo &tii, + const TargetRegisterInfo &tri) { + assert(RM.OrigMI && "Invalid remat"); + tii.reMaterialize(MBB, MI, DestReg, 0, RM.OrigMI, tri); + return lis.InsertMachineInstrInMaps(--MI).getDefIndex(); +} + diff --git a/lib/CodeGen/LiveRangeEdit.h b/lib/CodeGen/LiveRangeEdit.h index d9d9c613e1f..d6ba256aee4 100644 --- a/lib/CodeGen/LiveRangeEdit.h +++ b/lib/CodeGen/LiveRangeEdit.h @@ -19,9 +19,11 @@ #define LLVM_CODEGEN_LIVERANGEEDIT_H #include "llvm/CodeGen/LiveInterval.h" +#include "llvm/ADT/SmallPtrSet.h" namespace llvm { +class AliasAnalysis; class LiveIntervals; class MachineRegisterInfo; class VirtRegMap; @@ -34,6 +36,27 @@ class LiveRangeEdit { /// firstNew_ - Index of the first register added to newRegs_. const unsigned firstNew_; + /// scannedRemattable_ - true when remattable values have been identified. + bool scannedRemattable_; + + /// remattable_ - Values defined by remattable instructions as identified by + /// tii.isTriviallyReMaterializable(). + SmallPtrSet remattable_; + + /// rematted_ - Values that were actually rematted, and so need to have their + /// live range trimmed or entirely removed. + SmallPtrSet rematted_; + + /// scanRemattable - Identify the parent_ values that may rematerialize. + void scanRemattable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa); + + /// allUsesAvailableAt - Return true if all registers used by OrigMI at + /// OrigIdx are also available with the same value at UseIdx. + bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, + SlotIndex UseIdx, LiveIntervals &lis); + public: /// Create a LiveRangeEdit for breaking down parent into smaller pieces. /// @param parent The register being spilled or split. @@ -45,7 +68,7 @@ public: SmallVectorImpl &newRegs, const SmallVectorImpl &uselessRegs) : parent_(parent), newRegs_(newRegs), uselessRegs_(uselessRegs), - firstNew_(newRegs.size()) {} + firstNew_(newRegs.size()), scannedRemattable_(false) {} LiveInterval &getParent() const { return parent_; } unsigned getReg() const { return parent_.reg; } @@ -63,11 +86,43 @@ public: /// parent. LiveInterval &create(MachineRegisterInfo&, LiveIntervals&, VirtRegMap&); - /// allUsesAvailableAt - Return true if all registers used by OrigMI at - /// OrigIdx are also available with the same value at UseIdx. - bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, - SlotIndex UseIdx, LiveIntervals &lis); + /// anyRematerializable - Return true if any parent values may be + /// rematerializable. + /// This function must be called before ny rematerialization is attempted. + bool anyRematerializable(LiveIntervals&, const TargetInstrInfo&, + AliasAnalysis*); + + /// Remat - Information needed to rematerialize at a specific location. + struct Remat { + VNInfo *ParentVNI; // parent_'s value at the remat location. + MachineInstr *OrigMI; // Instruction defining ParentVNI. + operator bool() const { return OrigMI; } + }; + + /// canRematerializeAt - Determine if ParentVNI can be rematerialized at + /// UseIdx. It is assumed that parent_.getVNINfoAt(UseIdx) == ParentVNI. + /// When cheapAsAMove is set, only cheap remats are allowed. + Remat canRematerializeAt(VNInfo *ParentVNI, + SlotIndex UseIdx, + bool cheapAsAMove, + LiveIntervals &lis); + + /// rematerializeAt - Rematerialize RM.ParentVNI into DestReg by inserting an + /// instruction into MBB before MI. The new instruction is mapped, but + /// liveness is not updated. + /// Return the SlotIndex of the new instruction. + SlotIndex rematerializeAt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, + const Remat &RM, + LiveIntervals&, + const TargetInstrInfo&, + const TargetRegisterInfo&); + /// didRematerialize - Return true if ParentVNI was rematerialized anywhere. + bool didRematerialize(VNInfo *ParentVNI) const { + return rematted_.count(ParentVNI); + } }; }