1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
//===-- SPUNopFiller.cpp - Add nops/lnops to align the pipelines---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The final pass just before assembly printing. This pass is the last
// checkpoint where nops and lnops are added to the instruction stream to
// satisfy the dual issue requirements. The actual dual issue scheduling is
// done (TODO: nowhere, currently)
//
//===----------------------------------------------------------------------===//
#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; // the instruction slot (mem address) at hand is even/odd
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; //all functions get an .align 3 directive at start
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
FI != FE; ++FI)
runOnMachineBasicBlock(*FI);
return true; //never-ever do any more modifications, just print it!
}
typedef enum { none = 0, // no more instructions in this function / BB
pseudo = 1, // this does not get executed
even = 2,
odd = 3 } SPUOpPlace;
SPUOpPlace getOpPlacement( MachineInstr &instr );
};
char SPUNopFiller::ID = 0;
}
// Fill a BasicBlock to alignment.
// In the assebly we align the functions to 'even' adresses, but
// basic blocks have an implicit alignmnet. We hereby define
// basic blocks to have the same, even, alignment.
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;
}
// padd: odd(wrong), even(wrong), ...
// to: nop(corr), odd(corr), even(corr)...
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;
}
// padd: even(wrong), odd(wrong), ...
// to: lnop(corr), even(corr), odd(corr)...
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;
}
// now go to next mem slot
if( this_optype != pseudo )
isEvenPlace = !isEvenPlace;
}
// padd basicblock end
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);
}
// Figure out if 'instr' is executed in the even or odd pipeline
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;
}
|