Put code that generates debug labels into TableGen so that it can be used by
[oota-llvm.git] / lib / Target / PIC16 / PIC16AsmPrinter.cpp
1 //===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===//
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 contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to PIC16 assembly language.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "PIC16AsmPrinter.h"
16 #include "PIC16TargetAsmInfo.h"
17 #include "llvm/DerivedTypes.h"
18 #include "llvm/Function.h"
19 #include "llvm/Module.h"
20 #include "llvm/CodeGen/DwarfWriter.h"
21 #include "llvm/CodeGen/MachineFrameInfo.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Support/Mangler.h"
24
25 using namespace llvm;
26
27 #include "PIC16GenAsmWriter.inc"
28 bool PIC16AsmPrinter::inSameBank (char *s1, char *s2){
29
30   assert (s1 && s2 && "Null pointer assignment");
31
32   if ((*s1 == '.') && (*s2 == '.')) { //skip if they both start with '.'
33     s1++;
34     s2++;
35   }
36   while (*s1 && *s2) {
37     if (*s1 != *s2) 
38       goto _NotInSameBank;
39
40     if ((*s1 == '.') && (*s2 == '.')) //both symbols in same function
41       goto _InSameBank;               //in the same bank
42
43     s1++;
44     s2++;
45   }
46
47   if (*s1 && *s1) {
48   _InSameBank:
49     return true;
50   }
51
52  _NotInSameBank:
53   return false;
54 }
55
56 bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
57   std::string NewBankselLabel;
58   unsigned Operands = MI->getNumOperands();
59   if (Operands > 1) {
60     // Global address or external symbol should be second operand from last
61     // if we want to print banksel for it.
62     const MachineOperand &Op = MI->getOperand(Operands-2);
63     unsigned OpType = Op.getType();
64     if (OpType == MachineOperand::MO_GlobalAddress ||
65         OpType == MachineOperand::MO_ExternalSymbol) { 
66       if (OpType == MachineOperand::MO_GlobalAddress ) 
67         NewBankselLabel =  Mang->getValueName(Op.getGlobal());
68       else 
69         NewBankselLabel =  Op.getSymbolName();
70
71       // Operand after global address or external symbol should be  banksel.
72       // Value 1 for this operand means we need to generate banksel else do not
73       // generate banksel.
74       const MachineOperand &BS = MI->getOperand(Operands-1);
75       if (((int)BS.getImm() == 1) &&
76           (!inSameBank ((char *)CurrentBankselLabelInBasicBlock.c_str(),
77                         (char *)NewBankselLabel.c_str()))) {
78         CurrentBankselLabelInBasicBlock = NewBankselLabel;
79         O << "\tbanksel ";
80         printOperand(MI, Operands-2);
81         O << "\n";
82       }
83     }
84   }
85   printInstruction(MI);
86   return true;
87 }
88
89 /// runOnMachineFunction - This uses the printInstruction()
90 /// method to print assembly for each instruction.
91 ///
92 bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
93   // This calls the base class function required to be called at beginning
94   // of runOnMachineFunction.
95   SetupMachineFunction(MF);
96
97   // Get the mangled name.
98   const Function *F = MF.getFunction();
99   CurrentFnName = Mang->getValueName(F);
100
101   // Emit the function variables.
102   emitFunctionData(MF);
103   std::string codeSection;
104   codeSection = "code." + CurrentFnName + ".# " + "CODE";
105   const Section *fCodeSection = TAI->getNamedSection(codeSection.c_str(),
106                                                SectionFlags::Code);
107   O <<  "\n";
108   SwitchToSection (fCodeSection);
109
110   // Print out code for the function.
111   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
112        I != E; ++I) {
113     // Print a label for the basic block.
114     if (I != MF.begin()) {
115       printBasicBlockLabel(I, true);
116       O << '\n';
117     }
118     else
119       O << CurrentFnName << ":\n";
120     CurrentBankselLabelInBasicBlock = "";
121     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
122          II != E; ++II) {
123       // Print the assembly for the instruction.
124         printMachineInstruction(II);
125     }
126   }
127   return false;  // we didn't modify anything.
128 }
129
130 /// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
131 /// assembly code for a MachineFunction to the given output stream,
132 /// using the given target machine description.  This should work
133 /// regardless of whether the function is in SSA form.
134 ///
135 FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
136                                                PIC16TargetMachine &tm) {
137   return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
138 }
139
140 void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
141   const MachineOperand &MO = MI->getOperand(opNum);
142
143   switch (MO.getType()) {
144     case MachineOperand::MO_Register:
145       if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
146         O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
147       else
148         assert(0 && "not implemented");
149         return;
150
151     case MachineOperand::MO_Immediate:
152       O << (int)MO.getImm();
153       return;
154
155     case MachineOperand::MO_GlobalAddress:
156       O << Mang->getValueName(MO.getGlobal());
157       break;
158
159     case MachineOperand::MO_ExternalSymbol:
160       O << MO.getSymbolName();
161       break;
162
163     case MachineOperand::MO_MachineBasicBlock:
164       printBasicBlockLabel(MO.getMBB());
165       return;
166
167     default:
168       assert(0 && " Operand type not supported.");
169   }
170 }
171
172 void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
173   int CC = (int)MI->getOperand(opNum).getImm();
174   O << PIC16CondCodeToString((PIC16CC::CondCodes)CC);
175 }
176
177
178 bool PIC16AsmPrinter::doInitialization (Module &M) {
179   bool Result = AsmPrinter::doInitialization(M);
180   // FIXME:: This is temporary solution to generate the include file.
181   // The processor should be passed to llc as in input and the header file
182   // should be generated accordingly.
183   O << "\t#include P16F1937.INC\n";
184   EmitExternsAndGlobals (M);
185   EmitInitData (M);
186   EmitUnInitData(M);
187   EmitRomData(M);
188   return Result;
189 }
190
191 void PIC16AsmPrinter::EmitExternsAndGlobals (Module &M) {
192  // Emit declarations for external functions.
193   O << "section.0" <<"\n";
194   for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) {
195     std::string Name = Mang->getValueName(I);
196     if (Name.compare("abort") == 0)
197       continue;
198     if (I->isDeclaration()) {
199       O << "\textern " <<Name << "\n";
200       O << "\textern " << Name << ".retval\n";
201       O << "\textern " << Name << ".args\n";
202     }
203     else if (I->hasExternalLinkage()) {
204       O << "\tglobal " << Name << "\n";
205       O << "\tglobal " << Name << ".retval\n";
206       O << "\tglobal " << Name << ".args\n";
207     }
208   }
209
210   // Emit header file to include declaration of library functions
211   O << "\t#include C16IntrinsicCalls.INC\n";
212
213   // Emit declarations for external globals.
214   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
215        I != E; I++) {
216     // Any variables reaching here with ".auto." in its name is a local scope
217     // variable and should not be printed in global data section.
218     std::string Name = Mang->getValueName(I);
219     if (Name.find(".auto.") != std::string::npos)
220       continue;
221
222     if (I->isDeclaration())
223       O << "\textern "<< Name << "\n";
224     else if (I->hasCommonLinkage() || I->hasExternalLinkage())
225       O << "\tglobal "<< Name << "\n";
226   }
227 }
228
229 void PIC16AsmPrinter::EmitInitData (Module &M) {
230   SwitchToSection(TAI->getDataSection());
231   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
232        I != E; ++I) {
233     if (!I->hasInitializer())   // External global require no code.
234       continue;
235
236     Constant *C = I->getInitializer();
237     const PointerType *PtrTy = I->getType();
238     int AddrSpace = PtrTy->getAddressSpace();
239
240     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) {
241     
242       if (EmitSpecialLLVMGlobal(I)) 
243         continue;
244
245       // Any variables reaching here with "." in its name is a local scope
246       // variable and should not be printed in global data section.
247       std::string name = Mang->getValueName(I);
248       if (name.find(".auto.") != std::string::npos)
249         continue;
250
251       O << name;
252       EmitGlobalConstant(C, AddrSpace);
253     }
254   }
255 }
256
257 void PIC16AsmPrinter::EmitRomData (Module &M)
258 {
259   SwitchToSection(TAI->getReadOnlySection());
260   IsRomData = true;
261   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
262        I != E; ++I) {
263     if (!I->hasInitializer())   // External global require no code.
264       continue;
265
266     Constant *C = I->getInitializer();
267     const PointerType *PtrTy = I->getType();
268     int AddrSpace = PtrTy->getAddressSpace();
269     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::ROM_SPACE)) {
270
271       if (EmitSpecialLLVMGlobal(I))
272         continue;
273
274       // Any variables reaching here with "." in its name is a local scope
275       // variable and should not be printed in global data section.
276       std::string name = Mang->getValueName(I);
277       if (name.find(".") != std::string::npos)
278         continue;
279
280       O << name;
281       EmitGlobalConstant(C, AddrSpace);
282       O << "\n";
283     }
284   }
285   IsRomData = false;
286 }
287
288 void PIC16AsmPrinter::EmitUnInitData (Module &M)
289 {
290   SwitchToSection(TAI->getBSSSection_());
291   const TargetData *TD = TM.getTargetData();
292
293   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
294        I != E; ++I) {
295     if (!I->hasInitializer())   // External global require no code.
296       continue;
297
298     Constant *C = I->getInitializer();
299     if (C->isNullValue()) {
300
301       if (EmitSpecialLLVMGlobal(I))
302         continue;
303
304       // Any variables reaching here with "." in its name is a local scope
305       // variable and should not be printed in global data section.
306       std::string name = Mang->getValueName(I);
307       if (name.find(".") != std::string::npos)
308         continue;
309
310       const Type *Ty = C->getType();
311       unsigned Size = TD->getTypePaddedSize(Ty);
312
313       O << name << " " <<"RES"<< " " << Size ;
314       O << "\n";
315     }
316   }
317 }
318
319 bool PIC16AsmPrinter::doFinalization(Module &M) {
320   O << "\t" << "END\n";
321   bool Result = AsmPrinter::doFinalization(M);
322   return Result;
323 }
324
325 void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) {
326   const Function *F = MF.getFunction();
327   std::string FuncName = Mang->getValueName(F);
328   const Module *M = F->getParent();
329   const TargetData *TD = TM.getTargetData();
330   unsigned FrameSize = 0;
331   // Emit the data section name.
332   O << "\n"; 
333   std::string SectionName = "fdata." + CurrentFnName + ".# " + "UDATA";
334
335   const Section *fDataSection = TAI->getNamedSection(SectionName.c_str(),
336                                                SectionFlags::Writeable);
337   SwitchToSection(fDataSection);
338   
339   //Emit function return value.
340   O << CurrentFnName << ".retval:\n";
341   const Type *RetType = F->getReturnType();
342   unsigned RetSize = 0; 
343   if (RetType->getTypeID() != Type::VoidTyID) 
344     RetSize = TD->getTypePaddedSize(RetType);
345   
346   // Emit function arguments.
347   O << CurrentFnName << ".args:\n";
348   // Emit the function variables. 
349    
350   // In PIC16 all the function arguments and local variables are global.
351   // Therefore to get the variable belonging to this function entire
352   // global list will be traversed and variables belonging to this function
353   // will be emitted in the current data section.
354   for (Module::const_global_iterator I = M->global_begin(), E = M->global_end();
355        I != E; ++I) {
356     std::string VarName = Mang->getValueName(I);
357     
358     // The variables of a function are of form FuncName.* . If this variable
359     // does not belong to this function then continue. 
360     // Static local varilabes of a function does not have .auto. in their
361     // name. They are not printed as part of function data but module
362     // level global data.
363     if (!(VarName.find(FuncName + ".auto.") == 0 ? true : false))
364       continue;
365
366     Constant *C = I->getInitializer();
367     const Type *Ty = C->getType();
368     unsigned Size = TD->getTypePaddedSize(Ty);
369     FrameSize += Size; 
370     // Emit memory reserve directive.
371     O << VarName << "  RES  " << Size << "\n";
372   }
373
374   // Return value can not overlap with temp data, becasue a temp slot
375   // may be read/written after a return value is calculated and saved 
376   // within the function.
377   if (RetSize > FrameSize)
378     O << CurrentFnName << ".dummy" << " RES " << (RetSize - FrameSize) << "\n";
379
380   emitFunctionTempData(MF, FrameSize);
381 }
382
383 void PIC16AsmPrinter::emitFunctionTempData(MachineFunction &MF,
384                                            unsigned &FrameSize) {
385   // Emit temporary variables.
386   MachineFrameInfo *FrameInfo = MF.getFrameInfo();
387   if (FrameInfo->hasStackObjects()) {
388     int indexBegin = FrameInfo->getObjectIndexBegin();
389     int indexEnd = FrameInfo->getObjectIndexEnd();
390
391     if (indexBegin < indexEnd) { 
392       FrameSize += indexEnd - indexBegin; 
393       O << CurrentFnName << ".tmp RES"<< " " 
394         <<indexEnd - indexBegin <<"\n";
395     } 
396     /*
397     while (indexBegin < indexEnd) {
398         O << CurrentFnName << "_tmp_" << indexBegin << " " << "RES"<< " " 
399           << 1 << "\n" ;
400         indexBegin++;
401     }
402     */
403   }
404 }