#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/ReachingDefAnalysis.h"
#include "llvm/CodeGen/RegisterClassInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
namespace llvm {
class BreakFalseDeps : public MachineFunctionPass {
private:
MachineFunction *MF;
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
RegisterClassInfo RegClassInfo;
std::vector<std::pair<MachineInstr *, unsigned>> UndefReads;
LivePhysRegs LiveRegSet;
ReachingDefAnalysis *RDA;
public:
static char ID;
BreakFalseDeps() : MachineFunctionPass(ID) {
initializeBreakFalseDepsPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<ReachingDefAnalysis>();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
private:
void processBasicBlock(MachineBasicBlock *MBB);
void processDefs(MachineInstr *MI);
bool pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx,
unsigned Pref);
bool shouldBreakDependence(MachineInstr *, unsigned OpIdx, unsigned Pref);
void processUndefReads(MachineBasicBlock *);
};
}
#define DEBUG_TYPE "break-false-deps"
char BreakFalseDeps::ID = 0;
INITIALIZE_PASS_BEGIN(BreakFalseDeps, DEBUG_TYPE, "BreakFalseDeps", false, false)
INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)
INITIALIZE_PASS_END(BreakFalseDeps, DEBUG_TYPE, "BreakFalseDeps", false, false)
FunctionPass *llvm::createBreakFalseDeps() { return new BreakFalseDeps(); }
bool BreakFalseDeps::pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx,
unsigned Pref) {
if (MI->isRegTiedToDefOperand(OpIdx))
return false;
MachineOperand &MO = MI->getOperand(OpIdx);
assert(MO.isUndef() && "Expected undef machine operand");
if (!MO.isRenamable())
return false;
MCRegister OriginalReg = MO.getReg().asMCReg();
for (MCRegUnitIterator Unit(OriginalReg, TRI); Unit.isValid(); ++Unit) {
unsigned NumRoots = 0;
for (MCRegUnitRootIterator Root(*Unit, TRI); Root.isValid(); ++Root) {
NumRoots++;
if (NumRoots > 1)
return false;
}
}
const TargetRegisterClass *OpRC =
TII->getRegClass(MI->getDesc(), OpIdx, TRI, *MF);
for (MachineOperand &CurrMO : MI->operands()) {
if (!CurrMO.isReg() || CurrMO.isDef() || CurrMO.isUndef() ||
!OpRC->contains(CurrMO.getReg()))
continue;
MO.setReg(CurrMO.getReg());
return true;
}
unsigned MaxClearance = 0;
unsigned MaxClearanceReg = OriginalReg;
ArrayRef<MCPhysReg> Order = RegClassInfo.getOrder(OpRC);
for (MCPhysReg Reg : Order) {
unsigned Clearance = RDA->getClearance(MI, Reg);
if (Clearance <= MaxClearance)
continue;
MaxClearance = Clearance;
MaxClearanceReg = Reg;
if (MaxClearance > Pref)
break;
}
if (MaxClearanceReg != OriginalReg)
MO.setReg(MaxClearanceReg);
return false;
}
bool BreakFalseDeps::shouldBreakDependence(MachineInstr *MI, unsigned OpIdx,
unsigned Pref) {
MCRegister Reg = MI->getOperand(OpIdx).getReg().asMCReg();
unsigned Clearance = RDA->getClearance(MI, Reg);
LLVM_DEBUG(dbgs() << "Clearance: " << Clearance << ", want " << Pref);
if (Pref > Clearance) {
LLVM_DEBUG(dbgs() << ": Break dependency.\n");
return true;
}
LLVM_DEBUG(dbgs() << ": OK .\n");
return false;
}
void BreakFalseDeps::processDefs(MachineInstr *MI) {
assert(!MI->isDebugInstr() && "Won't process debug values");
const MCInstrDesc &MCID = MI->getDesc();
for (unsigned i = MCID.getNumDefs(), e = MCID.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg() || !MO.getReg() || !MO.isUse() || !MO.isUndef())
continue;
unsigned Pref = TII->getUndefRegClearance(*MI, i, TRI);
if (Pref) {
bool HadTrueDependency = pickBestRegisterForUndef(MI, i, Pref);
if (!HadTrueDependency && shouldBreakDependence(MI, i, Pref))
UndefReads.push_back(std::make_pair(MI, i));
}
}
if (MF->getFunction().hasMinSize())
return;
for (unsigned i = 0,
e = MI->isVariadic() ? MI->getNumOperands() : MCID.getNumDefs();
i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg() || !MO.getReg())
continue;
if (MO.isUse())
continue;
unsigned Pref = TII->getPartialRegUpdateClearance(*MI, i, TRI);
if (Pref && shouldBreakDependence(MI, i, Pref))
TII->breakPartialRegDependency(*MI, i, TRI);
}
}
void BreakFalseDeps::processUndefReads(MachineBasicBlock *MBB) {
if (UndefReads.empty())
return;
if (MF->getFunction().hasMinSize())
return;
LiveRegSet.init(*TRI);
LiveRegSet.addLiveOutsNoPristines(*MBB);
MachineInstr *UndefMI = UndefReads.back().first;
unsigned OpIdx = UndefReads.back().second;
for (MachineInstr &I : llvm::reverse(*MBB)) {
LiveRegSet.stepBackward(I);
if (UndefMI == &I) {
if (!LiveRegSet.contains(UndefMI->getOperand(OpIdx).getReg()))
TII->breakPartialRegDependency(*UndefMI, OpIdx, TRI);
UndefReads.pop_back();
if (UndefReads.empty())
return;
UndefMI = UndefReads.back().first;
OpIdx = UndefReads.back().second;
}
}
}
void BreakFalseDeps::processBasicBlock(MachineBasicBlock *MBB) {
UndefReads.clear();
for (MachineInstr &MI : *MBB) {
if (!MI.isDebugInstr())
processDefs(&MI);
}
processUndefReads(MBB);
}
bool BreakFalseDeps::runOnMachineFunction(MachineFunction &mf) {
if (skipFunction(mf.getFunction()))
return false;
MF = &mf;
TII = MF->getSubtarget().getInstrInfo();
TRI = MF->getSubtarget().getRegisterInfo();
RDA = &getAnalysis<ReachingDefAnalysis>();
RegClassInfo.runOnMachineFunction(mf);
LLVM_DEBUG(dbgs() << "********** BREAK FALSE DEPENDENCIES **********\n");
for (MachineBasicBlock &MBB : mf) {
processBasicBlock(&MBB);
}
return false;
}