//===-- PIC16TargetObjectFile.cpp - PIC16 object files --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PIC16TargetObjectFile.h" #include "MCSectionPIC16.h" #include "PIC16ISelLowering.h" #include "PIC16TargetMachine.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; MCSectionPIC16 *MCSectionPIC16::Create(const StringRef &Name, SectionKind K, int Address, int Color, MCContext &Ctx) { return new (Ctx) MCSectionPIC16(Name, K, Address, Color); } void MCSectionPIC16::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { OS << getName() << '\n'; } PIC16TargetObjectFile::PIC16TargetObjectFile() : ExternalVarDecls(0), ExternalVarDefs(0) { } const MCSectionPIC16 *PIC16TargetObjectFile:: getPIC16Section(const char *Name, SectionKind Kind, int Address, int Color) const { MCSectionPIC16 *&Entry = SectionsByName[Name]; if (Entry) return Entry; return Entry = MCSectionPIC16::Create(Name, Kind, Address, Color, getContext()); } void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ TargetLoweringObjectFile::Initialize(Ctx, tm); TM = &tm; BSSSection = getPIC16Section("udata.# UDATA", MCSectionPIC16::UDATA_Kind()); ReadOnlySection = getPIC16Section("romdata.# ROMDATA", MCSectionPIC16::ROMDATA_Kind()); DataSection = getPIC16Section("idata.# IDATA", MCSectionPIC16::IDATA_Kind()); // Need because otherwise a .text symbol is emitted by DwarfWriter // in BeginModule, and gpasm cribbs for that .text symbol. TextSection = getPIC16Section("", SectionKind::getText()); ROSections.push_back(new PIC16Section((MCSectionPIC16*)ReadOnlySection)); // FIXME: I don't know what the classification of these sections really is. // These aren't really objects belonging to any section. Just emit them // in AsmPrinter and remove this code from here. ExternalVarDecls = new PIC16Section(getPIC16Section("ExternalVarDecls", SectionKind::getMetadata())); ExternalVarDefs = new PIC16Section(getPIC16Section("ExternalVarDefs", SectionKind::getMetadata())); } const MCSection *PIC16TargetObjectFile:: getSectionForFunction(const std::string &FnName) const { std::string T = PAN::getCodeSectionName(FnName); return getPIC16Section(T.c_str(), SectionKind::getText()); } const MCSection *PIC16TargetObjectFile:: getSectionForFunctionFrame(const std::string &FnName) const { std::string T = PAN::getFrameSectionName(FnName); return getPIC16Section(T.c_str(), SectionKind::getDataRel()); } const MCSection * PIC16TargetObjectFile::getBSSSectionForGlobal(const GlobalVariable *GV) const { assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(C->isNullValue() && "Unitialized globals has non-zero initializer"); // Find how much space this global needs. const TargetData *TD = TM->getTargetData(); const Type *Ty = C->getType(); unsigned ValSize = TD->getTypeAllocSize(Ty); // Go through all BSS Sections and assign this variable // to the first available section having enough space. PIC16Section *FoundBSS = NULL; for (unsigned i = 0; i < BSSSections.size(); i++) { if (DataBankSize - BSSSections[i]->Size >= ValSize) { FoundBSS = BSSSections[i]; break; } } // No BSS section spacious enough was found. Crate a new one. if (!FoundBSS) { std::string name = PAN::getUdataSectionName(BSSSections.size()); const MCSectionPIC16 *NewSection = getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_Kind()); FoundBSS = new PIC16Section(NewSection); // Add this newly created BSS section to the list of BSSSections. BSSSections.push_back(FoundBSS); } // Insert the GV into this BSS. FoundBSS->Items.push_back(GV); FoundBSS->Size += ValSize; return FoundBSS->S_; } const MCSection * PIC16TargetObjectFile::getIDATASectionForGlobal(const GlobalVariable *GV) const{ assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(!C->isNullValue() && "initialized globals has zero initializer"); assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && "can split initialized RAM data only"); // Find how much space this global needs. const TargetData *TD = TM->getTargetData(); const Type *Ty = C->getType(); unsigned ValSize = TD->getTypeAllocSize(Ty); // Go through all IDATA Sections and assign this variable // to the first available section having enough space. PIC16Section *FoundIDATA = NULL; for (unsigned i = 0; i < IDATASections.size(); i++) { if (DataBankSize - IDATASections[i]->Size >= ValSize) { FoundIDATA = IDATASections[i]; break; } } // No IDATA section spacious enough was found. Crate a new one. if (!FoundIDATA) { std::string name = PAN::getIdataSectionName(IDATASections.size()); const MCSectionPIC16 *NewSection = getPIC16Section(name.c_str(), MCSectionPIC16::IDATA_Kind()); FoundIDATA = new PIC16Section(NewSection); // Add this newly created IDATA section to the list of IDATASections. IDATASections.push_back(FoundIDATA); } // Insert the GV into this IDATA. FoundIDATA->Items.push_back(GV); FoundIDATA->Size += ValSize; return FoundIDATA->S_; } // Get the section for an automatic variable of a function. // For PIC16 they are globals only with mangled names. const MCSection * PIC16TargetObjectFile::getSectionForAuto(const GlobalVariable *GV) const { const std::string name = PAN::getSectionNameForSym(GV->getName()); // Go through all Auto Sections and assign this variable // to the appropriate section. PIC16Section *FoundAutoSec = NULL; for (unsigned i = 0; i < AutosSections.size(); i++) { if (AutosSections[i]->S_->getName() == name) { FoundAutoSec = AutosSections[i]; break; } } // No Auto section was found. Crate a new one. if (!FoundAutoSec) { const MCSectionPIC16 *NewSection = getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_OVR_Kind()); FoundAutoSec = new PIC16Section(NewSection); // Add this newly created autos section to the list of AutosSections. AutosSections.push_back(FoundAutoSec); } // Insert the auto into this section. FoundAutoSec->Items.push_back(GV); return FoundAutoSec->S_; } // Override default implementation to put the true globals into // multiple data sections if required. const MCSection * PIC16TargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV1, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { // We select the section based on the initializer here, so it really // has to be a GlobalVariable. const GlobalVariable *GV = dyn_cast(GV1); if (!GV) return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM); // Record External Var Decls. if (GV->isDeclaration()) { ExternalVarDecls->Items.push_back(GV); return ExternalVarDecls->S_; } assert(GV->hasInitializer() && "A def without initializer?"); // First, if this is an automatic variable for a function, get the section // name for it and return. std::string name = GV->getName(); if (PAN::isLocalName(name)) return getSectionForAuto(GV); // Record Exteranl Var Defs. if (GV->hasExternalLinkage() || GV->hasCommonLinkage()) ExternalVarDefs->Items.push_back(GV); // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) return getBSSSectionForGlobal(GV); // If this is initialized data in RAM. Put it in the correct IDATA section. if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) return getIDATASectionForGlobal(GV); // This is initialized data in rom, put it in the readonly section. if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) return getROSectionForGlobal(GV); // Else let the default implementation take care of it. return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM); } PIC16TargetObjectFile::~PIC16TargetObjectFile() { for (unsigned i = 0; i < BSSSections.size(); i++) delete BSSSections[i]; for (unsigned i = 0; i < IDATASections.size(); i++) delete IDATASections[i]; for (unsigned i = 0; i < AutosSections.size(); i++) delete AutosSections[i]; for (unsigned i = 0; i < ROSections.size(); i++) delete ROSections[i]; delete ExternalVarDecls; delete ExternalVarDefs; } /// getSpecialCasedSectionGlobals - Allow the target to completely override /// section assignment of a global. const MCSection *PIC16TargetObjectFile:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { assert(GV->hasSection()); if (const GlobalVariable *GVar = cast(GV)) { std::string SectName = GVar->getSection(); // If address for a variable is specified, get the address and create // section. std::string AddrStr = "Address="; if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) { std::string SectAddr = SectName.substr(AddrStr.length()); return CreateSectionForGlobal(GVar, Mang, SectAddr); } // Create the section specified with section attribute. return CreateSectionForGlobal(GVar, Mang); } return getPIC16Section(GV->getSection().c_str(), Kind); } // Create a new section for global variable. If Addr is given then create // section at that address else create by name. const MCSection * PIC16TargetObjectFile::CreateSectionForGlobal(const GlobalVariable *GV, Mangler *Mang, const std::string &Addr) const { // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) return CreateBSSSectionForGlobal(GV, Addr); // If this is initialized data in RAM. Put it in the correct IDATA section. if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) return CreateIDATASectionForGlobal(GV, Addr); // This is initialized data in rom, put it in the readonly section. if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) return CreateROSectionForGlobal(GV, Addr); // Else let the default implementation take care of it. return TargetLoweringObjectFile::SectionForGlobal(GV, Mang, *TM); } // Create uninitialized section for a variable. const MCSection * PIC16TargetObjectFile::CreateBSSSectionForGlobal(const GlobalVariable *GV, std::string Addr) const { assert(GV->hasInitializer() && "This global doesn't need space"); assert(GV->getInitializer()->isNullValue() && "Unitialized global has non-zero initializer"); std::string Name; // If address is given then create a section at that address else create a // section by section name specified in GV. PIC16Section *FoundBSS = NULL; if (Addr.empty()) { Name = GV->getSection() + " UDATA"; for (unsigned i = 0; i < BSSSections.size(); i++) { if (BSSSections[i]->S_->getName() == Name) { FoundBSS = BSSSections[i]; break; } } } else { std::string Prefix = GV->getNameStr() + "." + Addr + "."; Name = PAN::getUdataSectionName(BSSSections.size(), Prefix) + " " + Addr; } PIC16Section *NewBSS = FoundBSS; if (NewBSS == NULL) { const MCSectionPIC16 *NewSection = getPIC16Section(Name.c_str(), MCSectionPIC16::UDATA_Kind()); NewBSS = new PIC16Section(NewSection); BSSSections.push_back(NewBSS); } // Insert the GV into this BSS. NewBSS->Items.push_back(GV); // We do not want to put any GV without explicit section into this section // so set its size to DatabankSize. NewBSS->Size = DataBankSize; return NewBSS->S_; } // Get rom section for a variable. Currently there can be only one rom section // unless a variable explicitly requests a section. const MCSection * PIC16TargetObjectFile::getROSectionForGlobal(const GlobalVariable *GV) const { ROSections[0]->Items.push_back(GV); return ROSections[0]->S_; } // Create initialized data section for a variable. const MCSection * PIC16TargetObjectFile::CreateIDATASectionForGlobal(const GlobalVariable *GV, std::string Addr) const { assert(GV->hasInitializer() && "This global doesn't need space"); assert(!GV->getInitializer()->isNullValue() && "initialized global has zero initializer"); assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && "can be used for initialized RAM data only"); std::string Name; // If address is given then create a section at that address else create a // section by section name specified in GV. PIC16Section *FoundIDATASec = NULL; if (Addr.empty()) { Name = GV->getSection() + " IDATA"; for (unsigned i = 0; i < IDATASections.size(); i++) { if (IDATASections[i]->S_->getName() == Name) { FoundIDATASec = IDATASections[i]; break; } } } else { std::string Prefix = GV->getNameStr() + "." + Addr + "."; Name = PAN::getIdataSectionName(IDATASections.size(), Prefix) + " " + Addr; } PIC16Section *NewIDATASec = FoundIDATASec; if (NewIDATASec == NULL) { const MCSectionPIC16 *NewSection = getPIC16Section(Name.c_str(), MCSectionPIC16::IDATA_Kind()); NewIDATASec = new PIC16Section(NewSection); IDATASections.push_back(NewIDATASec); } // Insert the GV into this IDATA Section. NewIDATASec->Items.push_back(GV); // We do not want to put any GV without explicit section into this section // so set its size to DatabankSize. NewIDATASec->Size = DataBankSize; return NewIDATASec->S_; } // Create a section in rom for a variable. const MCSection * PIC16TargetObjectFile::CreateROSectionForGlobal(const GlobalVariable *GV, std::string Addr) const { assert(GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE && "can be used for ROM data only"); std::string Name; // If address is given then create a section at that address else create a // section by section name specified in GV. PIC16Section *FoundROSec = NULL; if (Addr.empty()) { Name = GV->getSection() + " ROMDATA"; for (unsigned i = 1; i < ROSections.size(); i++) { if (ROSections[i]->S_->getName() == Name) { FoundROSec = ROSections[i]; break; } } } else { std::string Prefix = GV->getNameStr() + "." + Addr + "."; Name = PAN::getRomdataSectionName(ROSections.size(), Prefix) + " " + Addr; } PIC16Section *NewRomSec = FoundROSec; if (NewRomSec == NULL) { const MCSectionPIC16 *NewSection = getPIC16Section(Name.c_str(), MCSectionPIC16::ROMDATA_Kind()); NewRomSec = new PIC16Section(NewSection); ROSections.push_back(NewRomSec); } // Insert the GV into this ROM Section. NewRomSec->Items.push_back(GV); return NewRomSec->S_; }