LLVM API Documentation

PIC16AsmPrinter.cpp

Go to the documentation of this file.
00001 //===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains a printer that converts from our internal representation
00011 // of machine-dependent LLVM code to PIC16 assembly language.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "PIC16AsmPrinter.h"
00016 #include "PIC16TargetAsmInfo.h"
00017 #include "llvm/Support/raw_ostream.h"
00018 #include "llvm/Support/Mangler.h"
00019 #include "llvm/Function.h"
00020 #include "llvm/Module.h"
00021 #include "llvm/CodeGen/MachineFrameInfo.h"
00022 #include "llvm/DerivedTypes.h"
00023 
00024 using namespace llvm;
00025 
00026 #include "PIC16GenAsmWriter.inc"
00027 bool PIC16AsmPrinter::inSameBank (char *s1, char *s2){
00028 
00029   assert (s1 && s2 && "Null pointer assignment");
00030 
00031   if ((*s1 == '.') && (*s2 == '.')) { //skip if they both start with '.'
00032     s1++;
00033     s2++;
00034   }
00035   while (*s1 && *s2) {
00036     if (*s1 != *s2) 
00037       goto _NotInSameBank;
00038 
00039     if ((*s1 == '.') && (*s2 == '.')) //both symbols in same function
00040       goto _InSameBank;               //in the same bank
00041 
00042     s1++;
00043     s2++;
00044   }
00045 
00046   if (*s1 && *s1) {
00047   _InSameBank:
00048     return true;
00049   }
00050 
00051  _NotInSameBank:
00052   return false;
00053 }
00054 
00055 bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
00056   std::string NewBankselLabel;
00057   unsigned Operands = MI->getNumOperands();
00058   if (Operands > 1) {
00059     // Global address or external symbol should be second operand from last
00060     // if we want to print banksel for it.
00061     const MachineOperand &Op = MI->getOperand(Operands-2);
00062     unsigned OpType = Op.getType();
00063     if (OpType == MachineOperand::MO_GlobalAddress ||
00064         OpType == MachineOperand::MO_ExternalSymbol) { 
00065       if (OpType == MachineOperand::MO_GlobalAddress ) 
00066         NewBankselLabel =  Mang->getValueName(Op.getGlobal());
00067       else 
00068         NewBankselLabel =  Op.getSymbolName();
00069 
00070       // Operand after global address or external symbol should be  banksel.
00071       // Value 1 for this operand means we need to generate banksel else do not
00072       // generate banksel.
00073       const MachineOperand &BS = MI->getOperand(Operands-1);
00074       if (((int)BS.getImm() == 1) &&
00075           (!inSameBank ((char *)CurrentBankselLabelInBasicBlock.c_str(),
00076       (char *)NewBankselLabel.c_str()))) {
00077         CurrentBankselLabelInBasicBlock = NewBankselLabel;
00078         O << "\tbanksel ";
00079         printOperand(MI, Operands-2);
00080         O << "\n";
00081       }
00082     }
00083   }
00084   printInstruction(MI);
00085   return true;
00086 }
00087 
00088 /// runOnMachineFunction - This uses the printInstruction()
00089 /// method to print assembly for each instruction.
00090 ///
00091 bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
00092   // This calls the base class function required to be called at beginning
00093   // of runOnMachineFunction.
00094   SetupMachineFunction(MF);
00095 
00096   // Get the mangled name.
00097   const Function *F = MF.getFunction();
00098   CurrentFnName = Mang->getValueName(F);
00099 
00100   // Emit the function variables.
00101   emitFunctionData(MF);
00102   std::string codeSection;
00103   codeSection = "code." + CurrentFnName + ".# " + "CODE";
00104   const Section *fCodeSection = TAI->getNamedSection(codeSection.c_str(),
00105                                                SectionFlags::Code);
00106   O <<  "\n";
00107   SwitchToSection (fCodeSection);
00108 
00109   // Print out code for the function.
00110   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
00111        I != E; ++I) {
00112     // Print a label for the basic block.
00113     if (I != MF.begin()) {
00114       printBasicBlockLabel(I, true);
00115       O << '\n';
00116     }
00117     else
00118       O << CurrentFnName << ":\n";
00119     CurrentBankselLabelInBasicBlock = "";
00120     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
00121          II != E; ++II) {
00122       // Print the assembly for the instruction.
00123         printMachineInstruction(II);
00124     }
00125   }
00126   return false;  // we didn't modify anything.
00127 }
00128 
00129 /// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
00130 /// assembly code for a MachineFunction to the given output stream,
00131 /// using the given target machine description.  This should work
00132 /// regardless of whether the function is in SSA form.
00133 ///
00134 FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
00135                                                PIC16TargetMachine &tm) {
00136   return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
00137 }
00138 
00139 void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
00140   const MachineOperand &MO = MI->getOperand(opNum);
00141 
00142   switch (MO.getType()) {
00143     case MachineOperand::MO_Register:
00144       if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
00145         O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
00146       else
00147         assert(0 && "not implemented");
00148         return;
00149 
00150     case MachineOperand::MO_Immediate:
00151       O << (int)MO.getImm();
00152       return;
00153 
00154     case MachineOperand::MO_GlobalAddress:
00155       O << Mang->getValueName(MO.getGlobal());
00156       break;
00157 
00158     case MachineOperand::MO_ExternalSymbol:
00159       O << MO.getSymbolName();
00160       break;
00161 
00162     case MachineOperand::MO_MachineBasicBlock:
00163       printBasicBlockLabel(MO.getMBB());
00164       return;
00165 
00166     default:
00167       assert(0 && " Operand type not supported.");
00168   }
00169 }
00170 
00171 void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
00172   int CC = (int)MI->getOperand(opNum).getImm();
00173   O << PIC16CondCodeToString((PIC16CC::CondCodes)CC);
00174 }
00175 
00176 
00177 bool PIC16AsmPrinter::doInitialization (Module &M) {
00178   bool Result = AsmPrinter::doInitialization(M);
00179   // FIXME:: This is temporary solution to generate the include file.
00180   // The processor should be passed to llc as in input and the header file
00181   // should be generated accordingly.
00182   O << "\t#include P16F1937.INC\n";
00183   EmitExternsAndGlobals (M);
00184   EmitInitData (M);
00185   EmitUnInitData(M);
00186   EmitRomData(M);
00187   return Result;
00188 }
00189 
00190 void PIC16AsmPrinter::EmitExternsAndGlobals (Module &M) {
00191  // Emit declarations for external functions.
00192   O << "section.0" <<"\n";
00193   for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) {
00194     std::string Name = Mang->getValueName(I);
00195     if (Name.compare("abort") == 0)
00196       continue;
00197     if (I->isDeclaration()) {
00198       O << "\textern " <<Name << "\n";
00199       O << "\textern " << Name << ".retval\n";
00200       O << "\textern " << Name << ".args\n";
00201     }
00202     else if (I->hasExternalLinkage()) {
00203       O << "\tglobal " << Name << "\n";
00204       O << "\tglobal " << Name << ".retval\n";
00205       O << "\tglobal " << Name << ".args\n";
00206     }
00207   }
00208 
00209   // Emit header file to include declaration of library functions
00210   O << "\t#include C16IntrinsicCalls.INC\n";
00211 
00212   // Emit declarations for external globals.
00213   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
00214        I != E; I++) {
00215     std::string Name = Mang->getValueName(I);
00216     if (I->isDeclaration())
00217       O << "\textern "<< Name << "\n";
00218     else if (I->getLinkage() == GlobalValue::CommonLinkage)
00219       O << "\tglobal "<< Name << "\n";
00220   }
00221 }
00222 void PIC16AsmPrinter::EmitInitData (Module &M) {
00223   SwitchToSection(TAI->getDataSection());
00224   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
00225        I != E; ++I) {
00226     if (!I->hasInitializer())   // External global require no code.
00227       continue;
00228 
00229     Constant *C = I->getInitializer();
00230     const PointerType *PtrTy = I->getType();
00231     int AddrSpace = PtrTy->getAddressSpace();
00232 
00233     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) {
00234     
00235       if (EmitSpecialLLVMGlobal(I)) 
00236         continue;
00237 
00238       // Any variables reaching here with "." in its name is a local scope
00239       // variable and should not be printed in global data section.
00240       std::string name = Mang->getValueName(I);
00241       if (name.find(".") != std::string::npos)
00242         continue;
00243 
00244       O << name;
00245       EmitGlobalConstant(C, AddrSpace);
00246     }
00247   }
00248 }
00249 
00250 void PIC16AsmPrinter::EmitRomData (Module &M)
00251 {
00252   SwitchToSection(TAI->getReadOnlySection());
00253   IsRomData = true;
00254   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
00255        I != E; ++I) {
00256     if (!I->hasInitializer())   // External global require no code.
00257       continue;
00258 
00259     Constant *C = I->getInitializer();
00260     const PointerType *PtrTy = I->getType();
00261     int AddrSpace = PtrTy->getAddressSpace();
00262     if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::ROM_SPACE)) {
00263 
00264       if (EmitSpecialLLVMGlobal(I))
00265         continue;
00266 
00267       // Any variables reaching here with "." in its name is a local scope
00268       // variable and should not be printed in global data section.
00269       std::string name = Mang->getValueName(I);
00270       if (name.find(".") != std::string::npos)
00271         continue;
00272 
00273       O << name;
00274       EmitGlobalConstant(C, AddrSpace);
00275       O << "\n";
00276     }
00277   }
00278   IsRomData = false;
00279 }
00280 
00281 void PIC16AsmPrinter::EmitUnInitData (Module &M)
00282 {
00283   SwitchToSection(TAI->getBSSSection_());
00284   const TargetData *TD = TM.getTargetData();
00285 
00286   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
00287        I != E; ++I) {
00288     if (!I->hasInitializer())   // External global require no code.
00289       continue;
00290 
00291     Constant *C = I->getInitializer();
00292     if (C->isNullValue()) {
00293 
00294       if (EmitSpecialLLVMGlobal(I))
00295         continue;
00296 
00297       // Any variables reaching here with "." in its name is a local scope
00298       // variable and should not be printed in global data section.
00299       std::string name = Mang->getValueName(I);
00300       if (name.find(".") != std::string::npos)
00301         continue;
00302 
00303       const Type *Ty = C->getType();
00304       unsigned Size = TD->getTypePaddedSize(Ty);
00305 
00306       O << name << " " <<"RES"<< " " << Size ;
00307       O << "\n";
00308     }
00309   }
00310 }
00311 
00312 bool PIC16AsmPrinter::doFinalization(Module &M) {
00313   O << "\t" << "END\n";
00314   bool Result = AsmPrinter::doFinalization(M);
00315   return Result;
00316 }
00317 
00318 void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) {
00319   const Function *F = MF.getFunction();
00320   std::string FuncName = Mang->getValueName(F);
00321   const Module *M = F->getParent();
00322   const TargetData *TD = TM.getTargetData();
00323   unsigned FrameSize = 0;
00324   // Emit the data section name.
00325   O << "\n"; 
00326   std::string SectionName = "fdata." + CurrentFnName + ".# " + "UDATA";
00327 
00328   const Section *fDataSection = TAI->getNamedSection(SectionName.c_str(),
00329                                                SectionFlags::Writeable);
00330   SwitchToSection(fDataSection);
00331   
00332   //Emit function return value.
00333   O << CurrentFnName << ".retval:\n";
00334   const Type *RetType = F->getReturnType();
00335   unsigned RetSize = 0; 
00336   if (RetType->getTypeID() != Type::VoidTyID) 
00337     RetSize = TD->getTypePaddedSize(RetType);
00338   
00339   // Emit function arguments.
00340   O << CurrentFnName << ".args:\n";
00341   // Emit the function variables. 
00342    
00343   // In PIC16 all the function arguments and local variables are global.
00344   // Therefore to get the variable belonging to this function entire
00345   // global list will be traversed and variables belonging to this function
00346   // will be emitted in the current data section.
00347   for (Module::const_global_iterator I = M->global_begin(), E = M->global_end();
00348        I != E; ++I) {
00349     std::string VarName = Mang->getValueName(I);
00350     
00351     // The variables of a function are of form FuncName.* . If this variable
00352     // does not belong to this function then continue. 
00353     if (!(VarName.find(FuncName + ".") == 0 ? true : false))
00354       continue;
00355    
00356     Constant *C = I->getInitializer();
00357     const Type *Ty = C->getType();
00358     unsigned Size = TD->getTypePaddedSize(Ty);
00359     FrameSize += Size; 
00360     // Emit memory reserve directive.
00361     O << VarName << "  RES  " << Size << "\n";
00362   }
00363   emitFunctionTempData(MF, FrameSize);
00364   if (RetSize > FrameSize)
00365     O << CurrentFnName << ".dummy" << "RES" << (RetSize - FrameSize); 
00366 }
00367 
00368 void PIC16AsmPrinter::emitFunctionTempData(MachineFunction &MF,
00369                                            unsigned &FrameSize) {
00370   // Emit temporary variables.
00371   MachineFrameInfo *FrameInfo = MF.getFrameInfo();
00372   if (FrameInfo->hasStackObjects()) {
00373     int indexBegin = FrameInfo->getObjectIndexBegin();
00374     int indexEnd = FrameInfo->getObjectIndexEnd();
00375 
00376     if (indexBegin < indexEnd) { 
00377       FrameSize += indexEnd - indexBegin; 
00378       O << CurrentFnName << ".tmp RES"<< " " 
00379         <<indexEnd - indexBegin <<"\n";
00380     } 
00381     /*
00382     while (indexBegin < indexEnd) {
00383         O << CurrentFnName << "_tmp_" << indexBegin << " " << "RES"<< " " 
00384           << 1 << "\n" ;
00385         indexBegin++;
00386     }
00387     */
00388   }
00389 }