|  | //===-- 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; | 
|  | } |