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
25using namespace llvm;
26
27namespace {
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.
72void SPUNopFiller::
73runOnMachineBasicBlock(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
132FunctionPass *llvm::createSPUNopFillerPass(SPUTargetMachine &tm) {
133  return new SPUNopFiller(tm);
134}
135
136// Figure out if 'instr' is executed in the even or odd pipeline
137SPUNopFiller::SPUOpPlace
138SPUNopFiller::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