#include "Lanai.h"
#include "LanaiTargetMachine.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
#define DEBUG_TYPE "delay-slot-filler"
STATISTIC(FilledSlots, "Number of delay slots filled");
static cl::opt<bool>
NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false),
cl::desc("Fill Lanai delay slots with NOPs."),
cl::Hidden);
namespace {
struct Filler : public MachineFunctionPass {
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MachineBasicBlock::instr_iterator LastFiller;
static char ID;
explicit Filler() : MachineFunctionPass(ID) {}
StringRef getPassName() const override { return "Lanai Delay Slot Filler"; }
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &MF) override {
const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();
TII = Subtarget.getInstrInfo();
TRI = Subtarget.getRegisterInfo();
bool Changed = false;
for (MachineBasicBlock &MBB : MF)
Changed |= runOnMachineBasicBlock(MBB);
return Changed;
}
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
void insertDefsUses(MachineBasicBlock::instr_iterator MI,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses);
bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);
bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses);
bool findDelayInstr(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator Slot,
MachineBasicBlock::instr_iterator &Filler);
};
char Filler::ID = 0;
}
FunctionPass *
llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine & ) {
return new Filler();
}
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
bool Changed = false;
LastFiller = MBB.instr_end();
for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();
I != MBB.instr_end(); ++I) {
if (I->getDesc().hasDelaySlot()) {
MachineBasicBlock::instr_iterator InstrWithSlot = I;
MachineBasicBlock::instr_iterator J = I;
if (I->getOpcode() == Lanai::RET) {
MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();
assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
RI->getOperand(0).getReg() == Lanai::FP &&
RI->getOperand(1).isReg() &&
RI->getOperand(1).getReg() == Lanai::FP &&
RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);
++RI;
assert(RI->getOpcode() == Lanai::ADD_I_LO &&
RI->getOperand(0).isReg() &&
RI->getOperand(0).getReg() == Lanai::SP &&
RI->getOperand(1).isReg() &&
RI->getOperand(1).getReg() == Lanai::FP);
MachineBasicBlock::instr_iterator FI = RI.getReverse();
MBB.splice(std::next(I), &MBB, FI, I);
FilledSlots += 2;
} else {
if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {
MBB.splice(std::next(I), &MBB, J);
} else {
BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP));
}
++FilledSlots;
}
Changed = true;
LastFiller = ++I;
MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller));
}
}
return Changed;
}
bool Filler::findDelayInstr(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator Slot,
MachineBasicBlock::instr_iterator &Filler) {
SmallSet<unsigned, 32> RegDefs;
SmallSet<unsigned, 32> RegUses;
insertDefsUses(Slot, RegDefs, RegUses);
bool SawLoad = false;
bool SawStore = false;
for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();
I != MBB.instr_rend(); ++I) {
if (I->isDebugInstr())
continue;
MachineBasicBlock::instr_iterator FI = I.getReverse();
if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
FI == LastFiller || I->isPseudo())
break;
if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) {
insertDefsUses(FI, RegDefs, RegUses);
continue;
}
Filler = FI;
return true;
}
return false;
}
bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses) {
if (MI->isImplicitDef() || MI->isKill())
return true;
if (MI->mayLoad()) {
if (SawStore)
return true;
SawLoad = true;
}
if (MI->mayStore()) {
if (SawStore)
return true;
SawStore = true;
if (SawLoad)
return true;
}
assert((!MI->isCall() && !MI->isReturn()) &&
"Cannot put calls or returns in delay slot.");
for (const MachineOperand &MO : MI->operands()) {
unsigned Reg;
if (!MO.isReg() || !(Reg = MO.getReg()))
continue;
if (MO.isDef()) {
if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg))
return true;
}
if (MO.isUse()) {
if (isRegInSet(RegDefs, Reg))
return true;
}
}
return false;
}
void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses) {
MCInstrDesc MCID = MI->getDesc();
unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()
: MI->getNumOperands();
for (unsigned I = 0; I != E; ++I) {
const MachineOperand &MO = MI->getOperand(I);
unsigned Reg;
if (!MO.isReg() || !(Reg = MO.getReg()))
continue;
if (MO.isDef())
RegDefs.insert(Reg);
else if (MO.isUse())
RegUses.insert(Reg);
}
if (MI->isCall() || MI->isReturn())
RegDefs.insert(Lanai::SP);
}
bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
if (RegSet.count(*AI))
return true;
return false;
}