mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-01 04:29:57 +00:00
delay slot filler pass of MIPS, per suggestion of Jakob Stoklund Olesen. This change, along with the fix in r158154, enables machine verification to be run after delay slot filling. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158426 91177308-0d34-0410-b5e6-96231b3b80d8
267 lines
7.8 KiB
C++
267 lines
7.8 KiB
C++
//===-- DelaySlotFiller.cpp - Mips Delay Slot Filler ----------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Simple pass to fills delay slots with useful instructions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "delay-slot-filler"
|
|
|
|
#include "Mips.h"
|
|
#include "MipsTargetMachine.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
#include "llvm/Target/TargetRegisterInfo.h"
|
|
#include "llvm/ADT/SmallSet.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
using namespace llvm;
|
|
|
|
STATISTIC(FilledSlots, "Number of delay slots filled");
|
|
STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that"
|
|
" are not NOP.");
|
|
|
|
static cl::opt<bool> EnableDelaySlotFiller(
|
|
"enable-mips-delay-filler",
|
|
cl::init(false),
|
|
cl::desc("Fill the Mips delay slots useful instructions."),
|
|
cl::Hidden);
|
|
|
|
// This option can be used to silence complaints by machine verifier passes.
|
|
static cl::opt<bool> SkipDelaySlotFiller(
|
|
"skip-mips-delay-filler",
|
|
cl::init(false),
|
|
cl::desc("Skip MIPS' delay slot filling pass."),
|
|
cl::Hidden);
|
|
|
|
namespace {
|
|
struct Filler : public MachineFunctionPass {
|
|
typedef MachineBasicBlock::instr_iterator InstrIter;
|
|
typedef MachineBasicBlock::reverse_instr_iterator ReverseInstrIter;
|
|
|
|
TargetMachine &TM;
|
|
const TargetInstrInfo *TII;
|
|
InstrIter LastFiller;
|
|
|
|
static char ID;
|
|
Filler(TargetMachine &tm)
|
|
: MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { }
|
|
|
|
virtual const char *getPassName() const {
|
|
return "Mips Delay Slot Filler";
|
|
}
|
|
|
|
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
|
bool runOnMachineFunction(MachineFunction &F) {
|
|
if (SkipDelaySlotFiller)
|
|
return false;
|
|
|
|
bool Changed = false;
|
|
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
|
|
FI != FE; ++FI)
|
|
Changed |= runOnMachineBasicBlock(*FI);
|
|
return Changed;
|
|
}
|
|
|
|
bool isDelayFiller(MachineBasicBlock &MBB,
|
|
InstrIter candidate);
|
|
|
|
void insertCallUses(InstrIter MI,
|
|
SmallSet<unsigned, 32>& RegDefs,
|
|
SmallSet<unsigned, 32>& RegUses);
|
|
|
|
void insertDefsUses(InstrIter MI,
|
|
SmallSet<unsigned, 32>& RegDefs,
|
|
SmallSet<unsigned, 32>& RegUses);
|
|
|
|
bool IsRegInSet(SmallSet<unsigned, 32>& RegSet,
|
|
unsigned Reg);
|
|
|
|
bool delayHasHazard(InstrIter candidate,
|
|
bool &sawLoad, bool &sawStore,
|
|
SmallSet<unsigned, 32> &RegDefs,
|
|
SmallSet<unsigned, 32> &RegUses);
|
|
|
|
bool
|
|
findDelayInstr(MachineBasicBlock &MBB, InstrIter slot,
|
|
InstrIter &Filler);
|
|
|
|
|
|
};
|
|
char Filler::ID = 0;
|
|
} // end of anonymous namespace
|
|
|
|
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
|
|
/// We assume there is only one delay slot per delayed instruction.
|
|
bool Filler::
|
|
runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
|
bool Changed = false;
|
|
LastFiller = MBB.instr_end();
|
|
|
|
for (InstrIter I = MBB.instr_begin(); I != MBB.instr_end(); ++I)
|
|
if (I->hasDelaySlot()) {
|
|
++FilledSlots;
|
|
Changed = true;
|
|
|
|
InstrIter D;
|
|
|
|
if (EnableDelaySlotFiller && findDelayInstr(MBB, I, D)) {
|
|
MBB.splice(llvm::next(I), &MBB, D);
|
|
++UsefulSlots;
|
|
} else
|
|
BuildMI(MBB, llvm::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
|
|
|
|
// Record the filler instruction that filled the delay slot.
|
|
// The instruction after it will be visited in the next iteration.
|
|
LastFiller = ++I;
|
|
|
|
// Set InsideBundle bit so that the machine verifier doesn't expect this
|
|
// instruction to be a terminator.
|
|
LastFiller->setIsInsideBundle();
|
|
}
|
|
return Changed;
|
|
|
|
}
|
|
|
|
/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay
|
|
/// slots in Mips MachineFunctions
|
|
FunctionPass *llvm::createMipsDelaySlotFillerPass(MipsTargetMachine &tm) {
|
|
return new Filler(tm);
|
|
}
|
|
|
|
bool Filler::findDelayInstr(MachineBasicBlock &MBB,
|
|
InstrIter slot,
|
|
InstrIter &Filler) {
|
|
SmallSet<unsigned, 32> RegDefs;
|
|
SmallSet<unsigned, 32> RegUses;
|
|
|
|
insertDefsUses(slot, RegDefs, RegUses);
|
|
|
|
bool sawLoad = false;
|
|
bool sawStore = false;
|
|
|
|
for (ReverseInstrIter I(slot); I != MBB.instr_rend(); ++I) {
|
|
// skip debug value
|
|
if (I->isDebugValue())
|
|
continue;
|
|
|
|
// Convert to forward iterator.
|
|
InstrIter FI(llvm::next(I).base());
|
|
|
|
if (I->hasUnmodeledSideEffects()
|
|
|| I->isInlineAsm()
|
|
|| I->isLabel()
|
|
|| FI == LastFiller
|
|
|| I->isPseudo()
|
|
//
|
|
// Should not allow:
|
|
// ERET, DERET or WAIT, PAUSE. Need to add these to instruction
|
|
// list. TBD.
|
|
)
|
|
break;
|
|
|
|
if (delayHasHazard(FI, sawLoad, sawStore, RegDefs, RegUses)) {
|
|
insertDefsUses(FI, RegDefs, RegUses);
|
|
continue;
|
|
}
|
|
|
|
Filler = FI;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Filler::delayHasHazard(InstrIter candidate,
|
|
bool &sawLoad, bool &sawStore,
|
|
SmallSet<unsigned, 32> &RegDefs,
|
|
SmallSet<unsigned, 32> &RegUses) {
|
|
if (candidate->isImplicitDef() || candidate->isKill())
|
|
return true;
|
|
|
|
// Loads or stores cannot be moved past a store to the delay slot
|
|
// and stores cannot be moved past a load.
|
|
if (candidate->mayLoad()) {
|
|
if (sawStore)
|
|
return true;
|
|
sawLoad = true;
|
|
}
|
|
|
|
if (candidate->mayStore()) {
|
|
if (sawStore)
|
|
return true;
|
|
sawStore = true;
|
|
if (sawLoad)
|
|
return true;
|
|
}
|
|
|
|
assert((!candidate->isCall() && !candidate->isReturn()) &&
|
|
"Cannot put calls or returns in delay slot.");
|
|
|
|
for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) {
|
|
const MachineOperand &MO = candidate->getOperand(i);
|
|
unsigned Reg;
|
|
|
|
if (!MO.isReg() || !(Reg = MO.getReg()))
|
|
continue; // skip
|
|
|
|
if (MO.isDef()) {
|
|
// check whether Reg is defined or used before delay slot.
|
|
if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg))
|
|
return true;
|
|
}
|
|
if (MO.isUse()) {
|
|
// check whether Reg is defined before delay slot.
|
|
if (IsRegInSet(RegDefs, Reg))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
|
|
void Filler::insertDefsUses(InstrIter MI,
|
|
SmallSet<unsigned, 32>& RegDefs,
|
|
SmallSet<unsigned, 32>& RegUses) {
|
|
// If MI is a call or return, just examine the explicit non-variadic operands.
|
|
MCInstrDesc MCID = MI->getDesc();
|
|
unsigned e = MI->isCall() || MI->isReturn() ? MCID.getNumOperands() :
|
|
MI->getNumOperands();
|
|
|
|
// Add RA to RegDefs to prevent users of RA from going into delay slot.
|
|
if (MI->isCall())
|
|
RegDefs.insert(Mips::RA);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
//returns true if the Reg or its alias is in the RegSet.
|
|
bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg) {
|
|
// Check Reg and all aliased Registers.
|
|
for (MCRegAliasIterator AI(Reg, TM.getRegisterInfo(), true);
|
|
AI.isValid(); ++AI)
|
|
if (RegSet.count(*AI))
|
|
return true;
|
|
return false;
|
|
}
|