1 //===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to PIC16 assembly language.
13 //===----------------------------------------------------------------------===//
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"
26 #include "PIC16GenAsmWriter.inc"
28 bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
29 std::string NewBankselLabel;
30 unsigned Operands = MI->getNumOperands();
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());
41 NewBankselLabel = Op.getSymbolName();
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
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;
52 printOperand(MI, Operands-2);
61 /// runOnMachineFunction - This uses the printInstruction()
62 /// method to print assembly for each instruction.
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);
69 // Get the mangled name.
70 const Function *F = MF.getFunction();
71 CurrentFnName = Mang->getValueName(F);
73 // Emit the function variables.
75 std::string codeSection;
76 codeSection = "code." + CurrentFnName + ".#";
78 SwitchToTextSection (codeSection.c_str(),F);
80 // Print out code for the function.
81 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
83 // Print a label for the basic block.
84 if (I != MF.begin()) {
85 printBasicBlockLabel(I, true);
89 O << "_" << CurrentFnName << ":\n";
90 CurrentBankselLabelInBasicBlock = "";
91 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
93 // Print the assembly for the instruction.
94 printMachineInstruction(II);
97 return false; // we didn't modify anything.
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.
105 FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
106 PIC16TargetMachine &tm) {
107 return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
110 void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
111 const MachineOperand &MO = MI->getOperand(opNum);
113 switch (MO.getType()) {
114 case MachineOperand::MO_Register:
115 if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
116 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
118 assert(0 && "not implemented");
121 case MachineOperand::MO_Immediate:
122 O << (int)MO.getImm();
125 case MachineOperand::MO_GlobalAddress:
126 O << Mang->getValueName(MO.getGlobal());
129 case MachineOperand::MO_ExternalSymbol:
130 O << MO.getSymbolName();
134 assert(0 && " Operand type not supported.");
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";
151 void PIC16AsmPrinter::EmitInitData (Module &M)
153 std::string iDataSection = "idata.#";
154 SwitchToDataSection(iDataSection.c_str());
155 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
157 if (!I->hasInitializer()) // External global require no code.
160 Constant *C = I->getInitializer();
161 const PointerType *PtrTy = I->getType();
162 int AddrSpace = PtrTy->getAddressSpace();
164 if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) {
166 if (EmitSpecialLLVMGlobal(I))
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)
176 EmitGlobalConstant(C);
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();
186 // Expecting db directive here. In case of romdata we need to pad the
192 else if (BitWidth == 16) {
193 unsigned Element1, Element2;
194 Element1 = 0x00ff & Val;
195 Element2 = 0x00ff & (Val >> 8);
197 O << 0 <<", "<<Element1 <<", "<< 0 <<", "<< Element2;
199 O << Element1 <<", "<< Element2;
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);
208 O << 0 <<", "<< Element1 <<", "<< 0 <<", "<< Element2 <<", "<< 0
209 <<", "<< Element3 <<", "<< 0 <<", "<< Element4;
211 O << Element1 <<", "<< Element2 <<", "<< Element3 <<", "<< Element4;
215 AsmPrinter::EmitConstantValueOnly(CV);
218 void PIC16AsmPrinter::EmitRomData (Module &M)
220 std::string romDataSection = "romdata.#";
221 SwitchToRomDataSection(romDataSection.c_str());
223 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
225 if (!I->hasInitializer()) // External global require no code.
228 Constant *C = I->getInitializer();
229 const PointerType *PtrTy = I->getType();
230 int AddrSpace = PtrTy->getAddressSpace();
231 if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::ROM_SPACE)) {
233 if (EmitSpecialLLVMGlobal(I))
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)
243 EmitGlobalConstant(C);
251 void PIC16AsmPrinter::EmitUnInitData (Module &M)
253 std::string uDataSection = "udata.#";
254 SwitchToUDataSection(uDataSection.c_str());
255 const TargetData *TD = TM.getTargetData();
257 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
259 if (!I->hasInitializer()) // External global require no code.
262 Constant *C = I->getInitializer();
263 if (C->isNullValue()) {
265 if (EmitSpecialLLVMGlobal(I))
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)
274 const Type *Ty = C->getType();
275 unsigned Size = TD->getABITypeSize(Ty);
276 O << name << " " <<"RES"<< " " << Size ;
282 bool PIC16AsmPrinter::doFinalization(Module &M) {
283 O << "\t" << "END\n";
284 bool Result = AsmPrinter::doFinalization(M);
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();
294 // Emit the data section name.
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 << ":" ;
302 // Emit the function variables.
304 if (F->hasExternalLinkage()) {
305 O << "\t" << "GLOBAL _frame_" << CurrentFnName << "\n";
306 O << "\t" << "GLOBAL _" << CurrentFnName << "\n";
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();
314 std::string VarName = Mang->getValueName(I);
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))
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";
327 emitFunctionTempData(MF);
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();
337 if (indexBegin < indexEnd)
338 O << CurrentFnName << ".tmp RES"<< " "
339 <<indexEnd - indexBegin <<"\n";
341 while (indexBegin < indexEnd) {
342 O << CurrentFnName << "_tmp_" << indexBegin << " " << "RES"<< " "
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) {
355 if (GV && GV->hasSection())
356 NS = TAI->getSwitchToSectionDirective() + GV->getSection();
360 // If we're already in this section, we're done.
361 if (CurrentSection == NS) return;
363 // Close the current section, if applicable.
364 if (TAI->getSectionEndDirectiveSuffix() && !CurrentSection.empty())
365 O << CurrentSection << TAI->getSectionEndDirectiveSuffix() << '\n';
369 if (!CurrentSection.empty()){}
370 O << CurrentSection << (static_cast<const PIC16TargetAsmInfo *>(TAI))->
371 getUDataSectionStartSuffix() << '\n';
373 IsInTextSection = false;
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) {
381 if (GV && GV->hasSection())
382 NS = TAI->getSwitchToSectionDirective() + GV->getSection();
386 // If we're already in this section, we're done.
387 if (CurrentSection == NS) return;
389 // Close the current section, if applicable.
390 if (TAI->getSectionEndDirectiveSuffix() && !CurrentSection.empty())
391 O << CurrentSection << TAI->getSectionEndDirectiveSuffix() << '\n';
395 if (!CurrentSection.empty()) {}
396 O << CurrentSection << (static_cast< const PIC16TargetAsmInfo *>(TAI))->
397 getRomDataSectionStartSuffix() << '\n';
399 IsInTextSection = false;