CMake: Removed source file from lib/Target/PIC16/CMakeLists.txt.
[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/Support/raw_ostream.h"
18 #include "llvm/Support/Mangler.h"
19 #include "llvm/Function.h"
20 #include "llvm/Module.h"
21 #include "llvm/CodeGen/MachineFrameInfo.h"
22 #include "llvm/DerivedTypes.h"
23
24 using namespace llvm;
25
26 #include "PIC16GenAsmWriter.inc"
27
28 bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
29   std::string NewBankselLabel;
30   unsigned Operands = MI->getNumOperands();
31   if (Operands > 1) {
32     // Global address or external symbol should be second operand from last
33     // if we want to print banksel for it.
34     const MachineOperand &Op = MI->getOperand(Operands-2);
35     unsigned OpType = Op.getType();
36     if (OpType == MachineOperand::MO_GlobalAddress ||
37         OpType == MachineOperand::MO_ExternalSymbol) { 
38       if (OpType == MachineOperand::MO_GlobalAddress ) 
39         NewBankselLabel =  Mang->getValueName(Op.getGlobal());
40       else 
41         NewBankselLabel =  Op.getSymbolName();
42
43       // Operand after global address or external symbol should be  banksel.
44       // Value 1 for this operand means we need to generate banksel else do not
45       // generate banksel.
46       const MachineOperand &BS = MI->getOperand(Operands-1);
47       if (((int)BS.getImm() == 1) &&
48           (strcmp (CurrentBankselLabelInBasicBlock.c_str(),
49                    NewBankselLabel.c_str()))) {
50         CurrentBankselLabelInBasicBlock = NewBankselLabel;
51         O << "\tbanksel ";
52         printOperand(MI, Operands-2);
53         O << "\n";
54       }
55     }
56   }
57   printInstruction(MI);
58   return true;
59 }
60
61 /// runOnMachineFunction - This uses the printInstruction()
62 /// method to print assembly for each instruction.
63 ///
64 bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
65   // This calls the base class function required to be called at beginning
66   // of runOnMachineFunction.
67   SetupMachineFunction(MF);
68
69   // Get the mangled name.
70   const Function *F = MF.getFunction();
71   CurrentFnName = Mang->getValueName(F);
72
73   // Emit the function variables.
74   emitFunctionData(MF);
75   std::string codeSection;
76   codeSection = "code." + CurrentFnName + ".#";
77   O <<  "\n";
78   SwitchToTextSection (codeSection.c_str(),F);
79
80   // Print out code for the function.
81   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
82        I != E; ++I) {
83     // Print a label for the basic block.
84     if (I != MF.begin()) {
85       printBasicBlockLabel(I, true);
86       O << '\n';
87     }
88     else
89       O << "_" << CurrentFnName << ":\n";
90     CurrentBankselLabelInBasicBlock = "";
91     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
92          II != E; ++II) {
93       // Print the assembly for the instruction.
94         printMachineInstruction(II);
95     }
96   }
97   return false;  // we didn't modify anything.
98 }
99
100 /// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
101 /// assembly code for a MachineFunction to the given output stream,
102 /// using the given target machine description.  This should work
103 /// regardless of whether the function is in SSA form.
104 ///
105 FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
106                                                PIC16TargetMachine &tm) {
107   return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
108 }
109
110 void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
111   const MachineOperand &MO = MI->getOperand(opNum);
112
113   switch (MO.getType()) {
114     case MachineOperand::MO_Register:
115       if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
116         O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
117       else
118         assert(0 && "not implemented");
119         return;
120
121     case MachineOperand::MO_Immediate:
122       O << (int)MO.getImm();
123       return;
124
125     case MachineOperand::MO_GlobalAddress:
126       O << Mang->getValueName(MO.getGlobal());
127       break;
128
129     case MachineOperand::MO_ExternalSymbol:
130       O << MO.getSymbolName();
131       break;
132
133     default:
134       assert(0 && " Operand type not supported.");
135   }
136 }
137
138 bool PIC16AsmPrinter::doInitialization (Module &M) {
139   bool Result = AsmPrinter::doInitialization(M);
140   // FIXME:: This is temporary solution to generate the include file.
141   // The processor should be passed to llc as in input and the header file
142   // should be generated accordingly.
143   O << "\t#include P16F1937.INC\n";
144
145   EmitInitData (M);
146   EmitUnInitData(M);
147   EmitRomData(M);
148   return Result;
149 }
150
151 void PIC16AsmPrinter::EmitInitData (Module &M)
152 {
153   std::string iDataSection = "idata.#";
154   SwitchToDataSection(iDataSection.c_str());
155   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
156        I != E; ++I) {
157     if (!I->hasInitializer())   // External global require no code.
158       continue;
159
160     Constant *C = I->getInitializer();
161     const PointerType *PtrTy = I->getType();
162     int AddrSpace = PtrTy->getAddressSpace();
163
164     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) {
165     
166       if (EmitSpecialLLVMGlobal(I)) 
167         continue;
168
169       // Any variables reaching here with "." in its name is a local scope
170       // variable and should not be printed in global data section.
171       std::string name = Mang->getValueName(I);
172       if (name.find(".") != std::string::npos)
173         continue;
174
175       O << name;
176       EmitGlobalConstant(C);
177     }
178   }
179 }
180
181 void PIC16AsmPrinter::EmitConstantValueOnly(const Constant* CV) {
182   if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
183     unsigned BitWidth = CI->getBitWidth();
184     int Val = CI->getZExtValue();
185     if (BitWidth == 8) {
186       // Expecting db directive here. In case of romdata we need to pad the
187       // word with zeros.
188       if (IsRomData)
189         O << 0 <<", ";
190       O << Val; 
191     }
192     else if (BitWidth == 16) {
193       unsigned Element1, Element2;
194       Element1 = 0x00ff & Val;
195       Element2 = 0x00ff & (Val >> 8);
196       if (IsRomData)
197         O << 0 <<", "<<Element1 <<", "<< 0 <<", "<< Element2;
198       else
199         O << Element1 <<", "<< Element2;  
200     }
201     else if (BitWidth == 32) {
202       unsigned Element1, Element2, Element3, Element4;
203       Element1 = 0x00ff & Val;
204       Element2 = 0x00ff & (Val >> 8);
205       Element3 = 0x00ff & (Val >> 16);
206       Element4 = 0x00ff & (Val >> 24);
207       if (IsRomData)
208         O << 0 <<", "<< Element1 <<", "<< 0 <<", "<< Element2 <<", "<< 0 
209           <<", "<< Element3 <<", "<< 0 <<", "<< Element4;
210       else 
211         O << Element1 <<", "<< Element2 <<", "<< Element3 <<", "<< Element4;    
212     }
213     return;
214   }
215   AsmPrinter::EmitConstantValueOnly(CV);
216 }
217
218 void PIC16AsmPrinter::EmitRomData (Module &M)
219 {
220   std::string romDataSection = "romdata.#";
221   SwitchToRomDataSection(romDataSection.c_str());
222   IsRomData = true;
223   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
224        I != E; ++I) {
225     if (!I->hasInitializer())   // External global require no code.
226       continue;
227
228     Constant *C = I->getInitializer();
229     const PointerType *PtrTy = I->getType();
230     int AddrSpace = PtrTy->getAddressSpace();
231     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::ROM_SPACE)) {
232
233       if (EmitSpecialLLVMGlobal(I))
234         continue;
235
236       // Any variables reaching here with "." in its name is a local scope
237       // variable and should not be printed in global data section.
238       std::string name = Mang->getValueName(I);
239       if (name.find(".") != std::string::npos)
240         continue;
241
242       O << name;
243       EmitGlobalConstant(C);
244       O << "\n";
245     }
246   }
247   IsRomData = false;
248 }
249
250
251 void PIC16AsmPrinter::EmitUnInitData (Module &M)
252 {
253   std::string uDataSection = "udata.#";
254   SwitchToUDataSection(uDataSection.c_str());
255   const TargetData *TD = TM.getTargetData();
256
257   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
258        I != E; ++I) {
259     if (!I->hasInitializer())   // External global require no code.
260       continue;
261
262     Constant *C = I->getInitializer();
263     if (C->isNullValue()) {
264
265       if (EmitSpecialLLVMGlobal(I))
266         continue;
267
268       // Any variables reaching here with "." in its name is a local scope
269       // variable and should not be printed in global data section.
270       std::string name = Mang->getValueName(I);
271       if (name.find(".") != std::string::npos)
272         continue;
273
274       const Type *Ty = C->getType();
275       unsigned Size = TD->getABITypeSize(Ty);
276       O << name << " " <<"RES"<< " " << Size ;
277       O << "\n";
278     }
279   }
280 }
281
282 bool PIC16AsmPrinter::doFinalization(Module &M) {
283   O << "\t" << "END\n";
284   bool Result = AsmPrinter::doFinalization(M);
285   return Result;
286 }
287
288 void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) {
289   const Function *F = MF.getFunction();
290   std::string FuncName = Mang->getValueName(F);
291   const Module *M = F->getParent();
292   const TargetData *TD = TM.getTargetData();
293
294   // Emit the data section name.
295   O << "\n"; 
296   std::string fDataSection = "fdata." + CurrentFnName + ".#";
297   SwitchToUDataSection(fDataSection.c_str(), F);
298   // Emit the label for data section of current function.
299   O << "_frame_" << CurrentFnName << ":" ;
300   O << "\n";
301
302   // Emit the function variables. 
303    
304   if (F->hasExternalLinkage()) {
305     O << "\t" << "GLOBAL _frame_"  << CurrentFnName << "\n";
306     O << "\t" << "GLOBAL _"  << CurrentFnName << "\n";
307   }
308   // In PIC16 all the function arguments and local variables are global.
309   // Therefore to get the variable belonging to this function entire
310   // global list will be traversed and variables belonging to this function
311   // will be emitted in the current data section.
312   for (Module::const_global_iterator I = M->global_begin(), E = M->global_end();
313        I != E; ++I) {
314     std::string VarName = Mang->getValueName(I);
315     
316     // The variables of a function are of form FuncName.* . If this variable
317     // does not belong to this function then continue. 
318     if (!(VarName.find(FuncName + ".") == 0 ? true : false))
319       continue;
320    
321     Constant *C = I->getInitializer();
322     const Type *Ty = C->getType();
323     unsigned Size = TD->getABITypeSize(Ty);
324     // Emit memory reserve directive.
325     O << VarName << "  RES  " << Size << "\n";
326   }
327   emitFunctionTempData(MF);
328 }
329
330 void PIC16AsmPrinter::emitFunctionTempData(MachineFunction &MF) {
331   // Emit temporary variables.
332   MachineFrameInfo *FrameInfo = MF.getFrameInfo();
333   if (FrameInfo->hasStackObjects()) {
334     int indexBegin = FrameInfo->getObjectIndexBegin();
335     int indexEnd = FrameInfo->getObjectIndexEnd();
336
337     if (indexBegin < indexEnd)
338       O << CurrentFnName << ".tmp RES"<< " " 
339         <<indexEnd - indexBegin <<"\n";
340     /*
341     while (indexBegin < indexEnd) {
342         O << CurrentFnName << "_tmp_" << indexBegin << " " << "RES"<< " " 
343           << 1 << "\n" ;
344         indexBegin++;
345     }
346     */
347   }
348 }
349
350 /// The function is same as AsmPrinter::SwitchtoDataSection except the call
351 /// to getUDataSectionStartSuffix.
352 void PIC16AsmPrinter::SwitchToUDataSection(const char *NewSection,
353                                            const GlobalValue *GV) {
354   std::string NS;
355   if (GV && GV->hasSection())
356     NS = TAI->getSwitchToSectionDirective() + GV->getSection();
357   else
358     NS = NewSection;
359
360   // If we're already in this section, we're done.
361   if (CurrentSection == NS) return;
362
363   // Close the current section, if applicable.
364   if (TAI->getSectionEndDirectiveSuffix() && !CurrentSection.empty())
365     O << CurrentSection << TAI->getSectionEndDirectiveSuffix() << '\n';
366
367   CurrentSection = NS;
368
369   if (!CurrentSection.empty()){}
370     O << CurrentSection << (static_cast<const PIC16TargetAsmInfo *>(TAI))->
371                             getUDataSectionStartSuffix() << '\n';
372
373   IsInTextSection = false;
374 }
375
376 /// The function is same as AsmPrinter::SwitchtoDataSection except the call
377 /// to getRomDataSectionStartSuffix.
378 void PIC16AsmPrinter::SwitchToRomDataSection(const char *NewSection,
379                                              const GlobalValue *GV) {
380   std::string NS;
381   if (GV && GV->hasSection())
382     NS = TAI->getSwitchToSectionDirective() + GV->getSection();
383   else
384     NS = NewSection;
385
386   // If we're already in this section, we're done.
387   if (CurrentSection == NS) return;
388
389   // Close the current section, if applicable.
390   if (TAI->getSectionEndDirectiveSuffix() && !CurrentSection.empty())
391     O << CurrentSection << TAI->getSectionEndDirectiveSuffix() << '\n';
392
393   CurrentSection = NS;
394
395   if (!CurrentSection.empty()) {}
396     O << CurrentSection << (static_cast< const PIC16TargetAsmInfo *>(TAI))->
397                             getRomDataSectionStartSuffix() << '\n';
398
399   IsInTextSection = false;
400 }
401