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/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");
namespace {
class TwoAddressInstructionPass : public MachineFunctionPass {
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MachineRegisterInfo *MRI;
LiveVariables *LV;
AliasAnalysis *AA;
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 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);
AU.addPreservedID(PHIEliminationID);
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)
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 TargetInstrDesc &TID = UseMI->getDesc();
for (unsigned i = 0, e = TID.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 TargetInstrDesc &TID = MI.getDesc();
unsigned NumOps = MI.isInlineAsm() ? MI.getNumOperands():TID.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 *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 (!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) {
const TargetInstrDesc &TID = MI->getDesc();
if (TID.mayStore() || TID.isCall())
return false;
if (TID.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::
TryInstructionTransform(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
MachineFunction::iterator &mbbi,
unsigned SrcIdx, unsigned DstIdx, unsigned Dist,
SmallPtrSet<MachineInstr*, 8> &Processed) {
const TargetInstrDesc &TID = mi->getDesc();
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 (TID.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 (TargetRegisterInfo::isVirtualRegister(regA))
ScanUses(regA, &*mbbi, Processed);
if (TID.isConvertibleTo3Addr()) {
if (!regBKilled || isProfitableToConv3Addr(regA, regB)) {
if (ConvertInstTo3Addr(mi, nmi, mbbi, regA, regB, Dist)) {
++NumConvertedTo3Addr;
return true; }
}
}
if (TID.mayLoad() && !regBKilled) {
unsigned LoadRegIndex;
unsigned NewOpc =
TII->getOpcodeAfterMemoryUnfold(mi->getOpcode(),
true,
false,
&LoadRegIndex);
if (NewOpc != 0) {
const TargetInstrDesc &UnfoldTID = TII->get(NewOpc);
if (UnfoldTID.getNumDefs() == 1) {
MachineFunction &MF = *mbbi->getParent();
DEBUG(dbgs() << "2addr: UNFOLDING: " << *mi);
const TargetRegisterClass *RC =
UnfoldTID.OpInfo[LoadRegIndex].getRegClass(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();
LV = getAnalysisIfAvailable<LiveVariables>();
AA = &getAnalysis<AliasAnalysis>();
bool MadeChange = false;
DEBUG(dbgs() << "********** REWRITING TWO-ADDR INSTRS **********\n");
DEBUG(dbgs() << "********** Function: "
<< MF.getFunction()->getName() << '\n');
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 TargetInstrDesc &TID = mi->getDesc();
bool FirstTied = true;
DistanceMap.insert(std::make_pair(mi, ++Dist));
ProcessCopy(&*mi, &*mbbi, Processed);
unsigned NumOps = mi->isInlineAsm()
? mi->getNumOperands() : TID.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();
TiedOperandMap::iterator OI = TiedOperands.find(regB);
if (OI == TiedOperands.end()) {
SmallVector<std::pair<unsigned, unsigned>, 4> TiedPair;
OI = TiedOperands.insert(std::make_pair(regB, TiedPair)).first;
}
OI->second.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 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;
unsigned regA = mi->getOperand(DstIdx).getReg();
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->getDesc().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) {
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);
}
}
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;
}
SomeMI = UseMI;
}
if (!CanCoalesce)
continue;
MachineInstr *CopyMI = BuildMI(*SomeMI->getParent(), SomeMI,
SomeMI->getDebugLoc(),
TII->get(TargetOpcode::COPY))
.addReg(DstReg, RegState::Define, 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();
if (MI->getOperand(i).getSubReg() ||
TargetRegisterInfo::isPhysicalRegister(SrcReg)) {
DEBUG(dbgs() << "Illegal REG_SEQUENCE instruction:" << *MI);
llvm_unreachable(0);
}
MachineInstr *DefMI = MRI->getVRegDef(SrcReg);
if (DefMI->isImplicitDef()) {
DefMI->eraseFromParent();
continue;
}
IsImpDef = false;
if (DefMI->isCopy() && DefMI->getOperand(1).getSubReg())
RealSrcs.push_back(DefMI->getOperand(1).getReg());
bool isKill = MI->getOperand(i).isKill();
if (!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)
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 (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;
}