blob: 21f1902a9ec450c12d973a31975564345c70ae3d [file] [log] [blame]
Sanjiv Gupta0e687712008-05-13 09:02:57 +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
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +000015#include "PIC16AsmPrinter.h"
16#include "PIC16TargetAsmInfo.h"
Owen Andersoncb371882008-08-21 00:14:44 +000017#include "llvm/Support/raw_ostream.h"
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +000018#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"
Sanjiv Gupta0e687712008-05-13 09:02:57 +000023
24using namespace llvm;
25
Sanjiv Gupta0e687712008-05-13 09:02:57 +000026#include "PIC16GenAsmWriter.inc"
27
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +000028bool 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///
64bool 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
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000100/// 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///
Owen Andersoncb371882008-08-21 00:14:44 +0000105FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000106 PIC16TargetMachine &tm) {
107 return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
108}
109
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000110void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000111 const MachineOperand &MO = MI->getOperand(opNum);
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000112
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000113 switch (MO.getType()) {
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000114 case MachineOperand::MO_Register:
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000115 if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000116 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000117 else
118 assert(0 && "not implemented");
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000119 return;
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000120
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000121 case MachineOperand::MO_Immediate:
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000122 O << (int)MO.getImm();
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000123 return;
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000124
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000125 case MachineOperand::MO_GlobalAddress:
126 O << Mang->getValueName(MO.getGlobal());
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000127 break;
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000128
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000129 case MachineOperand::MO_ExternalSymbol:
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000130 O << MO.getSymbolName();
131 break;
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000132
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000133 default:
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000134 assert(0 && " Operand type not supported.");
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000135 }
136}
137
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000138bool PIC16AsmPrinter::doInitialization (Module &M) {
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000139 bool Result = AsmPrinter::doInitialization(M);
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000140 // 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);
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000148 return Result;
149}
150
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000151void PIC16AsmPrinter::EmitInitData (Module &M)
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000152{
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000153 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
181void 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
218void 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
251void PIC16AsmPrinter::EmitUnInitData (Module &M)
252{
253 std::string uDataSection = "udata.#";
254 SwitchToUDataSection(uDataSection.c_str());
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000255 const TargetData *TD = TM.getTargetData();
256
257 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
258 I != E; ++I) {
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000259 if (!I->hasInitializer()) // External global require no code.
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000260 continue;
261
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000262 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";
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000278 }
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000279 }
280}
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000281
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000282bool PIC16AsmPrinter::doFinalization(Module &M) {
283 O << "\t" << "END\n";
284 bool Result = AsmPrinter::doFinalization(M);
285 return Result;
286}
287
288void 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
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000321 Constant *C = I->getInitializer();
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000322 const Type *Ty = C->getType();
323 unsigned Size = TD->getABITypeSize(Ty);
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000324 // Emit memory reserve directive.
325 O << VarName << " RES " << Size << "\n";
326 }
327 emitFunctionTempData(MF);
328}
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000329
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000330void 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();
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000336
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000337 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++;
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000345 }
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000346 */
347 }
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000348}
349
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000350/// The function is same as AsmPrinter::SwitchtoDataSection except the call
351/// to getUDataSectionStartSuffix.
352void PIC16AsmPrinter::SwitchToUDataSection(const char *NewSection,
353 const GlobalValue *GV) {
354 std::string NS;
355 if (GV && GV->hasSection())
356 NS = TAI->getSwitchToSectionDirective() + GV->getSection();
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000357 else
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000358 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;
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000374}
375
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000376/// The function is same as AsmPrinter::SwitchtoDataSection except the call
377/// to getRomDataSectionStartSuffix.
378void PIC16AsmPrinter::SwitchToRomDataSection(const char *NewSection,
379 const GlobalValue *GV) {
380 std::string NS;
381 if (GV && GV->hasSection())
382 NS = TAI->getSwitchToSectionDirective() + GV->getSection();
Sanjiv Gupta2010b3e2008-05-14 11:31:39 +0000383 else
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000384 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;
Sanjiv Gupta0e687712008-05-13 09:02:57 +0000400}
Sanjiv Guptab1b5ffd2008-11-19 11:00:54 +0000401