TwoAddressInstructionPass.cpp [plain text]
#define DEBUG_TYPE "twoaddrinstr"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;
STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
STATISTIC(NumCommuted , "Number of instructions commuted to coalesce");
STATISTIC(NumAggrCommuted , "Number of instructions aggressively commuted");
STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address");
STATISTIC(Num3AddrSunk, "Number of 3-address instructions sunk");
STATISTIC(NumReMats, "Number of instructions re-materialized");
STATISTIC(NumDeletes, "Number of dead instructions deleted");
STATISTIC(NumReSchedUps, "Number of instructions re-scheduled up");
STATISTIC(NumReSchedDowns, "Number of instructions re-scheduled down");
namespace {
class TwoAddressInstructionPass : public MachineFunctionPass {
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
const InstrItineraryData *InstrItins;
MachineRegisterInfo *MRI;
LiveVariables *LV;
AliasAnalysis *AA;
CodeGenOpt::Level OptLevel;
DenseMap<MachineInstr*, unsigned> DistanceMap;
DenseMap<unsigned, unsigned> SrcRegMap;
DenseMap<unsigned, unsigned> DstRegMap;
SmallVector<MachineInstr*, 16> RegSequences;
bool Sink3AddrInstruction(MachineBasicBlock *MBB, MachineInstr *MI,
unsigned Reg,
MachineBasicBlock::iterator OldPos);
bool isProfitableToReMat(unsigned Reg, const TargetRegisterClass *RC,
MachineInstr *MI, MachineInstr *DefMI,
MachineBasicBlock *MBB, unsigned Loc);
bool NoUseAfterLastDef(unsigned Reg, MachineBasicBlock *MBB, unsigned Dist,
unsigned &LastDef);
MachineInstr *FindLastUseInMBB(unsigned Reg, MachineBasicBlock *MBB,
unsigned Dist);
bool isProfitableToCommute(unsigned regB, unsigned regC,
MachineInstr *MI, MachineBasicBlock *MBB,
unsigned Dist);
bool CommuteInstruction(MachineBasicBlock::iterator &mi,
MachineFunction::iterator &mbbi,
unsigned RegB, unsigned RegC, unsigned Dist);
bool isProfitableToConv3Addr(unsigned RegA, unsigned RegB);
bool ConvertInstTo3Addr(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned RegA, unsigned RegB, unsigned Dist);
typedef std::pair<std::pair<unsigned, bool>, MachineInstr*> NewKill;
bool canUpdateDeletedKills(SmallVector<unsigned, 4> &Kills,
SmallVector<NewKill, 4> &NewKills,
MachineBasicBlock *MBB, unsigned Dist);
bool DeleteUnusedInstr(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi, unsigned Dist);
bool isDefTooClose(unsigned Reg, unsigned Dist,
MachineInstr *MI, MachineBasicBlock *MBB);
bool RescheduleMIBelowKill(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned Reg);
bool RescheduleKillAboveMI(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned Reg);
bool TryInstructionTransform(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned SrcIdx, unsigned DstIdx,
unsigned Dist,
SmallPtrSet<MachineInstr*, 8> &Processed);
void ScanUses(unsigned DstReg, MachineBasicBlock *MBB,
SmallPtrSet<MachineInstr*, 8> &Processed);
void ProcessCopy(MachineInstr *MI, MachineBasicBlock *MBB,
SmallPtrSet<MachineInstr*, 8> &Processed);
void CoalesceExtSubRegs(SmallVector<unsigned,4> &Srcs, unsigned DstReg);
bool EliminateRegSequences();
public:
static char ID; TwoAddressInstructionPass() : MachineFunctionPass(ID) {
initializeTwoAddressInstructionPassPass(*PassRegistry::getPassRegistry());
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<AliasAnalysis>();
AU.addPreserved<LiveVariables>();
AU.addPreservedID(MachineLoopInfoID);
AU.addPreservedID(MachineDominatorsID);
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction&);
};
}
char TwoAddressInstructionPass::ID = 0;
INITIALIZE_PASS_BEGIN(TwoAddressInstructionPass, "twoaddressinstruction",
"Two-Address instruction pass", false, false)
INITIALIZE_AG_DEPENDENCY(AliasAnalysis)
INITIALIZE_PASS_END(TwoAddressInstructionPass, "twoaddressinstruction",
"Two-Address instruction pass", false, false)
char &llvm::TwoAddressInstructionPassID = TwoAddressInstructionPass::ID;
bool TwoAddressInstructionPass::Sink3AddrInstruction(MachineBasicBlock *MBB,
MachineInstr *MI, unsigned SavedReg,
MachineBasicBlock::iterator OldPos) {
bool SeenStore = true; if (!MI->isSafeToMove(TII, AA, SeenStore))
return false;
unsigned DefReg = 0;
SmallSet<unsigned, 4> UseRegs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isUse() && MOReg != SavedReg)
UseRegs.insert(MO.getReg());
if (!MO.isDef())
continue;
if (MO.isImplicit())
return false;
if (DefReg)
return false;
DefReg = MO.getReg();
}
MachineInstr *KillMI = NULL;
for (MachineRegisterInfo::use_nodbg_iterator
UI = MRI->use_nodbg_begin(SavedReg),
UE = MRI->use_nodbg_end(); UI != UE; ++UI) {
MachineOperand &UseMO = UI.getOperand();
if (!UseMO.isKill())
continue;
KillMI = UseMO.getParent();
break;
}
if (!KillMI || KillMI->getParent() != MBB || KillMI == MI ||
KillMI->isTerminator())
return false;
MachineOperand *KillMO = NULL;
MachineBasicBlock::iterator KillPos = KillMI;
++KillPos;
unsigned NumVisited = 0;
for (MachineBasicBlock::iterator I = llvm::next(OldPos); I != KillPos; ++I) {
MachineInstr *OtherMI = I;
if (OtherMI->isDebugValue())
continue;
if (NumVisited > 30) return false;
++NumVisited;
for (unsigned i = 0, e = OtherMI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = OtherMI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (DefReg == MOReg)
return false;
if (MO.isKill()) {
if (OtherMI == KillMI && MOReg == SavedReg)
KillMO = &MO;
else if (UseRegs.count(MOReg))
return false;
}
}
}
KillMO->setIsKill(false);
KillMO = MI->findRegisterUseOperand(SavedReg, false, TRI);
KillMO->setIsKill(true);
if (LV)
LV->replaceKillInstruction(SavedReg, KillMI, MI);
MBB->remove(MI);
MBB->insert(KillPos, MI);
++Num3AddrSunk;
return true;
}
static bool isTwoAddrUse(MachineInstr *UseMI, unsigned Reg) {
const MCInstrDesc &MCID = UseMI->getDesc();
for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {
MachineOperand &MO = UseMI->getOperand(i);
if (MO.isReg() && MO.getReg() == Reg &&
(MO.isDef() || UseMI->isRegTiedToDefOperand(i)))
return true;
}
return false;
}
bool
TwoAddressInstructionPass::isProfitableToReMat(unsigned Reg,
const TargetRegisterClass *RC,
MachineInstr *MI, MachineInstr *DefMI,
MachineBasicBlock *MBB, unsigned Loc) {
bool OtherUse = false;
for (MachineRegisterInfo::use_nodbg_iterator UI = MRI->use_nodbg_begin(Reg),
UE = MRI->use_nodbg_end(); UI != UE; ++UI) {
MachineOperand &UseMO = UI.getOperand();
MachineInstr *UseMI = UseMO.getParent();
MachineBasicBlock *UseMBB = UseMI->getParent();
if (UseMBB == MBB) {
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(UseMI);
if (DI != DistanceMap.end() && DI->second == Loc)
continue; OtherUse = true;
if (isTwoAddrUse(UseMI, Reg))
return true;
}
}
if (OtherUse)
return false;
return MBB == DefMI->getParent();
}
bool TwoAddressInstructionPass::NoUseAfterLastDef(unsigned Reg,
MachineBasicBlock *MBB, unsigned Dist,
unsigned &LastDef) {
LastDef = 0;
unsigned LastUse = Dist;
for (MachineRegisterInfo::reg_iterator I = MRI->reg_begin(Reg),
E = MRI->reg_end(); I != E; ++I) {
MachineOperand &MO = I.getOperand();
MachineInstr *MI = MO.getParent();
if (MI->getParent() != MBB || MI->isDebugValue())
continue;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
continue;
if (MO.isUse() && DI->second < LastUse)
LastUse = DI->second;
if (MO.isDef() && DI->second > LastDef)
LastDef = DI->second;
}
return !(LastUse > LastDef && LastUse < Dist);
}
MachineInstr *TwoAddressInstructionPass::FindLastUseInMBB(unsigned Reg,
MachineBasicBlock *MBB,
unsigned Dist) {
unsigned LastUseDist = 0;
MachineInstr *LastUse = 0;
for (MachineRegisterInfo::reg_iterator I = MRI->reg_begin(Reg),
E = MRI->reg_end(); I != E; ++I) {
MachineOperand &MO = I.getOperand();
MachineInstr *MI = MO.getParent();
if (MI->getParent() != MBB || MI->isDebugValue())
continue;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
continue;
if (DI->second >= Dist)
continue;
if (MO.isUse() && DI->second > LastUseDist) {
LastUse = DI->first;
LastUseDist = DI->second;
}
}
return LastUse;
}
static bool isCopyToReg(MachineInstr &MI, const TargetInstrInfo *TII,
unsigned &SrcReg, unsigned &DstReg,
bool &IsSrcPhys, bool &IsDstPhys) {
SrcReg = 0;
DstReg = 0;
if (MI.isCopy()) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
} else if (MI.isInsertSubreg() || MI.isSubregToReg()) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(2).getReg();
} else
return false;
IsSrcPhys = TargetRegisterInfo::isPhysicalRegister(SrcReg);
IsDstPhys = TargetRegisterInfo::isPhysicalRegister(DstReg);
return true;
}
static bool isKilled(MachineInstr &MI, unsigned Reg,
const MachineRegisterInfo *MRI,
const TargetInstrInfo *TII) {
MachineInstr *DefMI = &MI;
for (;;) {
if (!DefMI->killsRegister(Reg))
return false;
if (TargetRegisterInfo::isPhysicalRegister(Reg))
return true;
MachineRegisterInfo::def_iterator Begin = MRI->def_begin(Reg);
if (llvm::next(Begin) != MRI->def_end())
return true;
DefMI = &*Begin;
bool IsSrcPhys, IsDstPhys;
unsigned SrcReg, DstReg;
if (!isCopyToReg(*DefMI, TII, SrcReg, DstReg, IsSrcPhys, IsDstPhys))
return true;
Reg = SrcReg;
}
}
static bool isTwoAddrUse(MachineInstr &MI, unsigned Reg, unsigned &DstReg) {
const MCInstrDesc &MCID = MI.getDesc();
unsigned NumOps = MI.isInlineAsm()
? MI.getNumOperands() : MCID.getNumOperands();
for (unsigned i = 0; i != NumOps; ++i) {
const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg() || !MO.isUse() || MO.getReg() != Reg)
continue;
unsigned ti;
if (MI.isRegTiedToDefOperand(i, &ti)) {
DstReg = MI.getOperand(ti).getReg();
return true;
}
}
return false;
}
static
MachineInstr *findLocalKill(unsigned Reg, MachineBasicBlock *MBB,
MachineInstr *MI, MachineRegisterInfo *MRI,
DenseMap<MachineInstr*, unsigned> &DistanceMap) {
MachineInstr *KillMI = 0;
for (MachineRegisterInfo::use_nodbg_iterator
UI = MRI->use_nodbg_begin(Reg),
UE = MRI->use_nodbg_end(); UI != UE; ++UI) {
MachineInstr *UseMI = &*UI;
if (UseMI == MI || UseMI->getParent() != MBB)
continue;
if (DistanceMap.count(UseMI))
continue;
if (!UI.getOperand().isKill())
return 0;
if (KillMI)
return 0; KillMI = UseMI;
}
return KillMI;
}
static
MachineInstr *findOnlyInterestingUse(unsigned Reg, MachineBasicBlock *MBB,
MachineRegisterInfo *MRI,
const TargetInstrInfo *TII,
bool &IsCopy,
unsigned &DstReg, bool &IsDstPhys) {
if (!MRI->hasOneNonDBGUse(Reg))
return 0;
MachineInstr &UseMI = *MRI->use_nodbg_begin(Reg);
if (UseMI.getParent() != MBB)
return 0;
unsigned SrcReg;
bool IsSrcPhys;
if (isCopyToReg(UseMI, TII, SrcReg, DstReg, IsSrcPhys, IsDstPhys)) {
IsCopy = true;
return &UseMI;
}
IsDstPhys = false;
if (isTwoAddrUse(UseMI, Reg, DstReg)) {
IsDstPhys = TargetRegisterInfo::isPhysicalRegister(DstReg);
return &UseMI;
}
return 0;
}
static unsigned
getMappedReg(unsigned Reg, DenseMap<unsigned, unsigned> &RegMap) {
while (TargetRegisterInfo::isVirtualRegister(Reg)) {
DenseMap<unsigned, unsigned>::iterator SI = RegMap.find(Reg);
if (SI == RegMap.end())
return 0;
Reg = SI->second;
}
if (TargetRegisterInfo::isPhysicalRegister(Reg))
return Reg;
return 0;
}
static bool
regsAreCompatible(unsigned RegA, unsigned RegB, const TargetRegisterInfo *TRI) {
if (RegA == RegB)
return true;
if (!RegA || !RegB)
return false;
return TRI->regsOverlap(RegA, RegB);
}
bool
TwoAddressInstructionPass::isProfitableToCommute(unsigned regB, unsigned regC,
MachineInstr *MI, MachineBasicBlock *MBB,
unsigned Dist) {
if (OptLevel == CodeGenOpt::None)
return false;
if (!MI->killsRegister(regC))
return false;
unsigned FromRegB = getMappedReg(regB, SrcRegMap);
unsigned FromRegC = getMappedReg(regC, SrcRegMap);
unsigned ToRegB = getMappedReg(regB, DstRegMap);
unsigned ToRegC = getMappedReg(regC, DstRegMap);
if ((FromRegB && ToRegB && !regsAreCompatible(FromRegB, ToRegB, TRI)) &&
((!FromRegC && !ToRegC) ||
regsAreCompatible(FromRegB, ToRegC, TRI) ||
regsAreCompatible(FromRegC, ToRegB, TRI)))
return true;
unsigned LastDefC = 0;
if (!NoUseAfterLastDef(regC, MBB, Dist, LastDefC))
return false;
unsigned LastDefB = 0;
if (!NoUseAfterLastDef(regB, MBB, Dist, LastDefB))
return true;
return LastDefB && LastDefC && LastDefC > LastDefB;
}
bool
TwoAddressInstructionPass::CommuteInstruction(MachineBasicBlock::iterator &mi,
MachineFunction::iterator &mbbi,
unsigned RegB, unsigned RegC, unsigned Dist) {
MachineInstr *MI = mi;
DEBUG(dbgs() << "2addr: COMMUTING : " << *MI);
MachineInstr *NewMI = TII->commuteInstruction(MI);
if (NewMI == 0) {
DEBUG(dbgs() << "2addr: COMMUTING FAILED!\n");
return false;
}
DEBUG(dbgs() << "2addr: COMMUTED TO: " << *NewMI);
if (NewMI != MI) {
if (LV)
LV->replaceKillInstruction(RegC, MI, NewMI);
mbbi->insert(mi, NewMI); mbbi->erase(mi); mi = NewMI;
DistanceMap.insert(std::make_pair(NewMI, Dist));
}
unsigned FromRegC = getMappedReg(RegC, SrcRegMap);
if (FromRegC) {
unsigned RegA = MI->getOperand(0).getReg();
SrcRegMap[RegA] = FromRegC;
}
return true;
}
bool
TwoAddressInstructionPass::isProfitableToConv3Addr(unsigned RegA,unsigned RegB){
unsigned FromRegB = getMappedReg(RegB, SrcRegMap);
if (!FromRegB)
return false;
unsigned ToRegA = getMappedReg(RegA, DstRegMap);
return (ToRegA && !regsAreCompatible(FromRegB, ToRegA, TRI));
}
bool
TwoAddressInstructionPass::ConvertInstTo3Addr(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned RegA, unsigned RegB,
unsigned Dist) {
MachineInstr *NewMI = TII->convertToThreeAddress(mbbi, mi, LV);
if (NewMI) {
DEBUG(dbgs() << "2addr: CONVERTING 2-ADDR: " << *mi);
DEBUG(dbgs() << "2addr: TO 3-ADDR: " << *NewMI);
bool Sunk = false;
if (NewMI->findRegisterUseOperand(RegB, false, TRI))
Sunk = Sink3AddrInstruction(mbbi, NewMI, RegB, mi);
mbbi->erase(mi);
if (!Sunk) {
DistanceMap.insert(std::make_pair(NewMI, Dist));
mi = NewMI;
nmi = llvm::next(mi);
}
SrcRegMap.erase(RegA);
DstRegMap.erase(RegB);
return true;
}
return false;
}
void
TwoAddressInstructionPass::ScanUses(unsigned DstReg, MachineBasicBlock *MBB,
SmallPtrSet<MachineInstr*, 8> &Processed) {
SmallVector<unsigned, 4> VirtRegPairs;
bool IsDstPhys;
bool IsCopy = false;
unsigned NewReg = 0;
unsigned Reg = DstReg;
while (MachineInstr *UseMI = findOnlyInterestingUse(Reg, MBB, MRI, TII,IsCopy,
NewReg, IsDstPhys)) {
if (IsCopy && !Processed.insert(UseMI))
break;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(UseMI);
if (DI != DistanceMap.end())
break;
if (IsDstPhys) {
VirtRegPairs.push_back(NewReg);
break;
}
bool isNew = SrcRegMap.insert(std::make_pair(NewReg, Reg)).second;
if (!isNew)
assert(SrcRegMap[NewReg] == Reg && "Can't map to two src registers!");
VirtRegPairs.push_back(NewReg);
Reg = NewReg;
}
if (!VirtRegPairs.empty()) {
unsigned ToReg = VirtRegPairs.back();
VirtRegPairs.pop_back();
while (!VirtRegPairs.empty()) {
unsigned FromReg = VirtRegPairs.back();
VirtRegPairs.pop_back();
bool isNew = DstRegMap.insert(std::make_pair(FromReg, ToReg)).second;
if (!isNew)
assert(DstRegMap[FromReg] == ToReg &&"Can't map to two dst registers!");
ToReg = FromReg;
}
bool isNew = DstRegMap.insert(std::make_pair(DstReg, ToReg)).second;
if (!isNew)
assert(DstRegMap[DstReg] == ToReg && "Can't map to two dst registers!");
}
}
void TwoAddressInstructionPass::ProcessCopy(MachineInstr *MI,
MachineBasicBlock *MBB,
SmallPtrSet<MachineInstr*, 8> &Processed) {
if (Processed.count(MI))
return;
bool IsSrcPhys, IsDstPhys;
unsigned SrcReg, DstReg;
if (!isCopyToReg(*MI, TII, SrcReg, DstReg, IsSrcPhys, IsDstPhys))
return;
if (IsDstPhys && !IsSrcPhys)
DstRegMap.insert(std::make_pair(SrcReg, DstReg));
else if (!IsDstPhys && IsSrcPhys) {
bool isNew = SrcRegMap.insert(std::make_pair(DstReg, SrcReg)).second;
if (!isNew)
assert(SrcRegMap[DstReg] == SrcReg &&
"Can't map to two src physical registers!");
ScanUses(DstReg, MBB, Processed);
}
Processed.insert(MI);
return;
}
static bool isSafeToDelete(MachineInstr *MI,
const TargetInstrInfo *TII,
SmallVector<unsigned, 4> &Kills) {
if (MI->mayStore() || MI->isCall())
return false;
if (MI->isTerminator() || MI->hasUnmodeledSideEffects())
return false;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
if (MO.isDef() && !MO.isDead())
return false;
if (MO.isUse() && MO.isKill())
Kills.push_back(MO.getReg());
}
return true;
}
bool TwoAddressInstructionPass::
canUpdateDeletedKills(SmallVector<unsigned, 4> &Kills,
SmallVector<NewKill, 4> &NewKills,
MachineBasicBlock *MBB, unsigned Dist) {
while (!Kills.empty()) {
unsigned Kill = Kills.back();
Kills.pop_back();
if (TargetRegisterInfo::isPhysicalRegister(Kill))
return false;
MachineInstr *LastKill = FindLastUseInMBB(Kill, MBB, Dist);
if (!LastKill)
return false;
bool isModRef = LastKill->definesRegister(Kill);
NewKills.push_back(std::make_pair(std::make_pair(Kill, isModRef),
LastKill));
}
return true;
}
bool
TwoAddressInstructionPass::DeleteUnusedInstr(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned Dist) {
SmallVector<unsigned, 4> Kills;
if (!isSafeToDelete(mi, TII, Kills))
return false;
SmallVector<NewKill, 4> NewKills;
if (!canUpdateDeletedKills(Kills, NewKills, &*mbbi, Dist))
return false;
if (LV) {
while (!NewKills.empty()) {
MachineInstr *NewKill = NewKills.back().second;
unsigned Kill = NewKills.back().first.first;
bool isDead = NewKills.back().first.second;
NewKills.pop_back();
if (LV->removeVirtualRegisterKilled(Kill, mi)) {
if (isDead)
LV->addVirtualRegisterDead(Kill, NewKill);
else
LV->addVirtualRegisterKilled(Kill, NewKill);
}
}
}
mbbi->erase(mi); mi = nmi;
return true;
}
bool
TwoAddressInstructionPass::RescheduleMIBelowKill(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned Reg) {
MachineInstr *MI = &*mi;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
return false;
MachineInstr *KillMI = findLocalKill(Reg, MBB, mi, MRI, DistanceMap);
if (!KillMI || KillMI->isCopy() || KillMI->isCopyLike())
return false;
if (KillMI->hasUnmodeledSideEffects() || KillMI->isCall() ||
KillMI->isBranch() || KillMI->isTerminator())
return false;
unsigned DstReg;
if (isTwoAddrUse(*KillMI, Reg, DstReg))
return false;
bool SeenStore = true;
if (!MI->isSafeToMove(TII, AA, SeenStore))
return false;
if (TII->getInstrLatency(InstrItins, MI) > 1)
return false;
SmallSet<unsigned, 2> Uses;
SmallSet<unsigned, 2> Kills;
SmallSet<unsigned, 2> Defs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isDef())
Defs.insert(MOReg);
else {
Uses.insert(MOReg);
if (MO.isKill() && MOReg != Reg)
Kills.insert(MOReg);
}
}
MachineBasicBlock::iterator From = MI;
MachineBasicBlock::iterator To = llvm::next(From);
while (To->isCopy() && Defs.count(To->getOperand(1).getReg())) {
Defs.insert(To->getOperand(0).getReg());
++To;
}
unsigned NumVisited = 0;
MachineBasicBlock::iterator KillPos = KillMI;
++KillPos;
for (MachineBasicBlock::iterator I = To; I != KillPos; ++I) {
MachineInstr *OtherMI = I;
if (OtherMI->isDebugValue())
continue;
if (NumVisited > 10) return false;
++NumVisited;
if (OtherMI->hasUnmodeledSideEffects() || OtherMI->isCall() ||
OtherMI->isBranch() || OtherMI->isTerminator())
return false;
for (unsigned i = 0, e = OtherMI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = OtherMI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isDef()) {
if (Uses.count(MOReg))
return false;
if (!MO.isDead() && Defs.count(MOReg))
return false;
} else {
if (Defs.count(MOReg))
return false;
if (MOReg != Reg &&
((MO.isKill() && Uses.count(MOReg)) || Kills.count(MOReg)))
return false;
}
}
}
while (From != MBB->begin() && llvm::prior(From)->isDebugValue())
--From;
nmi = To;
MBB->splice(KillPos, MBB, From, To);
DistanceMap.erase(DI);
if (LV) {
LV->removeVirtualRegisterKilled(Reg, KillMI);
LV->addVirtualRegisterKilled(Reg, MI);
} else {
for (unsigned i = 0, e = KillMI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = KillMI->getOperand(i);
if (!MO.isReg() || !MO.isUse() || MO.getReg() != Reg)
continue;
MO.setIsKill(false);
}
MI->addRegisterKilled(Reg, 0);
}
return true;
}
bool TwoAddressInstructionPass::isDefTooClose(unsigned Reg, unsigned Dist,
MachineInstr *MI,
MachineBasicBlock *MBB) {
for (MachineRegisterInfo::def_iterator DI = MRI->def_begin(Reg),
DE = MRI->def_end(); DI != DE; ++DI) {
MachineInstr *DefMI = &*DI;
if (DefMI->getParent() != MBB || DefMI->isCopy() || DefMI->isCopyLike())
continue;
if (DefMI == MI)
return true; DenseMap<MachineInstr*, unsigned>::iterator DDI = DistanceMap.find(DefMI);
if (DDI == DistanceMap.end())
return true; unsigned DefDist = DDI->second;
assert(Dist > DefDist && "Visited def already?");
if (TII->getInstrLatency(InstrItins, DefMI) > (int)(Dist - DefDist))
return true;
}
return false;
}
bool
TwoAddressInstructionPass::RescheduleKillAboveMI(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned Reg) {
MachineInstr *MI = &*mi;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
return false;
MachineInstr *KillMI = findLocalKill(Reg, MBB, mi, MRI, DistanceMap);
if (!KillMI || KillMI->isCopy() || KillMI->isCopyLike())
return false;
unsigned DstReg;
if (isTwoAddrUse(*KillMI, Reg, DstReg))
return false;
bool SeenStore = true;
if (!KillMI->isSafeToMove(TII, AA, SeenStore))
return false;
SmallSet<unsigned, 2> Uses;
SmallSet<unsigned, 2> Kills;
SmallSet<unsigned, 2> Defs;
SmallSet<unsigned, 2> LiveDefs;
for (unsigned i = 0, e = KillMI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = KillMI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (MO.isUse()) {
if (!MOReg)
continue;
if (isDefTooClose(MOReg, DI->second, MI, MBB))
return false;
Uses.insert(MOReg);
if (MO.isKill() && MOReg != Reg)
Kills.insert(MOReg);
} else if (TargetRegisterInfo::isPhysicalRegister(MOReg)) {
Defs.insert(MOReg);
if (!MO.isDead())
LiveDefs.insert(MOReg);
}
}
unsigned NumVisited = 0;
MachineBasicBlock::iterator KillPos = KillMI;
for (MachineBasicBlock::iterator I = mi; I != KillPos; ++I) {
MachineInstr *OtherMI = I;
if (OtherMI->isDebugValue())
continue;
if (NumVisited > 10) return false;
++NumVisited;
if (OtherMI->hasUnmodeledSideEffects() || OtherMI->isCall() ||
OtherMI->isBranch() || OtherMI->isTerminator())
return false;
SmallVector<unsigned, 2> OtherDefs;
for (unsigned i = 0, e = OtherMI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = OtherMI->getOperand(i);
if (!MO.isReg())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isUse()) {
if (Defs.count(MOReg))
return false;
if (Kills.count(MOReg))
return false;
} else {
OtherDefs.push_back(MOReg);
}
}
for (unsigned i = 0, e = OtherDefs.size(); i != e; ++i) {
unsigned MOReg = OtherDefs[i];
if (Uses.count(MOReg))
return false;
if (TargetRegisterInfo::isPhysicalRegister(MOReg) &&
LiveDefs.count(MOReg))
return false;
Defs.erase(MOReg);
}
}
MachineBasicBlock::iterator InsertPos = mi;
while (InsertPos != MBB->begin() && llvm::prior(InsertPos)->isDebugValue())
--InsertPos;
MachineBasicBlock::iterator From = KillMI;
MachineBasicBlock::iterator To = llvm::next(From);
while (llvm::prior(From)->isDebugValue())
--From;
MBB->splice(InsertPos, MBB, From, To);
nmi = llvm::prior(InsertPos); DistanceMap.erase(DI);
if (LV) {
LV->removeVirtualRegisterKilled(Reg, KillMI);
LV->addVirtualRegisterKilled(Reg, MI);
} else {
for (unsigned i = 0, e = KillMI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = KillMI->getOperand(i);
if (!MO.isReg() || !MO.isUse() || MO.getReg() != Reg)
continue;
MO.setIsKill(false);
}
MI->addRegisterKilled(Reg, 0);
}
return true;
}
bool TwoAddressInstructionPass::
TryInstructionTransform(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned SrcIdx, unsigned DstIdx, unsigned Dist,
SmallPtrSet<MachineInstr*, 8> &Processed) {
if (OptLevel == CodeGenOpt::None)
return false;
MachineInstr &MI = *mi;
unsigned regA = MI.getOperand(DstIdx).getReg();
unsigned regB = MI.getOperand(SrcIdx).getReg();
assert(TargetRegisterInfo::isVirtualRegister(regB) &&
"cannot make instruction into two-address form");
bool regBKilled = isKilled(MI, regB, MRI, TII);
if (!regBKilled && MI.getOperand(DstIdx).isDead() &&
DeleteUnusedInstr(mi, nmi, mbbi, Dist)) {
++NumDeletes;
return true; }
unsigned SrcOp1, SrcOp2;
unsigned regC = 0;
unsigned regCIdx = ~0U;
bool TryCommute = false;
bool AggressiveCommute = false;
if (MI.isCommutable() && MI.getNumOperands() >= 3 &&
TII->findCommutedOpIndices(&MI, SrcOp1, SrcOp2)) {
if (SrcIdx == SrcOp1)
regCIdx = SrcOp2;
else if (SrcIdx == SrcOp2)
regCIdx = SrcOp1;
if (regCIdx != ~0U) {
regC = MI.getOperand(regCIdx).getReg();
if (!regBKilled && isKilled(MI, regC, MRI, TII))
TryCommute = true;
else if (isProfitableToCommute(regB, regC, &MI, mbbi, Dist)) {
TryCommute = true;
AggressiveCommute = true;
}
}
}
if (TryCommute && CommuteInstruction(mi, mbbi, regB, regC, Dist)) {
++NumCommuted;
if (AggressiveCommute)
++NumAggrCommuted;
return false;
}
if (RescheduleMIBelowKill(mbbi, mi, nmi, regB)) {
++NumReSchedDowns;
return true;
}
if (TargetRegisterInfo::isVirtualRegister(regA))
ScanUses(regA, &*mbbi, Processed);
if (MI.isConvertibleTo3Addr()) {
if (!regBKilled || isProfitableToConv3Addr(regA, regB)) {
if (ConvertInstTo3Addr(mi, nmi, mbbi, regA, regB, Dist)) {
++NumConvertedTo3Addr;
return true; }
}
}
if (RescheduleKillAboveMI(mbbi, mi, nmi, regB)) {
++NumReSchedUps;
return true;
}
if (MI.mayLoad() && !regBKilled) {
unsigned LoadRegIndex;
unsigned NewOpc =
TII->getOpcodeAfterMemoryUnfold(MI.getOpcode(),
true,
false,
&LoadRegIndex);
if (NewOpc != 0) {
const MCInstrDesc &UnfoldMCID = TII->get(NewOpc);
if (UnfoldMCID.getNumDefs() == 1) {
MachineFunction &MF = *mbbi->getParent();
DEBUG(dbgs() << "2addr: UNFOLDING: " << MI);
const TargetRegisterClass *RC =
TII->getRegClass(UnfoldMCID, LoadRegIndex, TRI);
unsigned Reg = MRI->createVirtualRegister(RC);
SmallVector<MachineInstr *, 2> NewMIs;
if (!TII->unfoldMemoryOperand(MF, &MI, Reg,
true,false,
NewMIs)) {
DEBUG(dbgs() << "2addr: ABANDONING UNFOLD\n");
return false;
}
assert(NewMIs.size() == 2 &&
"Unfolded a load into multiple instructions!");
NewMIs[1]->addRegisterKilled(Reg, TRI);
mbbi->insert(mi, NewMIs[0]);
mbbi->insert(mi, NewMIs[1]);
DEBUG(dbgs() << "2addr: NEW LOAD: " << *NewMIs[0]
<< "2addr: NEW INST: " << *NewMIs[1]);
unsigned NewDstIdx = NewMIs[1]->findRegisterDefOperandIdx(regA);
unsigned NewSrcIdx = NewMIs[1]->findRegisterUseOperandIdx(regB);
MachineBasicBlock::iterator NewMI = NewMIs[1];
bool TransformSuccess =
TryInstructionTransform(NewMI, mi, mbbi,
NewSrcIdx, NewDstIdx, Dist, Processed);
if (TransformSuccess ||
NewMIs[1]->getOperand(NewSrcIdx).isKill()) {
if (LV) {
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i);
if (MO.isReg() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
if (MO.isUse()) {
if (MO.isKill()) {
if (NewMIs[0]->killsRegister(MO.getReg()))
LV->replaceKillInstruction(MO.getReg(), &MI, NewMIs[0]);
else {
assert(NewMIs[1]->killsRegister(MO.getReg()) &&
"Kill missing after load unfold!");
LV->replaceKillInstruction(MO.getReg(), &MI, NewMIs[1]);
}
}
} else if (LV->removeVirtualRegisterDead(MO.getReg(), &MI)) {
if (NewMIs[1]->registerDefIsDead(MO.getReg()))
LV->addVirtualRegisterDead(MO.getReg(), NewMIs[1]);
else {
assert(NewMIs[0]->registerDefIsDead(MO.getReg()) &&
"Dead flag missing after load unfold!");
LV->addVirtualRegisterDead(MO.getReg(), NewMIs[0]);
}
}
}
}
LV->addVirtualRegisterKilled(Reg, NewMIs[1]);
}
MI.eraseFromParent();
mi = NewMIs[1];
if (TransformSuccess)
return true;
} else {
DEBUG(dbgs() << "2addr: ABANDONING UNFOLD\n");
NewMIs[0]->eraseFromParent();
NewMIs[1]->eraseFromParent();
}
}
}
}
return false;
}
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Machine Function\n");
const TargetMachine &TM = MF.getTarget();
MRI = &MF.getRegInfo();
TII = TM.getInstrInfo();
TRI = TM.getRegisterInfo();
InstrItins = TM.getInstrItineraryData();
LV = getAnalysisIfAvailable<LiveVariables>();
AA = &getAnalysis<AliasAnalysis>();
OptLevel = TM.getOptLevel();
bool MadeChange = false;
DEBUG(dbgs() << "********** REWRITING TWO-ADDR INSTRS **********\n");
DEBUG(dbgs() << "********** Function: "
<< MF.getFunction()->getName() << '\n');
MRI->leaveSSA();
BitVector ReMatRegs(MRI->getNumVirtRegs());
typedef DenseMap<unsigned, SmallVector<std::pair<unsigned, unsigned>, 4> >
TiedOperandMap;
TiedOperandMap TiedOperands(4);
SmallPtrSet<MachineInstr*, 8> Processed;
for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end();
mbbi != mbbe; ++mbbi) {
unsigned Dist = 0;
DistanceMap.clear();
SrcRegMap.clear();
DstRegMap.clear();
Processed.clear();
for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end();
mi != me; ) {
MachineBasicBlock::iterator nmi = llvm::next(mi);
if (mi->isDebugValue()) {
mi = nmi;
continue;
}
if (mi->isRegSequence())
RegSequences.push_back(&*mi);
const MCInstrDesc &MCID = mi->getDesc();
bool FirstTied = true;
DistanceMap.insert(std::make_pair(mi, ++Dist));
ProcessCopy(&*mi, &*mbbi, Processed);
unsigned NumOps = mi->isInlineAsm()
? mi->getNumOperands() : MCID.getNumOperands();
for (unsigned SrcIdx = 0; SrcIdx < NumOps; ++SrcIdx) {
unsigned DstIdx = 0;
if (!mi->isRegTiedToDefOperand(SrcIdx, &DstIdx))
continue;
if (FirstTied) {
FirstTied = false;
++NumTwoAddressInstrs;
DEBUG(dbgs() << '\t' << *mi);
}
assert(mi->getOperand(SrcIdx).isReg() &&
mi->getOperand(SrcIdx).getReg() &&
mi->getOperand(SrcIdx).isUse() &&
"two address instruction invalid");
unsigned regB = mi->getOperand(SrcIdx).getReg();
TiedOperands[regB].push_back(std::make_pair(SrcIdx, DstIdx));
}
for (TiedOperandMap::iterator OI = TiedOperands.begin(),
OE = TiedOperands.end(); OI != OE; ++OI) {
SmallVector<std::pair<unsigned, unsigned>, 4> &TiedPairs = OI->second;
if (TiedOperands.size() == 1 && TiedPairs.size() == 1) {
unsigned SrcIdx = TiedPairs[0].first;
unsigned DstIdx = TiedPairs[0].second;
if (mi->getOperand(SrcIdx).getReg() ==
mi->getOperand(DstIdx).getReg())
break;
if (TryInstructionTransform(mi, nmi, mbbi, SrcIdx, DstIdx, Dist,
Processed))
break; }
bool IsEarlyClobber = false;
bool RemovedKillFlag = false;
bool AllUsesCopied = true;
unsigned LastCopiedReg = 0;
unsigned regB = OI->first;
for (unsigned tpi = 0, tpe = TiedPairs.size(); tpi != tpe; ++tpi) {
unsigned SrcIdx = TiedPairs[tpi].first;
unsigned DstIdx = TiedPairs[tpi].second;
const MachineOperand &DstMO = mi->getOperand(DstIdx);
unsigned regA = DstMO.getReg();
IsEarlyClobber |= DstMO.isEarlyClobber();
regB = mi->getOperand(SrcIdx).getReg();
if (regA == regB) {
AllUsesCopied = false;
continue;
}
LastCopiedReg = regA;
assert(TargetRegisterInfo::isVirtualRegister(regB) &&
"cannot make instruction into two-address form");
#ifndef NDEBUG
for (unsigned i = 0; i != mi->getNumOperands(); ++i)
assert(i == DstIdx ||
!mi->getOperand(i).isReg() ||
mi->getOperand(i).getReg() != regA);
#endif
const TargetRegisterClass *rc = MRI->getRegClass(regB);
MachineInstr *DefMI = MRI->getVRegDef(regB);
if (DefMI &&
DefMI->isAsCheapAsAMove() &&
DefMI->isSafeToReMat(TII, AA, regB) &&
isProfitableToReMat(regB, rc, mi, DefMI, mbbi, Dist)){
DEBUG(dbgs() << "2addr: REMATTING : " << *DefMI << "\n");
unsigned regASubIdx = mi->getOperand(DstIdx).getSubReg();
TII->reMaterialize(*mbbi, mi, regA, regASubIdx, DefMI, *TRI);
ReMatRegs.set(TargetRegisterInfo::virtReg2Index(regB));
++NumReMats;
} else {
BuildMI(*mbbi, mi, mi->getDebugLoc(), TII->get(TargetOpcode::COPY),
regA).addReg(regB);
}
MachineBasicBlock::iterator prevMI = prior(mi);
DistanceMap.insert(std::make_pair(prevMI, Dist));
DistanceMap[mi] = ++Dist;
DEBUG(dbgs() << "\t\tprepend:\t" << *prevMI);
MachineOperand &MO = mi->getOperand(SrcIdx);
assert(MO.isReg() && MO.getReg() == regB && MO.isUse() &&
"inconsistent operand info for 2-reg pass");
if (MO.isKill()) {
MO.setIsKill(false);
RemovedKillFlag = true;
}
MO.setReg(regA);
}
if (AllUsesCopied) {
if (!IsEarlyClobber) {
for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
MachineOperand &MO = mi->getOperand(i);
if (MO.isReg() && MO.getReg() == regB && MO.isUse()) {
if (MO.isKill()) {
MO.setIsKill(false);
RemovedKillFlag = true;
}
MO.setReg(LastCopiedReg);
}
}
}
if (RemovedKillFlag && LV && LV->getVarInfo(regB).removeKill(mi))
LV->addVirtualRegisterKilled(regB, prior(mi));
} else if (RemovedKillFlag) {
for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
MachineOperand &MO = mi->getOperand(i);
if (MO.isReg() && MO.getReg() == regB && MO.isUse()) {
MO.setIsKill(true);
break;
}
}
}
TII->scheduleTwoAddrSource(prior(mi), mi, *TRI);
MadeChange = true;
DEBUG(dbgs() << "\t\trewrite to:\t" << *mi);
}
if (mi->isInsertSubreg()) {
unsigned SubIdx = mi->getOperand(3).getImm();
mi->RemoveOperand(3);
assert(mi->getOperand(0).getSubReg() == 0 && "Unexpected subreg idx");
mi->getOperand(0).setSubReg(SubIdx);
mi->RemoveOperand(1);
mi->setDesc(TII->get(TargetOpcode::COPY));
DEBUG(dbgs() << "\t\tconvert to:\t" << *mi);
}
TiedOperands.clear();
mi = nmi;
}
}
for (int i = ReMatRegs.find_first(); i != -1; i = ReMatRegs.find_next(i)) {
unsigned VReg = TargetRegisterInfo::index2VirtReg(i);
if (MRI->use_nodbg_empty(VReg)) {
MachineInstr *DefMI = MRI->getVRegDef(VReg);
DefMI->eraseFromParent();
}
}
MadeChange |= EliminateRegSequences();
return MadeChange;
}
static void UpdateRegSequenceSrcs(unsigned SrcReg,
unsigned DstReg, unsigned SubIdx,
MachineRegisterInfo *MRI,
const TargetRegisterInfo &TRI) {
for (MachineRegisterInfo::reg_iterator RI = MRI->reg_begin(SrcReg),
RE = MRI->reg_end(); RI != RE; ) {
MachineOperand &MO = RI.getOperand();
++RI;
MO.substVirtReg(DstReg, SubIdx, TRI);
}
}
static MachineInstr *findFirstDef(unsigned Reg, MachineRegisterInfo *MRI) {
SmallPtrSet<MachineInstr*, 8> Defs;
MachineInstr *First = 0;
for (MachineRegisterInfo::def_iterator RI = MRI->def_begin(Reg);
MachineInstr *MI = RI.skipInstruction(); Defs.insert(MI))
First = MI;
if (!First)
return 0;
MachineBasicBlock *MBB = First->getParent();
MachineBasicBlock::iterator A = First, B = First;
bool Moving;
do {
Moving = false;
if (A != MBB->begin()) {
Moving = true;
--A;
if (Defs.erase(A)) First = A;
}
if (B != MBB->end()) {
Defs.erase(B);
++B;
Moving = true;
}
} while (Moving && !Defs.empty());
assert(Defs.empty() && "Instructions outside basic block!");
return First;
}
void
TwoAddressInstructionPass::CoalesceExtSubRegs(SmallVector<unsigned,4> &Srcs,
unsigned DstReg) {
SmallSet<unsigned, 4> Seen;
for (unsigned i = 0, e = Srcs.size(); i != e; ++i) {
unsigned SrcReg = Srcs[i];
if (!Seen.insert(SrcReg))
continue;
MachineInstr *SrcDefMI = MRI->getVRegDef(SrcReg);
MachineInstr *DstDefMI = MRI->getVRegDef(DstReg);
if (SrcDefMI->getParent() != DstDefMI->getParent())
continue;
bool CanCoalesce = true;
SmallVector<unsigned, 4> SrcSubIndices, DstSubIndices;
for (MachineRegisterInfo::use_nodbg_iterator
UI = MRI->use_nodbg_begin(SrcReg),
UE = MRI->use_nodbg_end(); UI != UE; ++UI) {
MachineInstr *UseMI = &*UI;
if (!UseMI->isCopy() || UseMI->getOperand(0).getReg() != DstReg) {
CanCoalesce = false;
break;
}
SrcSubIndices.push_back(UseMI->getOperand(1).getSubReg());
DstSubIndices.push_back(UseMI->getOperand(0).getSubReg());
}
if (!CanCoalesce || SrcSubIndices.size() < 2)
continue;
std::sort(SrcSubIndices.begin(), SrcSubIndices.end());
unsigned NewSrcSubIdx = 0;
if (!TRI->canCombineSubRegIndices(MRI->getRegClass(SrcReg), SrcSubIndices,
NewSrcSubIdx))
continue;
std::sort(DstSubIndices.begin(), DstSubIndices.end());
unsigned NewDstSubIdx = 0;
if (!TRI->canCombineSubRegIndices(MRI->getRegClass(DstReg), DstSubIndices,
NewDstSubIdx))
continue;
if (NewSrcSubIdx != 0 && NewDstSubIdx != 0)
continue;
MachineInstr *SomeMI = 0;
CanCoalesce = true;
for (MachineRegisterInfo::use_nodbg_iterator
UI = MRI->use_nodbg_begin(SrcReg),
UE = MRI->use_nodbg_end(); UI != UE; ++UI) {
MachineInstr *UseMI = &*UI;
assert(UseMI->isCopy());
unsigned DstSubIdx = UseMI->getOperand(0).getSubReg();
unsigned SrcSubIdx = UseMI->getOperand(1).getSubReg();
assert(DstSubIdx != 0 && "missing subreg from RegSequence elimination");
if ((NewDstSubIdx == 0 &&
TRI->composeSubRegIndices(NewSrcSubIdx, DstSubIdx) != SrcSubIdx) ||
(NewSrcSubIdx == 0 &&
TRI->composeSubRegIndices(NewDstSubIdx, SrcSubIdx) != DstSubIdx)) {
CanCoalesce = false;
break;
}
if (!SomeMI || UseMI->getOperand(0).isUndef())
SomeMI = UseMI;
}
if (!CanCoalesce)
continue;
MachineInstr *CopyMI = BuildMI(*SomeMI->getParent(), SomeMI,
SomeMI->getDebugLoc(),
TII->get(TargetOpcode::COPY))
.addReg(DstReg, RegState::Define |
getUndefRegState(SomeMI->getOperand(0).isUndef()),
NewDstSubIdx)
.addReg(SrcReg, 0, NewSrcSubIdx);
for (MachineRegisterInfo::use_nodbg_iterator
UI = MRI->use_nodbg_begin(SrcReg),
UE = MRI->use_nodbg_end(); UI != UE; ) {
MachineInstr *UseMI = &*UI;
++UI;
if (UseMI == CopyMI)
continue;
assert(UseMI->isCopy());
if (UseMI->getOperand(1).isKill()) {
CopyMI->getOperand(1).setIsKill();
if (LV)
LV->replaceKillInstruction(SrcReg, UseMI, &*CopyMI);
}
UseMI->eraseFromParent();
}
}
}
static bool HasOtherRegSequenceUses(unsigned Reg, MachineInstr *RegSeq,
MachineRegisterInfo *MRI) {
for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(Reg),
UE = MRI->use_end(); UI != UE; ++UI) {
MachineInstr *UseMI = &*UI;
if (UseMI != RegSeq && UseMI->isRegSequence())
return true;
}
return false;
}
bool TwoAddressInstructionPass::EliminateRegSequences() {
if (RegSequences.empty())
return false;
for (unsigned i = 0, e = RegSequences.size(); i != e; ++i) {
MachineInstr *MI = RegSequences[i];
unsigned DstReg = MI->getOperand(0).getReg();
if (MI->getOperand(0).getSubReg() ||
TargetRegisterInfo::isPhysicalRegister(DstReg) ||
!(MI->getNumOperands() & 1)) {
DEBUG(dbgs() << "Illegal REG_SEQUENCE instruction:" << *MI);
llvm_unreachable(0);
}
bool IsImpDef = true;
SmallVector<unsigned, 4> RealSrcs;
SmallSet<unsigned, 4> Seen;
for (unsigned i = 1, e = MI->getNumOperands(); i < e; i += 2) {
unsigned SrcReg = MI->getOperand(i).getReg();
unsigned SubIdx = MI->getOperand(i+1).getImm();
MachineInstr *DefMI = NULL;
if (!MI->getOperand(i).getSubReg() &&
!TargetRegisterInfo::isPhysicalRegister(SrcReg)) {
DefMI = MRI->getVRegDef(SrcReg);
}
if (DefMI && DefMI->isImplicitDef()) {
DefMI->eraseFromParent();
continue;
}
IsImpDef = false;
if (DefMI && DefMI->isCopy() && DefMI->getOperand(1).getSubReg())
RealSrcs.push_back(DefMI->getOperand(1).getReg());
bool isKill = MI->getOperand(i).isKill();
if (!DefMI || !Seen.insert(SrcReg) ||
MI->getParent() != DefMI->getParent() ||
!isKill || HasOtherRegSequenceUses(SrcReg, MI, MRI) ||
!TRI->getMatchingSuperRegClass(MRI->getRegClass(DstReg),
MRI->getRegClass(SrcReg), SubIdx)) {
if (isKill)
for (unsigned j = i + 2; j < e; j += 2)
if (MI->getOperand(j).getReg() == SrcReg) {
MI->getOperand(j).setIsKill();
isKill = false;
break;
}
MachineBasicBlock::iterator InsertLoc = MI;
MachineInstr *CopyMI = BuildMI(*MI->getParent(), InsertLoc,
MI->getDebugLoc(), TII->get(TargetOpcode::COPY))
.addReg(DstReg, RegState::Define, SubIdx)
.addReg(SrcReg, getKillRegState(isKill));
MI->getOperand(i).setReg(0);
if (LV && isKill && !TargetRegisterInfo::isPhysicalRegister(SrcReg))
LV->replaceKillInstruction(SrcReg, MI, CopyMI);
DEBUG(dbgs() << "Inserted: " << *CopyMI);
}
}
for (unsigned i = 1, e = MI->getNumOperands(); i < e; i += 2) {
unsigned SrcReg = MI->getOperand(i).getReg();
if (!SrcReg) continue;
unsigned SubIdx = MI->getOperand(i+1).getImm();
UpdateRegSequenceSrcs(SrcReg, DstReg, SubIdx, MRI, *TRI);
}
if (MachineInstr *Def = findFirstDef(DstReg, MRI)) {
for (unsigned i = 0, e = Def->getNumOperands(); i != e; ++i) {
MachineOperand &MO = Def->getOperand(i);
if (MO.isReg() && MO.isDef() && MO.getReg() == DstReg)
MO.setIsUndef();
}
Def->addRegisterDefined(DstReg, TRI);
DEBUG(dbgs() << "First def: " << *Def);
}
if (IsImpDef) {
DEBUG(dbgs() << "Turned: " << *MI << " into an IMPLICIT_DEF");
MI->setDesc(TII->get(TargetOpcode::IMPLICIT_DEF));
for (int j = MI->getNumOperands() - 1, ee = 0; j > ee; --j)
MI->RemoveOperand(j);
} else {
DEBUG(dbgs() << "Eliminated: " << *MI);
MI->eraseFromParent();
}
if (LV)
CoalesceExtSubRegs(RealSrcs, DstReg);
}
RegSequences.clear();
return true;
}