Home | History | Annotate | Download | only in CellSPU
      1 //===-- SPUNopFiller.cpp - Add nops/lnops to align the pipelines ----------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // The final pass just before assembly printing. This pass is the last
     11 // checkpoint where nops and lnops are added to the instruction stream to
     12 // satisfy the dual issue requirements. The actual dual issue scheduling is
     13 // done (TODO: nowhere, currently)
     14 //
     15 //===----------------------------------------------------------------------===//
     16 
     17 #include "SPU.h"
     18 #include "SPUTargetMachine.h"
     19 #include "llvm/CodeGen/MachineFunctionPass.h"
     20 #include "llvm/CodeGen/MachineInstrBuilder.h"
     21 #include "llvm/Target/TargetInstrInfo.h"
     22 #include "llvm/Support/Debug.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 
     25 using namespace llvm;
     26 
     27 namespace {
     28   struct SPUNopFiller : public MachineFunctionPass {
     29 
     30     TargetMachine &TM;
     31     const TargetInstrInfo *TII;
     32     const InstrItineraryData *IID;
     33     bool isEvenPlace;  // the instruction slot (mem address) at hand is even/odd
     34 
     35     static char ID;
     36     SPUNopFiller(TargetMachine &tm)
     37       : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()),
     38         IID(tm.getInstrItineraryData())
     39     {
     40       DEBUG( dbgs() << "********** SPU Nop filler **********\n" ; );
     41     }
     42 
     43     virtual const char *getPassName() const {
     44       return "SPU nop/lnop Filler";
     45     }
     46 
     47     void runOnMachineBasicBlock(MachineBasicBlock &MBB);
     48 
     49     bool runOnMachineFunction(MachineFunction &F) {
     50       isEvenPlace = true; //all functions get an .align 3 directive at start
     51       for (MachineFunction::iterator FI = F.begin(), FE = F.end();
     52            FI != FE; ++FI)
     53         runOnMachineBasicBlock(*FI);
     54       return true; //never-ever do any more modifications, just print it!
     55     }
     56 
     57     typedef enum { none   = 0, // no more instructions in this function / BB
     58                    pseudo = 1, // this does not get executed
     59                    even   = 2,
     60                    odd    = 3 } SPUOpPlace;
     61     SPUOpPlace getOpPlacement( MachineInstr &instr );
     62 
     63   };
     64   char SPUNopFiller::ID = 0;
     65 
     66 }
     67 
     68 // Fill a BasicBlock to alignment.
     69 // In the assebly we align the functions to 'even' adresses, but
     70 // basic blocks have an implicit alignmnet. We hereby define
     71 // basic blocks to have the same, even, alignment.
     72 void SPUNopFiller::
     73 runOnMachineBasicBlock(MachineBasicBlock &MBB)
     74 {
     75   assert( isEvenPlace && "basic block start from odd address");
     76   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I)
     77   {
     78     SPUOpPlace this_optype, next_optype;
     79     MachineBasicBlock::iterator J = I;
     80     J++;
     81 
     82     this_optype = getOpPlacement( *I );
     83     next_optype = none;
     84     while (J!=MBB.end()){
     85       next_optype = getOpPlacement( *J );
     86       ++J;
     87       if (next_optype != pseudo )
     88         break;
     89     }
     90 
     91     // padd: odd(wrong), even(wrong), ...
     92     // to:   nop(corr), odd(corr), even(corr)...
     93     if( isEvenPlace && this_optype == odd && next_optype == even ) {
     94       DEBUG( dbgs() <<"Adding NOP before: "; );
     95       DEBUG( I->dump(); );
     96       BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::ENOP));
     97       isEvenPlace=false;
     98     }
     99 
    100     // padd: even(wrong), odd(wrong), ...
    101     // to:   lnop(corr), even(corr), odd(corr)...
    102     else if ( !isEvenPlace && this_optype == even && next_optype == odd){
    103       DEBUG( dbgs() <<"Adding LNOP before: "; );
    104       DEBUG( I->dump(); );
    105       BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::LNOP));
    106       isEvenPlace=true;
    107     }
    108 
    109     // now go to next mem slot
    110     if( this_optype != pseudo )
    111       isEvenPlace = !isEvenPlace;
    112 
    113   }
    114 
    115   // padd basicblock end
    116   if( !isEvenPlace ){
    117     MachineBasicBlock::iterator J = MBB.end();
    118     J--;
    119     if (getOpPlacement( *J ) == odd) {
    120       DEBUG( dbgs() <<"Padding basic block with NOP\n"; );
    121       BuildMI(MBB, J, J->getDebugLoc(), TII->get(SPU::ENOP));
    122     }
    123     else {
    124       J++;
    125       DEBUG( dbgs() <<"Padding basic block with LNOP\n"; );
    126       BuildMI(MBB, J, DebugLoc(), TII->get(SPU::LNOP));
    127     }
    128     isEvenPlace=true;
    129   }
    130 }
    131 
    132 FunctionPass *llvm::createSPUNopFillerPass(SPUTargetMachine &tm) {
    133   return new SPUNopFiller(tm);
    134 }
    135 
    136 // Figure out if 'instr' is executed in the even or odd pipeline
    137 SPUNopFiller::SPUOpPlace
    138 SPUNopFiller::getOpPlacement( MachineInstr &instr ) {
    139   int sc = instr.getDesc().getSchedClass();
    140   const InstrStage *stage = IID->beginStage(sc);
    141   unsigned FUs = stage->getUnits();
    142   SPUOpPlace retval;
    143 
    144   switch( FUs ) {
    145     case 0: retval = pseudo; break;
    146     case 1: retval = odd;    break;
    147     case 2: retval = even;   break;
    148     default: retval= pseudo;
    149              assert( false && "got unknown FuncUnit\n");
    150              break;
    151   };
    152   return retval;
    153 }
    154