blob: b96ae54005ec9cf39c1df49e7143dd75d80dcdb1 [file] [log] [blame]
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +00001//===-- 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"
Chris Lattner19435562009-08-15 06:13:40 +000016#include "MCSectionPIC16.h"
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000017#include "PIC16TargetAsmInfo.h"
18#include "llvm/DerivedTypes.h"
19#include "llvm/Function.h"
20#include "llvm/Module.h"
21#include "llvm/CodeGen/DwarfWriter.h"
22#include "llvm/CodeGen/MachineFrameInfo.h"
23#include "llvm/CodeGen/DwarfWriter.h"
24#include "llvm/CodeGen/MachineModuleInfo.h"
Chris Lattner73266f92009-08-19 05:49:37 +000025#include "llvm/MC/MCStreamer.h"
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000026#include "llvm/Target/TargetRegistry.h"
27#include "llvm/Target/TargetLoweringObjectFile.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/Support/FormattedStream.h"
30#include "llvm/Support/Mangler.h"
31#include <cstring>
32using namespace llvm;
33
34#include "PIC16GenAsmWriter.inc"
35
36PIC16AsmPrinter::PIC16AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
37 const TargetAsmInfo *T, bool V)
38: AsmPrinter(O, TM, T, V), DbgInfo(O, T) {
39 PTLI = static_cast<PIC16TargetLowering*>(TM.getTargetLowering());
40 PTAI = static_cast<const PIC16TargetAsmInfo*>(T);
41 PTOF = (PIC16TargetObjectFile*)&PTLI->getObjFileLowering();
Sanjiv Guptab42cab92009-08-20 19:28:24 +000042 CurrentFnPtr = NULL;
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000043}
44
45bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
46 printInstruction(MI);
47 return true;
48}
49
50/// runOnMachineFunction - This emits the frame section, autos section and
51/// assembly for each instruction. Also takes care of function begin debug
52/// directive and file begin debug directive (if required) for the function.
53///
54bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
55 this->MF = &MF;
56
57 // This calls the base class function required to be called at beginning
58 // of runOnMachineFunction.
59 SetupMachineFunction(MF);
60
61 // Get the mangled name.
62 const Function *F = MF.getFunction();
63 CurrentFnName = Mang->getMangledName(F);
Sanjiv Guptab42cab92009-08-20 19:28:24 +000064 CurrentFnPtr = F;
65
66 // Current function name was mangled in llvm-ld for both
67 // MainLine and InterruptLine and should be demangled here
68 PAN::updateCallLineSymbol(CurrentFnName, CurrentFnPtr);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000069
70 // Emit the function frame (args and temps).
71 EmitFunctionFrame(MF);
72
73 DbgInfo.BeginFunction(MF);
74
75 // Emit the autos section of function.
Chris Lattner08e63732009-08-21 23:08:09 +000076 EmitAutos(CurrentFnName);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000077
78 // Now emit the instructions of function in its code section.
79 const MCSection *fCodeSection =
Sanjiv Guptab42cab92009-08-20 19:28:24 +000080 getObjFileLowering().getSectionForFunction(CurrentFnName,
81 PAN::isISR(F));
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000082 // Start the Code Section.
83 O << "\n";
Chris Lattner73266f92009-08-19 05:49:37 +000084 OutStreamer.SwitchSection(fCodeSection);
Sanjiv Guptab42cab92009-08-20 19:28:24 +000085
86 // If it is not an interrupt function then emit the data address
87 // retrieval code in function code itself.
88 if (!(PAN::isISR(F))) {
89 // Emit the frame address of the function at the beginning of code.
90 O << "\tretlw low(" << PAN::getFrameLabel(CurrentFnName) << ")\n";
91 O << "\tretlw high(" << PAN::getFrameLabel(CurrentFnName) << ")\n";
92 }
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000093
94 // Emit function start label.
95 O << CurrentFnName << ":\n";
Sanjiv Guptab42cab92009-08-20 19:28:24 +000096
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +000097 DebugLoc CurDL;
98 O << "\n";
99 // Print out code for the function.
100 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
101 I != E; ++I) {
102
103 // Print a label for the basic block.
104 if (I != MF.begin()) {
105 printBasicBlockLabel(I, true);
106 O << '\n';
107 }
108
109 // Print a basic block.
110 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
111 II != E; ++II) {
112
113 // Emit the line directive if source line changed.
114 const DebugLoc DL = II->getDebugLoc();
115 if (!DL.isUnknown() && DL != CurDL) {
116 DbgInfo.ChangeDebugLoc(MF, DL);
117 CurDL = DL;
118 }
119
120 // Print the assembly for the instruction.
121 printMachineInstruction(II);
122 }
123 }
124
125 // Emit function end debug directives.
126 DbgInfo.EndFunction(MF);
127
128 return false; // we didn't modify anything.
129}
130
131
132// printOperand - print operand of insn.
133void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
134 const MachineOperand &MO = MI->getOperand(opNum);
135
136 switch (MO.getType()) {
137 case MachineOperand::MO_Register:
138 if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
139 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
140 else
141 llvm_unreachable("not implemented");
142 return;
143
144 case MachineOperand::MO_Immediate:
145 O << (int)MO.getImm();
146 return;
147
148 case MachineOperand::MO_GlobalAddress: {
149 std::string Sname = Mang->getMangledName(MO.getGlobal());
150 // FIXME: currently we do not have a memcpy def coming in the module
151 // by any chance, as we do not link in those as .bc lib. So these calls
152 // are always external and it is safe to emit an extern.
153 if (PAN::isMemIntrinsic(Sname)) {
154 LibcallDecls.push_back(createESName(Sname));
155 }
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000156 // All the call sites were mangled in llvm-ld pass hence the
157 // operands for call instructions should be demangled here.
158 PAN::updateCallLineSymbol(Sname, CurrentFnPtr);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000159 O << Sname;
160 break;
161 }
162 case MachineOperand::MO_ExternalSymbol: {
163 const char *Sname = MO.getSymbolName();
164
165 // If its a libcall name, record it to decls section.
166 if (PAN::getSymbolTag(Sname) == PAN::LIBCALL) {
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000167 // LibCallDecls for InterruptLine functions should have ".IL" suffix
168 const char *NewName= PAN::getUpdatedLibCallDecl(Sname, CurrentFnPtr);
169 LibcallDecls.push_back(NewName);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000170 }
171
172 // Record a call to intrinsic to print the extern declaration for it.
173 std::string Sym = Sname;
174 if (PAN::isMemIntrinsic(Sym)) {
175 Sym = PAN::addPrefix(Sym);
176 LibcallDecls.push_back(createESName(Sym));
177 }
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000178 // Update the library call symbols. Library calls to InterruptLine
179 // functions are different. (They have ".IL" in their names)
180 // Also other symbols (frame and temp) for the cloned function
181 // should be updated here.
182 PAN::updateCallLineSymbol(Sym, CurrentFnPtr);
183 O << Sym;
184 break;
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000185 }
186 case MachineOperand::MO_MachineBasicBlock:
187 printBasicBlockLabel(MO.getMBB());
188 return;
189
190 default:
191 llvm_unreachable(" Operand type not supported.");
192 }
193}
194
195/// printCCOperand - Print the cond code operand.
196///
197void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
198 int CC = (int)MI->getOperand(opNum).getImm();
199 O << PIC16CondCodeToString((PIC16CC::CondCodes)CC);
200}
201
202// This function is used to sort the decls list.
203// should return true if s1 should come before s2.
204static bool is_before(const char *s1, const char *s2) {
205 return strcmp(s1, s2) <= 0;
206}
207
208// This is used by list::unique below.
209// unique will filter out duplicates if it knows them.
210static bool is_duplicate(const char *s1, const char *s2) {
211 return !strcmp(s1, s2);
212}
213
214/// printLibcallDecls - print the extern declarations for compiler
215/// intrinsics.
216///
217void PIC16AsmPrinter::printLibcallDecls() {
218 // If no libcalls used, return.
219 if (LibcallDecls.empty()) return;
220
221 O << TAI->getCommentString() << "External decls for libcalls - BEGIN." <<"\n";
222 // Remove duplicate entries.
223 LibcallDecls.sort(is_before);
224 LibcallDecls.unique(is_duplicate);
225
226 for (std::list<const char*>::const_iterator I = LibcallDecls.begin();
227 I != LibcallDecls.end(); I++) {
228 O << TAI->getExternDirective() << *I << "\n";
229 O << TAI->getExternDirective() << PAN::getArgsLabel(*I) << "\n";
230 O << TAI->getExternDirective() << PAN::getRetvalLabel(*I) << "\n";
231 }
232 O << TAI->getCommentString() << "External decls for libcalls - END." <<"\n";
233}
234
235/// doInitialization - Perfrom Module level initializations here.
236/// One task that we do here is to sectionize all global variables.
237/// The MemSelOptimizer pass depends on the sectionizing.
238///
239bool PIC16AsmPrinter::doInitialization(Module &M) {
240 bool Result = AsmPrinter::doInitialization(M);
241
242 // FIXME:: This is temporary solution to generate the include file.
243 // The processor should be passed to llc as in input and the header file
244 // should be generated accordingly.
245 O << "\n\t#include P16F1937.INC\n";
246
247 // Set the section names for all globals.
248 for (Module::global_iterator I = M.global_begin(), E = M.global_end();
249 I != E; ++I)
250 if (!I->isDeclaration() && !I->hasAvailableExternallyLinkage()) {
251 const MCSection *S = getObjFileLowering().SectionForGlobal(I, Mang, TM);
252
253 I->setSection(((const MCSectionPIC16*)S)->getName());
254 }
255
256 DbgInfo.BeginModule(M);
257 EmitFunctionDecls(M);
258 EmitUndefinedVars(M);
259 EmitDefinedVars(M);
260 EmitIData(M);
261 EmitUData(M);
262 EmitRomData(M);
263 return Result;
264}
265
266/// Emit extern decls for functions imported from other modules, and emit
267/// global declarations for function defined in this module and which are
268/// available to other modules.
269///
270void PIC16AsmPrinter::EmitFunctionDecls(Module &M) {
271 // Emit declarations for external functions.
272 O <<"\n"<<TAI->getCommentString() << "Function Declarations - BEGIN." <<"\n";
273 for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) {
274 if (I->isIntrinsic())
275 continue;
276
277 std::string Name = Mang->getMangledName(I);
278 if (Name.compare("@abort") == 0)
279 continue;
280
281 if (!I->isDeclaration() && !I->hasExternalLinkage())
282 continue;
283
284 // Do not emit memcpy, memset, and memmove here.
285 // Calls to these routines can be generated in two ways,
286 // 1. User calling the standard lib function
287 // 2. Codegen generating these calls for llvm intrinsics.
288 // In the first case a prototype is alread availale, while in
289 // second case the call is via and externalsym and the prototype is missing.
290 // So declarations for these are currently always getting printing by
291 // tracking both kind of references in printInstrunction.
292 if (I->isDeclaration() && PAN::isMemIntrinsic(Name)) continue;
293
294 const char *directive = I->isDeclaration() ? TAI->getExternDirective() :
295 TAI->getGlobalDirective();
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000296
297 // This is called in initialization. Hence information of the current
298 // function line is not available. Hence UnspecifiedLine. UnspecifiedLine
299 // will be treated as MainLine.
300 PAN::updateCallLineSymbol(Name, PAN::UnspecifiedLine);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000301 O << directive << Name << "\n";
302 O << directive << PAN::getRetvalLabel(Name) << "\n";
303 O << directive << PAN::getArgsLabel(Name) << "\n";
304 }
305
306 O << TAI->getCommentString() << "Function Declarations - END." <<"\n";
307}
308
309// Emit variables imported from other Modules.
310void PIC16AsmPrinter::EmitUndefinedVars(Module &M) {
311 std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDecls->Items;
312 if (!Items.size()) return;
313
314 O << "\n" << TAI->getCommentString() << "Imported Variables - BEGIN" << "\n";
315 for (unsigned j = 0; j < Items.size(); j++) {
316 O << TAI->getExternDirective() << Mang->getMangledName(Items[j]) << "\n";
317 }
318 O << TAI->getCommentString() << "Imported Variables - END" << "\n";
319}
320
321// Emit variables defined in this module and are available to other modules.
322void PIC16AsmPrinter::EmitDefinedVars(Module &M) {
323 std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDefs->Items;
324 if (!Items.size()) return;
325
326 O << "\n" << TAI->getCommentString() << "Exported Variables - BEGIN" << "\n";
327 for (unsigned j = 0; j < Items.size(); j++) {
328 O << TAI->getGlobalDirective() << Mang->getMangledName(Items[j]) << "\n";
329 }
330 O << TAI->getCommentString() << "Exported Variables - END" << "\n";
331}
332
333// Emit initialized data placed in ROM.
334void PIC16AsmPrinter::EmitRomData(Module &M) {
335 // Print ROM Data section.
336 const std::vector<PIC16Section*> &ROSections = PTOF->ROSections;
337 for (unsigned i = 0; i < ROSections.size(); i++) {
338 const std::vector<const GlobalVariable*> &Items = ROSections[i]->Items;
339 if (!Items.size()) continue;
340 O << "\n";
Chris Lattner73266f92009-08-19 05:49:37 +0000341 OutStreamer.SwitchSection(PTOF->ROSections[i]->S_);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000342 for (unsigned j = 0; j < Items.size(); j++) {
343 O << Mang->getMangledName(Items[j]);
344 Constant *C = Items[j]->getInitializer();
345 int AddrSpace = Items[j]->getType()->getAddressSpace();
346 EmitGlobalConstant(C, AddrSpace);
347 }
348 }
349}
350
351bool PIC16AsmPrinter::doFinalization(Module &M) {
352 printLibcallDecls();
353 EmitRemainingAutos();
354 DbgInfo.EndModule(M);
355 O << "\n\t" << "END\n";
356 return AsmPrinter::doFinalization(M);
357}
358
359void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) {
360 const Function *F = MF.getFunction();
361 std::string FuncName = Mang->getMangledName(F);
362 const TargetData *TD = TM.getTargetData();
363 // Emit the data section name.
364 O << "\n";
Chris Lattner08e63732009-08-21 23:08:09 +0000365
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000366 const MCSection *fPDataSection =
Chris Lattner08e63732009-08-21 23:08:09 +0000367 getObjFileLowering().getSectionForFunctionFrame(CurrentFnName);
Chris Lattner73266f92009-08-19 05:49:37 +0000368 OutStreamer.SwitchSection(fPDataSection);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000369
370 // Emit function frame label
371 O << PAN::getFrameLabel(CurrentFnName) << ":\n";
372
373 const Type *RetType = F->getReturnType();
374 unsigned RetSize = 0;
375 if (RetType->getTypeID() != Type::VoidTyID)
376 RetSize = TD->getTypeAllocSize(RetType);
377
378 //Emit function return value space
379 // FIXME: Do not emit RetvalLable when retsize is zero. To do this
380 // we will need to avoid printing a global directive for Retval label
381 // in emitExternandGloblas.
382 if(RetSize > 0)
383 O << PAN::getRetvalLabel(CurrentFnName) << " RES " << RetSize << "\n";
384 else
385 O << PAN::getRetvalLabel(CurrentFnName) << ": \n";
386
387 // Emit variable to hold the space for function arguments
388 unsigned ArgSize = 0;
389 for (Function::const_arg_iterator argi = F->arg_begin(),
390 arge = F->arg_end(); argi != arge ; ++argi) {
391 const Type *Ty = argi->getType();
392 ArgSize += TD->getTypeAllocSize(Ty);
393 }
394
395 O << PAN::getArgsLabel(CurrentFnName) << " RES " << ArgSize << "\n";
396
397 // Emit temporary space
398 int TempSize = PTLI->GetTmpSize();
399 if (TempSize > 0)
400 O << PAN::getTempdataLabel(CurrentFnName) << " RES " << TempSize << '\n';
401}
402
403void PIC16AsmPrinter::EmitIData(Module &M) {
404
405 // Print all IDATA sections.
406 const std::vector<PIC16Section*> &IDATASections = PTOF->IDATASections;
407 for (unsigned i = 0; i < IDATASections.size(); i++) {
408 O << "\n";
409 if (IDATASections[i]->S_->getName().find("llvm.") != std::string::npos)
410 continue;
Chris Lattner73266f92009-08-19 05:49:37 +0000411 OutStreamer.SwitchSection(IDATASections[i]->S_);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000412 std::vector<const GlobalVariable*> Items = IDATASections[i]->Items;
413 for (unsigned j = 0; j < Items.size(); j++) {
414 std::string Name = Mang->getMangledName(Items[j]);
415 Constant *C = Items[j]->getInitializer();
416 int AddrSpace = Items[j]->getType()->getAddressSpace();
417 O << Name;
418 EmitGlobalConstant(C, AddrSpace);
419 }
420 }
421}
422
423void PIC16AsmPrinter::EmitUData(Module &M) {
424 const TargetData *TD = TM.getTargetData();
425
426 // Print all BSS sections.
427 const std::vector<PIC16Section*> &BSSSections = PTOF->BSSSections;
428 for (unsigned i = 0; i < BSSSections.size(); i++) {
429 O << "\n";
Chris Lattner73266f92009-08-19 05:49:37 +0000430 OutStreamer.SwitchSection(BSSSections[i]->S_);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000431 std::vector<const GlobalVariable*> Items = BSSSections[i]->Items;
432 for (unsigned j = 0; j < Items.size(); j++) {
433 std::string Name = Mang->getMangledName(Items[j]);
434 Constant *C = Items[j]->getInitializer();
435 const Type *Ty = C->getType();
436 unsigned Size = TD->getTypeAllocSize(Ty);
437
438 O << Name << " RES " << Size << "\n";
439 }
440 }
441}
442
Chris Lattner08e63732009-08-21 23:08:09 +0000443void PIC16AsmPrinter::EmitAutos(std::string FunctName) {
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000444 // Section names for all globals are already set.
445 const TargetData *TD = TM.getTargetData();
446
447 // Now print Autos section for this function.
Chris Lattner08e63732009-08-21 23:08:09 +0000448 std::string SectionName = PAN::getAutosSectionName(FunctName);
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000449
450 // If this function is a cloned function then the name of auto section
451 // will not be present in the list of existing section. Hence this section
452 // should be cloned.
453 // This function will check and clone
454 PTOF->createClonedSectionForAutos(SectionName);
455
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000456 const std::vector<PIC16Section*> &AutosSections = PTOF->AutosSections;
457 for (unsigned i = 0; i < AutosSections.size(); i++) {
458 O << "\n";
459 if (AutosSections[i]->S_->getName() == SectionName) {
460 // Set the printing status to true
461 AutosSections[i]->setPrintedStatus(true);
Chris Lattner73266f92009-08-19 05:49:37 +0000462 OutStreamer.SwitchSection(AutosSections[i]->S_);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000463 const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items;
464 for (unsigned j = 0; j < Items.size(); j++) {
465 std::string VarName = Mang->getMangledName(Items[j]);
466 Constant *C = Items[j]->getInitializer();
467 const Type *Ty = C->getType();
468 unsigned Size = TD->getTypeAllocSize(Ty);
Sanjiv Guptab42cab92009-08-20 19:28:24 +0000469 // Auto variables should be cloned for the cloned function
470 PAN::updateCallLineAutos(VarName, CurrentFnName);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000471 // Emit memory reserve directive.
472 O << VarName << " RES " << Size << "\n";
473 }
474 break;
475 }
476 }
477}
478
479// Print autos that were not printed during the code printing of functions.
480// As the functions might themselves would have got deleted by the optimizer.
481void PIC16AsmPrinter::EmitRemainingAutos() {
482 const TargetData *TD = TM.getTargetData();
483
484 // Now print Autos section for this function.
485 std::vector <PIC16Section *>AutosSections = PTOF->AutosSections;
486 for (unsigned i = 0; i < AutosSections.size(); i++) {
487
488 // if the section is already printed then don't print again
489 if (AutosSections[i]->isPrinted())
490 continue;
491
492 // Set status as printed
493 AutosSections[i]->setPrintedStatus(true);
494
495 O << "\n";
Chris Lattner73266f92009-08-19 05:49:37 +0000496 OutStreamer.SwitchSection(AutosSections[i]->S_);
Sanjiv Gupta8aae07e2009-08-13 16:37:05 +0000497 const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items;
498 for (unsigned j = 0; j < Items.size(); j++) {
499 std::string VarName = Mang->getMangledName(Items[j]);
500 Constant *C = Items[j]->getInitializer();
501 const Type *Ty = C->getType();
502 unsigned Size = TD->getTypeAllocSize(Ty);
503 // Emit memory reserve directive.
504 O << VarName << " RES " << Size << "\n";
505 }
506 }
507}
508
509
510extern "C" void LLVMInitializePIC16AsmPrinter() {
511 RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target);
512}
513
514