#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <cassert>
#include <iterator>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "twoaddressinstruction"
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(NumReSchedUps, "Number of instructions re-scheduled up");
STATISTIC(NumReSchedDowns, "Number of instructions re-scheduled down");
static cl::opt<bool>
EnableRescheduling("twoaddr-reschedule",
cl::desc("Coalesce copies by rescheduling (default=true)"),
cl::init(true), cl::Hidden);
static cl::opt<unsigned> MaxDataFlowEdge(
"dataflow-edge-limit", cl::Hidden, cl::init(3),
cl::desc("Maximum number of dataflow edges to traverse when evaluating "
"the benefit of commuting operands"));
namespace {
class TwoAddressInstructionPass : public MachineFunctionPass {
MachineFunction *MF;
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
const InstrItineraryData *InstrItins;
MachineRegisterInfo *MRI;
LiveVariables *LV;
LiveIntervals *LIS;
AliasAnalysis *AA;
CodeGenOpt::Level OptLevel;
MachineBasicBlock *MBB;
DenseMap<MachineInstr*, unsigned> DistanceMap;
SmallPtrSet<MachineInstr*, 8> Processed;
DenseMap<Register, Register> SrcRegMap;
DenseMap<Register, Register> DstRegMap;
void removeClobberedSrcRegMap(MachineInstr *MI);
bool isRevCopyChain(Register FromReg, Register ToReg, int Maxlen);
bool noUseAfterLastDef(Register Reg, unsigned Dist, unsigned &LastDef);
bool isProfitableToCommute(Register RegA, Register RegB, Register RegC,
MachineInstr *MI, unsigned Dist);
bool commuteInstruction(MachineInstr *MI, unsigned DstIdx,
unsigned RegBIdx, unsigned RegCIdx, unsigned Dist);
bool isProfitableToConv3Addr(Register RegA, Register RegB);
bool convertInstTo3Addr(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi, Register RegA,
Register RegB, unsigned &Dist);
bool isDefTooClose(Register Reg, unsigned Dist, MachineInstr *MI);
bool rescheduleMIBelowKill(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi, Register Reg);
bool rescheduleKillAboveMI(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi, Register Reg);
bool tryInstructionTransform(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned SrcIdx, unsigned DstIdx,
unsigned &Dist, bool shouldOnlyCommute);
bool tryInstructionCommute(MachineInstr *MI,
unsigned DstOpIdx,
unsigned BaseOpIdx,
bool BaseOpKilled,
unsigned Dist);
void scanUses(Register DstReg);
void processCopy(MachineInstr *MI);
using TiedPairList = SmallVector<std::pair<unsigned, unsigned>, 4>;
using TiedOperandMap = SmallDenseMap<unsigned, TiedPairList>;
bool collectTiedOperands(MachineInstr *MI, TiedOperandMap&);
void processTiedPairs(MachineInstr *MI, TiedPairList&, unsigned &Dist);
void eliminateRegSequence(MachineBasicBlock::iterator&);
bool processStatepoint(MachineInstr *MI, TiedOperandMap &TiedOperands);
public:
static char ID;
TwoAddressInstructionPass() : MachineFunctionPass(ID) {
initializeTwoAddressInstructionPassPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
AU.addUsedIfAvailable<AAResultsWrapperPass>();
AU.addUsedIfAvailable<LiveVariables>();
AU.addPreserved<LiveVariables>();
AU.addPreserved<SlotIndexes>();
AU.addPreserved<LiveIntervals>();
AU.addPreservedID(MachineLoopInfoID);
AU.addPreservedID(MachineDominatorsID);
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction&) override;
};
}
char TwoAddressInstructionPass::ID = 0;
char &llvm::TwoAddressInstructionPassID = TwoAddressInstructionPass::ID;
INITIALIZE_PASS_BEGIN(TwoAddressInstructionPass, DEBUG_TYPE,
"Two-Address instruction pass", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(TwoAddressInstructionPass, DEBUG_TYPE,
"Two-Address instruction pass", false, false)
static bool isPlainlyKilled(MachineInstr *MI, Register Reg, LiveIntervals *LIS);
static MachineInstr *getSingleDef(Register Reg, MachineBasicBlock *BB,
const MachineRegisterInfo *MRI) {
MachineInstr *Ret = nullptr;
for (MachineInstr &DefMI : MRI->def_instructions(Reg)) {
if (DefMI.getParent() != BB || DefMI.isDebugValue())
continue;
if (!Ret)
Ret = &DefMI;
else if (Ret != &DefMI)
return nullptr;
}
return Ret;
}
bool TwoAddressInstructionPass::isRevCopyChain(Register FromReg, Register ToReg,
int Maxlen) {
Register TmpReg = FromReg;
for (int i = 0; i < Maxlen; i++) {
MachineInstr *Def = getSingleDef(TmpReg, MBB, MRI);
if (!Def || !Def->isCopy())
return false;
TmpReg = Def->getOperand(1).getReg();
if (TmpReg == ToReg)
return true;
}
return false;
}
bool TwoAddressInstructionPass::noUseAfterLastDef(Register Reg, unsigned Dist,
unsigned &LastDef) {
LastDef = 0;
unsigned LastUse = Dist;
for (MachineOperand &MO : MRI->reg_operands(Reg)) {
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);
}
static bool isCopyToReg(MachineInstr &MI, const TargetInstrInfo *TII,
Register &SrcReg, Register &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 = SrcReg.isPhysical();
IsDstPhys = DstReg.isPhysical();
return true;
}
static bool isPlainlyKilled(MachineInstr *MI, Register Reg,
LiveIntervals *LIS) {
if (LIS && Reg.isVirtual() && !LIS->isNotInMIMap(*MI)) {
LiveInterval &LI = LIS->getInterval(Reg);
if (!LI.hasAtLeastOneValue())
return false;
SlotIndex useIdx = LIS->getInstructionIndex(*MI);
LiveInterval::const_iterator I = LI.find(useIdx);
assert(I != LI.end() && "Reg must be live-in to use.");
return !I->end.isBlock() && SlotIndex::isSameInstr(I->end, useIdx);
}
return MI->killsRegister(Reg);
}
static bool isKilled(MachineInstr &MI, Register Reg,
const MachineRegisterInfo *MRI, const TargetInstrInfo *TII,
LiveIntervals *LIS, bool allowFalsePositives) {
MachineInstr *DefMI = &MI;
while (true) {
if (Reg.isPhysical() && (allowFalsePositives || MRI->hasOneUse(Reg)))
return true;
if (!isPlainlyKilled(DefMI, Reg, LIS))
return false;
if (Reg.isPhysical())
return true;
MachineRegisterInfo::def_iterator Begin = MRI->def_begin(Reg);
if (std::next(Begin) != MRI->def_end())
return true;
DefMI = Begin->getParent();
bool IsSrcPhys, IsDstPhys;
Register SrcReg, DstReg;
if (!isCopyToReg(*DefMI, TII, SrcReg, DstReg, IsSrcPhys, IsDstPhys))
return true;
Reg = SrcReg;
}
}
static bool isTwoAddrUse(MachineInstr &MI, Register Reg, Register &DstReg) {
for (unsigned i = 0, NumOps = MI.getNumOperands(); 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(Register Reg, MachineBasicBlock *MBB,
MachineRegisterInfo *MRI, const TargetInstrInfo *TII,
bool &IsCopy, Register &DstReg, bool &IsDstPhys,
LiveIntervals *LIS) {
MachineOperand *UseOp = nullptr;
for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {
MachineInstr *MI = MO.getParent();
if (MI->getParent() != MBB)
return nullptr;
if (isPlainlyKilled(MI, Reg, LIS))
UseOp = &MO;
}
if (!UseOp)
return nullptr;
MachineInstr &UseMI = *UseOp->getParent();
Register SrcReg;
bool IsSrcPhys;
if (isCopyToReg(UseMI, TII, SrcReg, DstReg, IsSrcPhys, IsDstPhys)) {
IsCopy = true;
return &UseMI;
}
IsDstPhys = false;
if (isTwoAddrUse(UseMI, Reg, DstReg)) {
IsDstPhys = DstReg.isPhysical();
return &UseMI;
}
if (UseMI.isCommutable()) {
unsigned Src1 = TargetInstrInfo::CommuteAnyOperandIndex;
unsigned Src2 = UseMI.getOperandNo(UseOp);
if (TII->findCommutedOpIndices(UseMI, Src1, Src2)) {
MachineOperand &MO = UseMI.getOperand(Src1);
if (MO.isReg() && MO.isUse() &&
isTwoAddrUse(UseMI, MO.getReg(), DstReg)) {
IsDstPhys = DstReg.isPhysical();
return &UseMI;
}
}
}
return nullptr;
}
static MCRegister getMappedReg(Register Reg,
DenseMap<Register, Register> &RegMap) {
while (Reg.isVirtual()) {
DenseMap<Register, Register>::iterator SI = RegMap.find(Reg);
if (SI == RegMap.end())
return 0;
Reg = SI->second;
}
if (Reg.isPhysical())
return Reg;
return 0;
}
static bool regsAreCompatible(Register RegA, Register RegB,
const TargetRegisterInfo *TRI) {
if (RegA == RegB)
return true;
if (!RegA || !RegB)
return false;
return TRI->regsOverlap(RegA, RegB);
}
static void removeMapRegEntry(const MachineOperand &MO,
DenseMap<Register, Register> &RegMap,
const TargetRegisterInfo *TRI) {
assert(
(MO.isReg() || MO.isRegMask()) &&
"removeMapRegEntry must be called with a register or regmask operand.");
SmallVector<Register, 2> Srcs;
for (auto SI : RegMap) {
Register ToReg = SI.second;
if (ToReg.isVirtual())
continue;
if (MO.isReg()) {
Register Reg = MO.getReg();
if (TRI->regsOverlap(ToReg, Reg))
Srcs.push_back(SI.first);
} else if (MO.clobbersPhysReg(ToReg))
Srcs.push_back(SI.first);
}
for (auto SrcReg : Srcs)
RegMap.erase(SrcReg);
}
void TwoAddressInstructionPass::removeClobberedSrcRegMap(MachineInstr *MI) {
if (MI->isCopy()) {
Register Dst = MI->getOperand(0).getReg();
if (!Dst || Dst.isVirtual())
return;
Register Src = MI->getOperand(1).getReg();
if (regsAreCompatible(Dst, getMappedReg(Src, SrcRegMap), TRI))
return;
}
for (const MachineOperand &MO : MI->operands()) {
if (MO.isRegMask()) {
removeMapRegEntry(MO, SrcRegMap, TRI);
continue;
}
if (!MO.isReg() || !MO.isDef())
continue;
Register Reg = MO.getReg();
if (!Reg || Reg.isVirtual())
continue;
removeMapRegEntry(MO, SrcRegMap, TRI);
}
}
static bool regOverlapsSet(const SmallVectorImpl<Register> &Set, Register Reg,
const TargetRegisterInfo *TRI) {
for (unsigned R : Set)
if (TRI->regsOverlap(R, Reg))
return true;
return false;
}
bool TwoAddressInstructionPass::isProfitableToCommute(Register RegA,
Register RegB,
Register RegC,
MachineInstr *MI,
unsigned Dist) {
if (OptLevel == CodeGenOpt::None)
return false;
if (!isPlainlyKilled(MI, RegC, LIS))
return false;
MCRegister ToRegA = getMappedReg(RegA, DstRegMap);
if (ToRegA) {
MCRegister FromRegB = getMappedReg(RegB, SrcRegMap);
MCRegister FromRegC = getMappedReg(RegC, SrcRegMap);
bool CompB = FromRegB && regsAreCompatible(FromRegB, ToRegA, TRI);
bool CompC = FromRegC && regsAreCompatible(FromRegC, ToRegA, TRI);
if ((!FromRegB && CompC) || (FromRegB && !CompB && (!FromRegC || CompC)))
return true;
if ((!FromRegC && CompB) || (FromRegC && !CompC && (!FromRegB || CompB)))
return false;
}
unsigned LastDefC = 0;
if (!noUseAfterLastDef(RegC, Dist, LastDefC))
return false;
unsigned LastDefB = 0;
if (!noUseAfterLastDef(RegB, Dist, LastDefB))
return true;
if (isRevCopyChain(RegC, RegA, MaxDataFlowEdge))
return true;
if (isRevCopyChain(RegB, RegA, MaxDataFlowEdge))
return false;
bool Commute;
if (TII->hasCommutePreference(*MI, Commute))
return Commute;
return LastDefB && LastDefC && LastDefC > LastDefB;
}
bool TwoAddressInstructionPass::commuteInstruction(MachineInstr *MI,
unsigned DstIdx,
unsigned RegBIdx,
unsigned RegCIdx,
unsigned Dist) {
Register RegC = MI->getOperand(RegCIdx).getReg();
LLVM_DEBUG(dbgs() << "2addr: COMMUTING : " << *MI);
MachineInstr *NewMI = TII->commuteInstruction(*MI, false, RegBIdx, RegCIdx);
if (NewMI == nullptr) {
LLVM_DEBUG(dbgs() << "2addr: COMMUTING FAILED!\n");
return false;
}
LLVM_DEBUG(dbgs() << "2addr: COMMUTED TO: " << *NewMI);
assert(NewMI == MI &&
"TargetInstrInfo::commuteInstruction() should not return a new "
"instruction unless it was requested.");
MCRegister FromRegC = getMappedReg(RegC, SrcRegMap);
if (FromRegC) {
Register RegA = MI->getOperand(DstIdx).getReg();
SrcRegMap[RegA] = FromRegC;
}
return true;
}
bool TwoAddressInstructionPass::isProfitableToConv3Addr(Register RegA,
Register RegB) {
MCRegister FromRegB = getMappedReg(RegB, SrcRegMap);
if (!FromRegB)
return false;
MCRegister ToRegA = getMappedReg(RegA, DstRegMap);
return (ToRegA && !regsAreCompatible(FromRegB, ToRegA, TRI));
}
bool TwoAddressInstructionPass::convertInstTo3Addr(
MachineBasicBlock::iterator &mi, MachineBasicBlock::iterator &nmi,
Register RegA, Register RegB, unsigned &Dist) {
MachineInstrSpan MIS(mi, MBB);
MachineInstr *NewMI = TII->convertToThreeAddress(*mi, LV, LIS);
if (!NewMI)
return false;
LLVM_DEBUG(dbgs() << "2addr: CONVERTING 2-ADDR: " << *mi);
LLVM_DEBUG(dbgs() << "2addr: TO 3-ADDR: " << *NewMI);
if (auto OldInstrNum = mi->peekDebugInstrNum()) {
assert(mi->getNumExplicitDefs() == 1);
assert(NewMI->getNumExplicitDefs() == 1);
auto OldIt = mi->defs().begin();
auto NewIt = NewMI->defs().begin();
unsigned OldIdx = mi->getOperandNo(OldIt);
unsigned NewIdx = NewMI->getOperandNo(NewIt);
unsigned NewInstrNum = NewMI->getDebugInstrNum();
MF->makeDebugValueSubstitution(std::make_pair(OldInstrNum, OldIdx),
std::make_pair(NewInstrNum, NewIdx));
}
MBB->erase(mi);
for (MachineInstr &MI : MIS)
DistanceMap.insert(std::make_pair(&MI, Dist++));
Dist--;
mi = NewMI;
nmi = std::next(mi);
SrcRegMap.erase(RegA);
DstRegMap.erase(RegB);
return true;
}
void TwoAddressInstructionPass::scanUses(Register DstReg) {
SmallVector<Register, 4> VirtRegPairs;
bool IsDstPhys;
bool IsCopy = false;
Register NewReg;
Register Reg = DstReg;
while (MachineInstr *UseMI = findOnlyInterestingUse(Reg, MBB, MRI, TII,IsCopy,
NewReg, IsDstPhys, LIS)) {
if (IsCopy && !Processed.insert(UseMI).second)
break;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(UseMI);
if (DI != DistanceMap.end())
break;
if (IsDstPhys) {
VirtRegPairs.push_back(NewReg);
break;
}
SrcRegMap[NewReg] = Reg;
VirtRegPairs.push_back(NewReg);
Reg = NewReg;
}
if (!VirtRegPairs.empty()) {
unsigned ToReg = VirtRegPairs.back();
VirtRegPairs.pop_back();
while (!VirtRegPairs.empty()) {
unsigned FromReg = VirtRegPairs.pop_back_val();
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) {
if (Processed.count(MI))
return;
bool IsSrcPhys, IsDstPhys;
Register 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);
}
Processed.insert(MI);
}
bool TwoAddressInstructionPass::rescheduleMIBelowKill(
MachineBasicBlock::iterator &mi, MachineBasicBlock::iterator &nmi,
Register Reg) {
if (!LV && !LIS)
return false;
MachineInstr *MI = &*mi;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
return false;
MachineInstr *KillMI = nullptr;
if (LIS) {
LiveInterval &LI = LIS->getInterval(Reg);
assert(LI.end() != LI.begin() &&
"Reg should not have empty live interval.");
SlotIndex MBBEndIdx = LIS->getMBBEndIdx(MBB).getPrevSlot();
LiveInterval::const_iterator I = LI.find(MBBEndIdx);
if (I != LI.end() && I->start < MBBEndIdx)
return false;
--I;
KillMI = LIS->getInstructionFromIndex(I->end);
} else {
KillMI = LV->getVarInfo(Reg).findKill(MBB);
}
if (!KillMI || MI == KillMI || KillMI->isCopy() || KillMI->isCopyLike())
return false;
if (KillMI->hasUnmodeledSideEffects() || KillMI->isCall() ||
KillMI->isBranch() || KillMI->isTerminator())
return false;
Register DstReg;
if (isTwoAddrUse(*KillMI, Reg, DstReg))
return false;
bool SeenStore = true;
if (!MI->isSafeToMove(AA, SeenStore))
return false;
if (TII->getInstrLatency(InstrItins, *MI) > 1)
return false;
SmallVector<Register, 2> Uses;
SmallVector<Register, 2> Kills;
SmallVector<Register, 2> Defs;
for (const MachineOperand &MO : MI->operands()) {
if (!MO.isReg())
continue;
Register MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isDef())
Defs.push_back(MOReg);
else {
Uses.push_back(MOReg);
if (MOReg != Reg && (MO.isKill() ||
(LIS && isPlainlyKilled(MI, MOReg, LIS))))
Kills.push_back(MOReg);
}
}
MachineBasicBlock::iterator Begin = MI;
MachineBasicBlock::iterator AfterMI = std::next(Begin);
MachineBasicBlock::iterator End = AfterMI;
while (End != MBB->end()) {
End = skipDebugInstructionsForward(End, MBB->end());
if (End->isCopy() && regOverlapsSet(Defs, End->getOperand(1).getReg(), TRI))
Defs.push_back(End->getOperand(0).getReg());
else
break;
++End;
}
unsigned NumVisited = 0;
MachineBasicBlock::iterator KillPos = KillMI;
++KillPos;
for (MachineInstr &OtherMI : make_range(End, KillPos)) {
if (OtherMI.isDebugOrPseudoInstr())
continue;
if (NumVisited > 10) return false;
++NumVisited;
if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() ||
OtherMI.isBranch() || OtherMI.isTerminator())
return false;
for (const MachineOperand &MO : OtherMI.operands()) {
if (!MO.isReg())
continue;
Register MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isDef()) {
if (regOverlapsSet(Uses, MOReg, TRI))
return false;
if (!MO.isDead() && regOverlapsSet(Defs, MOReg, TRI))
return false;
} else {
if (regOverlapsSet(Defs, MOReg, TRI))
return false;
bool isKill =
MO.isKill() || (LIS && isPlainlyKilled(&OtherMI, MOReg, LIS));
if (MOReg != Reg && ((isKill && regOverlapsSet(Uses, MOReg, TRI)) ||
regOverlapsSet(Kills, MOReg, TRI)))
return false;
if (MOReg == Reg && !isKill)
return false;
assert((MOReg != Reg || &OtherMI == KillMI) &&
"Found multiple kills of a register in a basic block");
}
}
}
while (Begin != MBB->begin() && std::prev(Begin)->isDebugInstr())
--Begin;
nmi = End;
MachineBasicBlock::iterator InsertPos = KillPos;
if (LIS) {
for (MachineBasicBlock::iterator MBBI = AfterMI; MBBI != End;) {
auto CopyMI = MBBI++;
MBB->splice(InsertPos, MBB, CopyMI);
if (!CopyMI->isDebugOrPseudoInstr())
LIS->handleMove(*CopyMI);
InsertPos = CopyMI;
}
End = std::next(MachineBasicBlock::iterator(MI));
}
MBB->splice(InsertPos, MBB, Begin, End);
DistanceMap.erase(DI);
if (LIS) {
LIS->handleMove(*MI);
} else {
LV->removeVirtualRegisterKilled(Reg, *KillMI);
LV->addVirtualRegisterKilled(Reg, *MI);
}
LLVM_DEBUG(dbgs() << "\trescheduled below kill: " << *KillMI);
return true;
}
bool TwoAddressInstructionPass::isDefTooClose(Register Reg, unsigned Dist,
MachineInstr *MI) {
for (MachineInstr &DefMI : MRI->def_instructions(Reg)) {
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) > (Dist - DefDist))
return true;
}
return false;
}
bool TwoAddressInstructionPass::rescheduleKillAboveMI(
MachineBasicBlock::iterator &mi, MachineBasicBlock::iterator &nmi,
Register Reg) {
if (!LV && !LIS)
return false;
MachineInstr *MI = &*mi;
DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(MI);
if (DI == DistanceMap.end())
return false;
MachineInstr *KillMI = nullptr;
if (LIS) {
LiveInterval &LI = LIS->getInterval(Reg);
assert(LI.end() != LI.begin() &&
"Reg should not have empty live interval.");
SlotIndex MBBEndIdx = LIS->getMBBEndIdx(MBB).getPrevSlot();
LiveInterval::const_iterator I = LI.find(MBBEndIdx);
if (I != LI.end() && I->start < MBBEndIdx)
return false;
--I;
KillMI = LIS->getInstructionFromIndex(I->end);
} else {
KillMI = LV->getVarInfo(Reg).findKill(MBB);
}
if (!KillMI || MI == KillMI || KillMI->isCopy() || KillMI->isCopyLike())
return false;
Register DstReg;
if (isTwoAddrUse(*KillMI, Reg, DstReg))
return false;
bool SeenStore = true;
if (!KillMI->isSafeToMove(AA, SeenStore))
return false;
SmallVector<Register, 2> Uses;
SmallVector<Register, 2> Kills;
SmallVector<Register, 2> Defs;
SmallVector<Register, 2> LiveDefs;
for (const MachineOperand &MO : KillMI->operands()) {
if (!MO.isReg())
continue;
Register MOReg = MO.getReg();
if (MO.isUse()) {
if (!MOReg)
continue;
if (isDefTooClose(MOReg, DI->second, MI))
return false;
bool isKill = MO.isKill() || (LIS && isPlainlyKilled(KillMI, MOReg, LIS));
if (MOReg == Reg && !isKill)
return false;
Uses.push_back(MOReg);
if (isKill && MOReg != Reg)
Kills.push_back(MOReg);
} else if (MOReg.isPhysical()) {
Defs.push_back(MOReg);
if (!MO.isDead())
LiveDefs.push_back(MOReg);
}
}
unsigned NumVisited = 0;
for (MachineInstr &OtherMI :
make_range(mi, MachineBasicBlock::iterator(KillMI))) {
if (OtherMI.isDebugOrPseudoInstr())
continue;
if (NumVisited > 10) return false;
++NumVisited;
if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() ||
OtherMI.isBranch() || OtherMI.isTerminator())
return false;
SmallVector<Register, 2> OtherDefs;
for (const MachineOperand &MO : OtherMI.operands()) {
if (!MO.isReg())
continue;
Register MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isUse()) {
if (regOverlapsSet(Defs, MOReg, TRI))
return false;
if (regOverlapsSet(Kills, MOReg, TRI))
return false;
if (&OtherMI != MI && MOReg == Reg &&
!(MO.isKill() || (LIS && isPlainlyKilled(&OtherMI, MOReg, LIS))))
return false;
} else {
OtherDefs.push_back(MOReg);
}
}
for (unsigned i = 0, e = OtherDefs.size(); i != e; ++i) {
Register MOReg = OtherDefs[i];
if (regOverlapsSet(Uses, MOReg, TRI))
return false;
if (MOReg.isPhysical() && regOverlapsSet(LiveDefs, MOReg, TRI))
return false;
llvm::erase_value(Defs, MOReg);
}
}
MachineBasicBlock::iterator InsertPos = mi;
while (InsertPos != MBB->begin() && std::prev(InsertPos)->isDebugInstr())
--InsertPos;
MachineBasicBlock::iterator From = KillMI;
MachineBasicBlock::iterator To = std::next(From);
while (std::prev(From)->isDebugInstr())
--From;
MBB->splice(InsertPos, MBB, From, To);
nmi = std::prev(InsertPos); DistanceMap.erase(DI);
if (LIS) {
LIS->handleMove(*KillMI);
} else {
LV->removeVirtualRegisterKilled(Reg, *KillMI);
LV->addVirtualRegisterKilled(Reg, *MI);
}
LLVM_DEBUG(dbgs() << "\trescheduled kill: " << *KillMI);
return true;
}
bool TwoAddressInstructionPass::tryInstructionCommute(MachineInstr *MI,
unsigned DstOpIdx,
unsigned BaseOpIdx,
bool BaseOpKilled,
unsigned Dist) {
if (!MI->isCommutable())
return false;
bool MadeChange = false;
Register DstOpReg = MI->getOperand(DstOpIdx).getReg();
Register BaseOpReg = MI->getOperand(BaseOpIdx).getReg();
unsigned OpsNum = MI->getDesc().getNumOperands();
unsigned OtherOpIdx = MI->getDesc().getNumDefs();
for (; OtherOpIdx < OpsNum; OtherOpIdx++) {
if (OtherOpIdx == BaseOpIdx || !MI->getOperand(OtherOpIdx).isReg() ||
!TII->findCommutedOpIndices(*MI, BaseOpIdx, OtherOpIdx))
continue;
Register OtherOpReg = MI->getOperand(OtherOpIdx).getReg();
bool AggressiveCommute = false;
bool OtherOpKilled = isKilled(*MI, OtherOpReg, MRI, TII, LIS, false);
bool DoCommute = !BaseOpKilled && OtherOpKilled;
if (!DoCommute &&
isProfitableToCommute(DstOpReg, BaseOpReg, OtherOpReg, MI, Dist)) {
DoCommute = true;
AggressiveCommute = true;
}
if (DoCommute && commuteInstruction(MI, DstOpIdx, BaseOpIdx, OtherOpIdx,
Dist)) {
MadeChange = true;
++NumCommuted;
if (AggressiveCommute)
++NumAggrCommuted;
BaseOpReg = OtherOpReg;
BaseOpKilled = OtherOpKilled;
OpsNum = MI->getDesc().getNumOperands();
}
}
return MadeChange;
}
bool TwoAddressInstructionPass::
tryInstructionTransform(MachineBasicBlock::iterator &mi,
MachineBasicBlock::iterator &nmi,
unsigned SrcIdx, unsigned DstIdx,
unsigned &Dist, bool shouldOnlyCommute) {
if (OptLevel == CodeGenOpt::None)
return false;
MachineInstr &MI = *mi;
Register regA = MI.getOperand(DstIdx).getReg();
Register regB = MI.getOperand(SrcIdx).getReg();
assert(regB.isVirtual() && "cannot make instruction into two-address form");
bool regBKilled = isKilled(MI, regB, MRI, TII, LIS, true);
if (regA.isVirtual())
scanUses(regA);
bool Commuted = tryInstructionCommute(&MI, DstIdx, SrcIdx, regBKilled, Dist);
if (Commuted && !MI.isConvertibleTo3Addr())
return false;
if (shouldOnlyCommute)
return false;
if (!Commuted && EnableRescheduling && rescheduleMIBelowKill(mi, nmi, regB)) {
++NumReSchedDowns;
return true;
}
if (Commuted) {
regB = MI.getOperand(SrcIdx).getReg();
regBKilled = isKilled(MI, regB, MRI, TII, LIS, true);
}
if (MI.isConvertibleTo3Addr()) {
if (!regBKilled || isProfitableToConv3Addr(regA, regB)) {
if (convertInstTo3Addr(mi, nmi, regA, regB, Dist)) {
++NumConvertedTo3Addr;
return true; }
}
}
if (Commuted)
return false;
if (EnableRescheduling && rescheduleKillAboveMI(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) {
LLVM_DEBUG(dbgs() << "2addr: UNFOLDING: " << MI);
const TargetRegisterClass *RC =
TRI->getAllocatableClass(
TII->getRegClass(UnfoldMCID, LoadRegIndex, TRI, *MF));
Register Reg = MRI->createVirtualRegister(RC);
SmallVector<MachineInstr *, 2> NewMIs;
if (!TII->unfoldMemoryOperand(*MF, MI, Reg,
true,
false, NewMIs)) {
LLVM_DEBUG(dbgs() << "2addr: ABANDONING UNFOLD\n");
return false;
}
assert(NewMIs.size() == 2 &&
"Unfolded a load into multiple instructions!");
NewMIs[1]->addRegisterKilled(Reg, TRI);
MBB->insert(mi, NewMIs[0]);
MBB->insert(mi, NewMIs[1]);
DistanceMap.insert(std::make_pair(NewMIs[0], Dist++));
DistanceMap.insert(std::make_pair(NewMIs[1], Dist));
LLVM_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 TransformResult =
tryInstructionTransform(NewMI, mi, NewSrcIdx, NewDstIdx, Dist, true);
(void)TransformResult;
assert(!TransformResult &&
"tryInstructionTransform() should return false.");
if (NewMIs[1]->getOperand(NewSrcIdx).isKill()) {
if (LV) {
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg() && MO.getReg().isVirtual()) {
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]);
}
SmallVector<Register, 4> OrigRegs;
if (LIS) {
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg())
OrigRegs.push_back(MO.getReg());
}
LIS->RemoveMachineInstrFromMaps(MI);
}
MI.eraseFromParent();
DistanceMap.erase(&MI);
if (LIS) {
MachineBasicBlock::iterator Begin(NewMIs[0]);
MachineBasicBlock::iterator End(NewMIs[1]);
LIS->repairIntervalsInRange(MBB, Begin, End, OrigRegs);
}
mi = NewMIs[1];
} else {
LLVM_DEBUG(dbgs() << "2addr: ABANDONING UNFOLD\n");
NewMIs[0]->eraseFromParent();
NewMIs[1]->eraseFromParent();
DistanceMap.erase(NewMIs[0]);
DistanceMap.erase(NewMIs[1]);
Dist--;
}
}
}
}
return false;
}
bool TwoAddressInstructionPass::
collectTiedOperands(MachineInstr *MI, TiedOperandMap &TiedOperands) {
bool AnyOps = false;
unsigned NumOps = MI->getNumOperands();
for (unsigned SrcIdx = 0; SrcIdx < NumOps; ++SrcIdx) {
unsigned DstIdx = 0;
if (!MI->isRegTiedToDefOperand(SrcIdx, &DstIdx))
continue;
AnyOps = true;
MachineOperand &SrcMO = MI->getOperand(SrcIdx);
MachineOperand &DstMO = MI->getOperand(DstIdx);
Register SrcReg = SrcMO.getReg();
Register DstReg = DstMO.getReg();
if (SrcReg == DstReg)
continue;
assert(SrcReg && SrcMO.isUse() && "two address instruction invalid");
if (SrcMO.isUndef() && !DstMO.getSubReg()) {
if (DstReg.isVirtual()) {
const TargetRegisterClass *RC = MRI->getRegClass(SrcReg);
MRI->constrainRegClass(DstReg, RC);
}
SrcMO.setReg(DstReg);
SrcMO.setSubReg(0);
LLVM_DEBUG(dbgs() << "\t\trewrite undef:\t" << *MI);
continue;
}
TiedOperands[SrcReg].push_back(std::make_pair(SrcIdx, DstIdx));
}
return AnyOps;
}
void
TwoAddressInstructionPass::processTiedPairs(MachineInstr *MI,
TiedPairList &TiedPairs,
unsigned &Dist) {
bool IsEarlyClobber = llvm::any_of(TiedPairs, [MI](auto const &TP) {
return MI->getOperand(TP.second).isEarlyClobber();
});
bool RemovedKillFlag = false;
bool AllUsesCopied = true;
unsigned LastCopiedReg = 0;
SlotIndex LastCopyIdx;
Register RegB = 0;
unsigned SubRegB = 0;
for (auto &TP : TiedPairs) {
unsigned SrcIdx = TP.first;
unsigned DstIdx = TP.second;
const MachineOperand &DstMO = MI->getOperand(DstIdx);
Register RegA = DstMO.getReg();
RegB = MI->getOperand(SrcIdx).getReg();
SubRegB = MI->getOperand(SrcIdx).getSubReg();
if (RegA == RegB) {
AllUsesCopied = false;
continue;
}
LastCopiedReg = RegA;
assert(RegB.isVirtual() && "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
MachineInstrBuilder MIB = BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
TII->get(TargetOpcode::COPY), RegA);
MIB.addReg(RegB, 0, SubRegB);
const TargetRegisterClass *RC = MRI->getRegClass(RegB);
if (SubRegB) {
if (RegA.isVirtual()) {
assert(TRI->getMatchingSuperRegClass(RC, MRI->getRegClass(RegA),
SubRegB) &&
"tied subregister must be a truncation");
RC = nullptr;
} else {
assert(TRI->getMatchingSuperReg(RegA, SubRegB, MRI->getRegClass(RegB))
&& "tied subregister must be a truncation");
}
}
MachineBasicBlock::iterator PrevMI = MI;
--PrevMI;
DistanceMap.insert(std::make_pair(&*PrevMI, Dist));
DistanceMap[MI] = ++Dist;
if (LIS) {
LastCopyIdx = LIS->InsertMachineInstrInMaps(*PrevMI).getRegSlot();
SlotIndex endIdx =
LIS->getInstructionIndex(*MI).getRegSlot(IsEarlyClobber);
if (RegA.isVirtual()) {
LiveInterval &LI = LIS->getInterval(RegA);
VNInfo *VNI = LI.getNextValue(LastCopyIdx, LIS->getVNInfoAllocator());
LI.addSegment(LiveRange::Segment(LastCopyIdx, endIdx, VNI));
for (auto &S : LI.subranges()) {
VNI = S.getNextValue(LastCopyIdx, LIS->getVNInfoAllocator());
S.addSegment(LiveRange::Segment(LastCopyIdx, endIdx, VNI));
}
} else {
for (MCRegUnitIterator Unit(RegA, TRI); Unit.isValid(); ++Unit) {
if (LiveRange *LR = LIS->getCachedRegUnit(*Unit)) {
VNInfo *VNI =
LR->getNextValue(LastCopyIdx, LIS->getVNInfoAllocator());
LR->addSegment(LiveRange::Segment(LastCopyIdx, endIdx, VNI));
}
}
}
}
LLVM_DEBUG(dbgs() << "\t\tprepend:\t" << *MIB);
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;
}
if (RegA.isVirtual() && RegB.isVirtual())
MRI->constrainRegClass(RegA, RC);
MO.setReg(RegA);
MO.setSubReg(0);
}
if (AllUsesCopied) {
LaneBitmask RemainingUses = LaneBitmask::getNone();
for (MachineOperand &MO : MI->operands()) {
if (MO.isReg() && MO.getReg() == RegB && MO.isUse()) {
if (MO.getSubReg() == SubRegB && !IsEarlyClobber) {
if (MO.isKill()) {
MO.setIsKill(false);
RemovedKillFlag = true;
}
MO.setReg(LastCopiedReg);
MO.setSubReg(0);
} else {
RemainingUses |= TRI->getSubRegIndexLaneMask(MO.getSubReg());
}
}
}
if (RemovedKillFlag && RemainingUses.none() && LV &&
LV->getVarInfo(RegB).removeKill(*MI)) {
MachineBasicBlock::iterator PrevMI = MI;
--PrevMI;
LV->addVirtualRegisterKilled(RegB, *PrevMI);
}
if (RemovedKillFlag && RemainingUses.none())
SrcRegMap[LastCopiedReg] = RegB;
if (LIS) {
SlotIndex UseIdx = LIS->getInstructionIndex(*MI);
auto Shrink = [=](LiveRange &LR, LaneBitmask LaneMask) {
LiveRange::Segment *S = LR.getSegmentContaining(LastCopyIdx);
if (!S)
return true;
if ((LaneMask & RemainingUses).any())
return false;
if (S->end.getBaseIndex() != UseIdx)
return false;
S->end = LastCopyIdx;
return true;
};
LiveInterval &LI = LIS->getInterval(RegB);
bool ShrinkLI = true;
for (auto &S : LI.subranges())
ShrinkLI &= Shrink(S, S.LaneMask);
if (ShrinkLI)
Shrink(LI, LaneBitmask::getAll());
}
} else if (RemovedKillFlag) {
for (MachineOperand &MO : MI->operands()) {
if (MO.isReg() && MO.getReg() == RegB && MO.isUse()) {
MO.setIsKill(true);
break;
}
}
}
}
bool TwoAddressInstructionPass::processStatepoint(
MachineInstr *MI, TiedOperandMap &TiedOperands) {
bool NeedCopy = false;
for (auto &TO : TiedOperands) {
Register RegB = TO.first;
if (TO.second.size() != 1) {
NeedCopy = true;
continue;
}
unsigned SrcIdx = TO.second[0].first;
unsigned DstIdx = TO.second[0].second;
MachineOperand &DstMO = MI->getOperand(DstIdx);
Register RegA = DstMO.getReg();
assert(RegB == MI->getOperand(SrcIdx).getReg());
if (RegA == RegB)
continue;
MRI->replaceRegWith(RegA, RegB);
if (LIS) {
VNInfo::Allocator &A = LIS->getVNInfoAllocator();
LiveInterval &LI = LIS->getInterval(RegB);
for (auto &S : LIS->getInterval(RegA)) {
VNInfo *VNI = LI.getNextValue(S.start, A);
LiveRange::Segment NewSeg(S.start, S.end, VNI);
LI.addSegment(NewSeg);
}
LIS->removeInterval(RegA);
}
if (LV) {
if (MI->getOperand(SrcIdx).isKill())
LV->removeVirtualRegisterKilled(RegB, *MI);
LiveVariables::VarInfo &SrcInfo = LV->getVarInfo(RegB);
LiveVariables::VarInfo &DstInfo = LV->getVarInfo(RegA);
SrcInfo.AliveBlocks |= DstInfo.AliveBlocks;
for (auto *KillMI : DstInfo.Kills)
LV->addVirtualRegisterKilled(RegB, *KillMI, false);
}
}
return !NeedCopy;
}
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &Func) {
MF = &Func;
const TargetMachine &TM = MF->getTarget();
MRI = &MF->getRegInfo();
TII = MF->getSubtarget().getInstrInfo();
TRI = MF->getSubtarget().getRegisterInfo();
InstrItins = MF->getSubtarget().getInstrItineraryData();
LV = getAnalysisIfAvailable<LiveVariables>();
LIS = getAnalysisIfAvailable<LiveIntervals>();
if (auto *AAPass = getAnalysisIfAvailable<AAResultsWrapperPass>())
AA = &AAPass->getAAResults();
else
AA = nullptr;
OptLevel = TM.getOptLevel();
if (skipFunction(Func.getFunction()))
OptLevel = CodeGenOpt::None;
bool MadeChange = false;
LLVM_DEBUG(dbgs() << "********** REWRITING TWO-ADDR INSTRS **********\n");
LLVM_DEBUG(dbgs() << "********** Function: " << MF->getName() << '\n');
MRI->leaveSSA();
MF->getProperties()
.set(MachineFunctionProperties::Property::TiedOpsRewritten);
TiedOperandMap TiedOperands;
for (MachineBasicBlock &MBBI : *MF) {
MBB = &MBBI;
unsigned Dist = 0;
DistanceMap.clear();
SrcRegMap.clear();
DstRegMap.clear();
Processed.clear();
for (MachineBasicBlock::iterator mi = MBB->begin(), me = MBB->end();
mi != me; ) {
MachineBasicBlock::iterator nmi = std::next(mi);
if (mi->isDebugInstr()) {
mi = nmi;
continue;
}
if (mi->isRegSequence())
eliminateRegSequence(mi);
DistanceMap.insert(std::make_pair(&*mi, ++Dist));
processCopy(&*mi);
if (!collectTiedOperands(&*mi, TiedOperands)) {
removeClobberedSrcRegMap(&*mi);
mi = nmi;
continue;
}
++NumTwoAddressInstrs;
MadeChange = true;
LLVM_DEBUG(dbgs() << '\t' << *mi);
if (TiedOperands.size() == 1) {
SmallVectorImpl<std::pair<unsigned, unsigned>> &TiedPairs
= TiedOperands.begin()->second;
if (TiedPairs.size() == 1) {
unsigned SrcIdx = TiedPairs[0].first;
unsigned DstIdx = TiedPairs[0].second;
Register SrcReg = mi->getOperand(SrcIdx).getReg();
Register DstReg = mi->getOperand(DstIdx).getReg();
if (SrcReg != DstReg &&
tryInstructionTransform(mi, nmi, SrcIdx, DstIdx, Dist, false)) {
TiedOperands.clear();
removeClobberedSrcRegMap(&*mi);
mi = nmi;
continue;
}
}
}
if (mi->getOpcode() == TargetOpcode::STATEPOINT &&
processStatepoint(&*mi, TiedOperands)) {
TiedOperands.clear();
LLVM_DEBUG(dbgs() << "\t\trewrite to:\t" << *mi);
mi = nmi;
continue;
}
for (auto &TO : TiedOperands) {
processTiedPairs(&*mi, TO.second, Dist);
LLVM_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->getOperand(0).setIsUndef(mi->getOperand(1).isUndef());
mi->removeOperand(1);
mi->setDesc(TII->get(TargetOpcode::COPY));
LLVM_DEBUG(dbgs() << "\t\tconvert to:\t" << *mi);
if (LIS) {
Register Reg = mi->getOperand(0).getReg();
LiveInterval &LI = LIS->getInterval(Reg);
if (LI.hasSubRanges()) {
LaneBitmask LaneMask =
TRI->getSubRegIndexLaneMask(mi->getOperand(0).getSubReg());
SlotIndex Idx = LIS->getInstructionIndex(*mi);
for (auto &S : LI.subranges()) {
if ((S.LaneMask & LaneMask).none()) {
LiveRange::iterator UseSeg = S.FindSegmentContaining(Idx);
LiveRange::iterator DefSeg = std::next(UseSeg);
S.MergeValueNumberInto(DefSeg->valno, UseSeg->valno);
}
}
LIS->shrinkToUses(&LI);
} else {
LIS->removeInterval(Reg);
LIS->createAndComputeVirtRegInterval(Reg);
}
}
}
TiedOperands.clear();
removeClobberedSrcRegMap(&*mi);
mi = nmi;
}
}
return MadeChange;
}
void TwoAddressInstructionPass::
eliminateRegSequence(MachineBasicBlock::iterator &MBBI) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
if (MI.getOperand(0).getSubReg() || DstReg.isPhysical() ||
!(MI.getNumOperands() & 1)) {
LLVM_DEBUG(dbgs() << "Illegal REG_SEQUENCE instruction:" << MI);
llvm_unreachable(nullptr);
}
SmallVector<Register, 4> OrigRegs;
if (LIS) {
OrigRegs.push_back(MI.getOperand(0).getReg());
for (unsigned i = 1, e = MI.getNumOperands(); i < e; i += 2)
OrigRegs.push_back(MI.getOperand(i).getReg());
}
bool DefEmitted = false;
for (unsigned i = 1, e = MI.getNumOperands(); i < e; i += 2) {
MachineOperand &UseMO = MI.getOperand(i);
Register SrcReg = UseMO.getReg();
unsigned SubIdx = MI.getOperand(i+1).getImm();
if (UseMO.isUndef())
continue;
bool isKill = UseMO.isKill();
if (isKill)
for (unsigned j = i + 2; j < e; j += 2)
if (MI.getOperand(j).getReg() == SrcReg) {
MI.getOperand(j).setIsKill();
UseMO.setIsKill(false);
isKill = false;
break;
}
MachineInstr *CopyMI = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
TII->get(TargetOpcode::COPY))
.addReg(DstReg, RegState::Define, SubIdx)
.add(UseMO);
if (!DefEmitted) {
CopyMI->getOperand(0).setIsUndef(true);
MBBI = CopyMI;
}
DefEmitted = true;
if (LV && isKill && !SrcReg.isPhysical())
LV->replaceKillInstruction(SrcReg, MI, *CopyMI);
LLVM_DEBUG(dbgs() << "Inserted: " << *CopyMI);
}
MachineBasicBlock::iterator EndMBBI =
std::next(MachineBasicBlock::iterator(MI));
if (!DefEmitted) {
LLVM_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 {
if (LIS)
LIS->RemoveMachineInstrFromMaps(MI);
LLVM_DEBUG(dbgs() << "Eliminated: " << MI);
MI.eraseFromParent();
}
if (LIS)
LIS->repairIntervalsInRange(MBB, MBBI, EndMBBI, OrigRegs);
}