Convert some tab stops into spaces.
[oota-llvm.git] / lib / Target / PIC16 / PIC16MemSelOpt.cpp
1 //===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer  --------------------===//
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 // This file defines the pass which optimizes the emitting of banksel 
11 // instructions before accessing data memory. This currently works within
12 // a basic block only and keep tracks of the last accessed memory bank.
13 // If memory access continues to be in the same bank it just makes banksel
14 // immediate, which is a part of the insn accessing the data memory, from 1
15 // to zero. The asm printer emits a banksel only if that immediate is 1. 
16 //
17 // FIXME: this is not implemented yet.  The banksel pass only works on local
18 // basic blocks.
19 //
20 //===----------------------------------------------------------------------===//
21
22 #define DEBUG_TYPE "pic16-codegen"
23 #include "PIC16.h"
24 #include "PIC16ABINames.h"
25 #include "PIC16InstrInfo.h"
26 #include "PIC16MCAsmInfo.h"
27 #include "PIC16TargetMachine.h"
28 #include "llvm/CodeGen/MachineFunctionPass.h"
29 #include "llvm/CodeGen/MachineInstrBuilder.h"
30 #include "llvm/CodeGen/Passes.h"
31 #include "llvm/Target/TargetInstrInfo.h"
32 #include "llvm/Target/TargetMachine.h"
33 #include "llvm/GlobalValue.h"
34 #include "llvm/DerivedTypes.h"
35
36 using namespace llvm;
37
38 namespace {
39   struct MemSelOpt : public MachineFunctionPass {
40     static char ID;
41     MemSelOpt() : MachineFunctionPass(&ID) {}
42
43     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
44       AU.addPreservedID(MachineLoopInfoID);
45       AU.addPreservedID(MachineDominatorsID);
46       MachineFunctionPass::getAnalysisUsage(AU);
47     }
48
49     virtual bool runOnMachineFunction(MachineFunction &MF);
50
51     virtual const char *getPassName() const { 
52       return "PIC16 Memsel Optimizer"; 
53     }
54
55    bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB);
56    bool processInstruction(MachineInstr *MI);
57
58   private:
59     const TargetInstrInfo *TII; // Machine instruction info.
60     MachineBasicBlock *MBB;     // Current basic block
61     std::string CurBank;
62     int PageChanged;
63
64   };
65   char MemSelOpt::ID = 0;
66 }
67
68 FunctionPass *llvm::createPIC16MemSelOptimizerPass() { 
69   return new MemSelOpt(); 
70 }
71
72
73 /// runOnMachineFunction - Loop over all of the basic blocks, transforming FP
74 /// register references into FP stack references.
75 ///
76 bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) {
77   TII = MF.getTarget().getInstrInfo();
78   bool Changed = false;
79   for (MachineFunction::iterator I = MF.begin(), E = MF.end();
80        I != E; ++I) {
81     Changed |= processBasicBlock(MF, *I);
82   }
83
84   return Changed;
85 }
86
87 /// processBasicBlock - Loop over all of the instructions in the basic block,
88 /// transforming FP instructions into their stack form.
89 ///
90 bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
91   bool Changed = false;
92   MBB = &BB;
93
94   // Let us assume that when entering a basic block now bank is selected.
95   // Ideally we should look at the predecessors for this information.
96   CurBank=""; 
97   PageChanged=0;
98
99   MachineBasicBlock::iterator I;
100   for (I = BB.begin(); I != BB.end(); ++I) {
101     Changed |= processInstruction(I);
102
103     // if the page has changed insert a page sel before 
104     // any instruction that needs one
105     if (PageChanged == 1)
106     {
107       // Restore the page if it was changed, before leaving the basic block,
108       // because it may be required by the goto terminator or the fall thru
109       // basic blcok.
110       // If the terminator is return, we don't need to restore since there
111       // is no goto or fall thru basic block.
112       if ((I->getOpcode() == PIC16::sublw_3) || //macro has goto
113           (I->getOpcode() == PIC16::sublw_6) || //macro has goto
114           (I->getOpcode() == PIC16::addlwc)  || //macro has goto
115           (TII->get(I->getOpcode()).isBranch()))
116       {
117         DebugLoc dl = I->getDebugLoc();
118         BuildMI(*MBB, I, dl, TII->get(PIC16::pagesel)).addExternalSymbol("$");
119         Changed = true;
120         PageChanged = 0;            
121       }
122     }
123   }
124
125    // The basic block is over, but if we did not find any goto yet,
126    // we haven't restored the page.
127    // Restore the page if it was changed, before leaving the basic block,
128    // because it may be required by fall thru basic blcok.
129    // If the terminator is return, we don't need to restore since there
130    // is fall thru basic block.
131    if (PageChanged == 1) {
132       // save the end pointer before we move back to last insn.
133      MachineBasicBlock::iterator J = I;
134      I--;
135      const TargetInstrDesc &TID = TII->get(I->getOpcode());
136      if (! TID.isReturn())
137      {
138        DebugLoc dl = I->getDebugLoc();
139        BuildMI(*MBB, J, dl, 
140                TII->get(PIC16::pagesel)).addExternalSymbol("$");
141        Changed = true;
142        PageChanged = 0;
143      }
144    }
145
146
147   return Changed;
148 }
149
150 bool MemSelOpt::processInstruction(MachineInstr *MI) {
151   bool Changed = false;
152
153   unsigned NumOperands = MI->getNumOperands();
154   if (NumOperands == 0) return false;
155
156
157   // If this insn is not going to access any memory, return.
158   const TargetInstrDesc &TID = TII->get(MI->getOpcode());
159   if (!(TID.isBranch() || TID.isCall() || TID.mayLoad() || TID.mayStore()))
160     return false;
161
162   // The first thing we should do is that record if banksel/pagesel are
163   // changed in an unknown way. This can happend via any type of call. 
164   // We do it here first before scanning of MemOp / BBOp as the indirect
165   // call insns do not have any operands, but they still may change bank/page.
166   if (TID.isCall()) {
167     // Record that we have changed the page, so that we can restore it
168     // before basic block ends.
169     // We require to signal that a page anc bank change happened even for
170     // indirect calls. 
171     PageChanged = 1;
172
173     // When a call is made, there may be banksel for variables in callee.
174     // Hence the banksel in caller needs to be reset.
175     CurBank = "";
176   }
177
178   // Scan for the memory address operand.
179   // FIXME: Should we use standard interfaces like memoperands_iterator,
180   // hasMemOperand() etc ?
181   int MemOpPos = -1;
182   int BBOpPos = -1;
183   for (unsigned i = 0; i < NumOperands; i++) {
184     MachineOperand Op = MI->getOperand(i);
185     if (Op.getType() ==  MachineOperand::MO_GlobalAddress ||
186         Op.getType() ==  MachineOperand::MO_ExternalSymbol) { 
187       // We found one mem operand. Next one may be BS.
188       MemOpPos = i;
189     }
190     if (Op.getType() ==  MachineOperand::MO_MachineBasicBlock) {
191       // We found one BB operand. Next one may be pagesel.
192       BBOpPos = i;
193     }
194   }
195
196   // If we did not find an insn accessing memory. Continue.
197   if ((MemOpPos == -1) &&
198       (BBOpPos == -1))
199     return false;
200   assert ((BBOpPos != MemOpPos) && "operand can only be of one type");
201  
202
203   // If this is a pagesel material, handle it first.
204   // CALL and br_ucond insns use MemOp (GA or ES) and not BBOp.
205   // Pagesel is required only for a direct call.
206   if ((MI->getOpcode() == PIC16::CALL)) {
207     // Get the BBOp.
208     MachineOperand &MemOp = MI->getOperand(MemOpPos);
209     DebugLoc dl = MI->getDebugLoc();
210     BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)).addOperand(MemOp);   
211
212     // CALL and br_ucond needs only pagesel. so we are done.
213     return true; 
214   }
215
216   // Pagesel is handled. Now, add a Banksel if needed.
217   if (MemOpPos == -1) return Changed;
218   // Get the MemOp.
219   MachineOperand &Op = MI->getOperand(MemOpPos);
220
221   // Get the section name(NewBank) for MemOp.
222   // This assumes that the section names for globals are already set by
223   // AsmPrinter->doInitialization.
224   std::string NewBank = CurBank;
225   bool hasExternalLinkage = false;
226   if (Op.getType() ==  MachineOperand::MO_GlobalAddress &&
227       Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) {
228     if (Op.getGlobal()->hasExternalLinkage())
229       hasExternalLinkage= true;
230     NewBank = Op.getGlobal()->getSection();
231   } else if (Op.getType() ==  MachineOperand::MO_ExternalSymbol) {
232     // External Symbol is generated for temp data and arguments. They are
233     // in fpdata.<functionname>.# section.
234     std::string Sym = Op.getSymbolName();
235     NewBank = PAN::getSectionNameForSym(Sym);
236   }
237
238   // If the section is shared section, do not emit banksel.
239   if (NewBank == PAN::getSharedUDataSectionName())
240     return Changed;
241
242   // If the previous and new section names are same, we don't need to
243   // emit banksel. 
244   if (NewBank.compare(CurBank) != 0 || hasExternalLinkage) {
245     DebugLoc dl = MI->getDebugLoc();
246     BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)).
247       addOperand(Op);
248     Changed = true;
249     CurBank = NewBank;
250   }
251
252   return Changed;
253 }
254