#include "SPU.h"
#include "SPUTargetMachine.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct SPUNopFiller : public MachineFunctionPass {
TargetMachine &TM;
const TargetInstrInfo *TII;
const InstrItineraryData *IID;
bool isEvenPlace;
static char ID;
SPUNopFiller(TargetMachine &tm)
: MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()),
IID(tm.getInstrItineraryData())
{
DEBUG( dbgs() << "********** SPU Nop filler **********\n" ; );
}
virtual const char *getPassName() const {
return "SPU nop/lnop Filler";
}
void runOnMachineBasicBlock(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &F) {
isEvenPlace = true; for (MachineFunction::iterator FI = F.begin(), FE = F.end();
FI != FE; ++FI)
runOnMachineBasicBlock(*FI);
return true; }
typedef enum { none = 0, pseudo = 1, even = 2,
odd = 3 } SPUOpPlace;
SPUOpPlace getOpPlacement( MachineInstr &instr );
};
char SPUNopFiller::ID = 0;
}
void SPUNopFiller::
runOnMachineBasicBlock(MachineBasicBlock &MBB)
{
assert( isEvenPlace && "basic block start from odd address");
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I)
{
SPUOpPlace this_optype, next_optype;
MachineBasicBlock::iterator J = I;
J++;
this_optype = getOpPlacement( *I );
next_optype = none;
while (J!=MBB.end()){
next_optype = getOpPlacement( *J );
++J;
if (next_optype != pseudo )
break;
}
if( isEvenPlace && this_optype == odd && next_optype == even ) {
DEBUG( dbgs() <<"Adding NOP before: "; );
DEBUG( I->dump(); );
BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::ENOP));
isEvenPlace=false;
}
else if ( !isEvenPlace && this_optype == even && next_optype == odd){
DEBUG( dbgs() <<"Adding LNOP before: "; );
DEBUG( I->dump(); );
BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::LNOP));
isEvenPlace=true;
}
if( this_optype != pseudo )
isEvenPlace = !isEvenPlace;
}
if( !isEvenPlace ){
MachineBasicBlock::iterator J = MBB.end();
J--;
if (getOpPlacement( *J ) == odd) {
DEBUG( dbgs() <<"Padding basic block with NOP\n"; );
BuildMI(MBB, J, J->getDebugLoc(), TII->get(SPU::ENOP));
}
else {
J++;
DEBUG( dbgs() <<"Padding basic block with LNOP\n"; );
BuildMI(MBB, J, DebugLoc(), TII->get(SPU::LNOP));
}
isEvenPlace=true;
}
}
FunctionPass *llvm::createSPUNopFillerPass(SPUTargetMachine &tm) {
return new SPUNopFiller(tm);
}
SPUNopFiller::SPUOpPlace
SPUNopFiller::getOpPlacement( MachineInstr &instr ) {
int sc = instr.getDesc().getSchedClass();
const InstrStage *stage = IID->beginStage(sc);
unsigned FUs = stage->getUnits();
SPUOpPlace retval;
switch( FUs ) {
case 0: retval = pseudo; break;
case 1: retval = odd; break;
case 2: retval = even; break;
default: retval= pseudo;
assert( false && "got unknown FuncUnit\n");
break;
};
return retval;
}