• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
SPUNopFiller__anon861411560111::SPUNopFiller36     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 
getPassName__anon861411560111::SPUNopFiller43     virtual const char *getPassName() const {
44       return "SPU nop/lnop Filler";
45     }
46 
47     void runOnMachineBasicBlock(MachineBasicBlock &MBB);
48 
runOnMachineFunction__anon861411560111::SPUNopFiller49     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::
runOnMachineBasicBlock(MachineBasicBlock & MBB)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 
createSPUNopFillerPass(SPUTargetMachine & tm)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
getOpPlacement(MachineInstr & instr)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