| //===-- 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 "PIC16ISelLowering.h" |
| #include "PIC16TargetMachine.h" |
| #include "PIC16Section.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; |
| |
| |
| PIC16TargetObjectFile::PIC16TargetObjectFile() { |
| } |
| |
| PIC16TargetObjectFile::~PIC16TargetObjectFile() { |
| } |
| |
| /// Find a pic16 section. Return null if not found. Do not create one. |
| PIC16Section *PIC16TargetObjectFile:: |
| findPIC16Section(const std::string &Name) { |
| /// Return if we have an already existing one. |
| PIC16Section *Entry = SectionsByName[Name]; |
| if (Entry) |
| return Entry; |
| |
| return NULL; |
| } |
| |
| |
| /// Find a pic16 section. If not found, create one. |
| PIC16Section *PIC16TargetObjectFile:: |
| getPIC16Section(const std::string &Name, PIC16SectionType Ty, |
| const std::string &Address, int Color) const { |
| |
| /// Return if we have an already existing one. |
| PIC16Section *&Entry = SectionsByName[Name]; |
| if (Entry) |
| return Entry; |
| |
| |
| Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); |
| return Entry; |
| } |
| |
| /// Find a standard pic16 data section. If not found, create one and keep |
| /// track of it by adding it to appropriate std section list. |
| PIC16Section *PIC16TargetObjectFile:: |
| getPIC16DataSection(const std::string &Name, PIC16SectionType Ty, |
| const std::string &Address, int Color) const { |
| |
| /// Return if we have an already existing one. |
| PIC16Section *&Entry = SectionsByName[Name]; |
| if (Entry) |
| return Entry; |
| |
| |
| /// Else create a new one and add it to appropriate section list. |
| Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); |
| |
| switch (Ty) { |
| default: llvm_unreachable ("unknow standard section type."); |
| case UDATA: UDATASections_.push_back(Entry); break; |
| case IDATA: IDATASections_.push_back(Entry); break; |
| case ROMDATA: ROMDATASection_ = Entry; break; |
| case UDATA_SHR: SHAREDUDATASection_ = Entry; break; |
| } |
| |
| return Entry; |
| } |
| |
| |
| /// Find a standard pic16 autos section. If not found, create one and keep |
| /// track of it by adding it to appropriate std section list. |
| PIC16Section *PIC16TargetObjectFile:: |
| getPIC16AutoSection(const std::string &Name, PIC16SectionType Ty, |
| const std::string &Address, int Color) const { |
| |
| /// Return if we have an already existing one. |
| PIC16Section *&Entry = SectionsByName[Name]; |
| if (Entry) |
| return Entry; |
| |
| |
| /// Else create a new one and add it to appropriate section list. |
| Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); |
| |
| assert (Ty == UDATA_OVR && "incorrect section type for autos"); |
| AUTOSections_.push_back(Entry); |
| |
| return Entry; |
| } |
| |
| /// Find a pic16 user section. If not found, create one and keep |
| /// track of it by adding it to appropriate std section list. |
| PIC16Section *PIC16TargetObjectFile:: |
| getPIC16UserSection(const std::string &Name, PIC16SectionType Ty, |
| const std::string &Address, int Color) const { |
| |
| /// Return if we have an already existing one. |
| PIC16Section *&Entry = SectionsByName[Name]; |
| if (Entry) |
| return Entry; |
| |
| |
| /// Else create a new one and add it to appropriate section list. |
| Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); |
| |
| USERSections_.push_back(Entry); |
| |
| return Entry; |
| } |
| |
| /// Do some standard initialization. |
| void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ |
| TargetLoweringObjectFile::Initialize(Ctx, tm); |
| TM = &tm; |
| |
| ROMDATASection_ = NULL; |
| SHAREDUDATASection_ = NULL; |
| } |
| |
| /// allocateUDATA - Allocate a un-initialized global to an existing or new UDATA |
| /// section and return that section. |
| const MCSection * |
| PIC16TargetObjectFile::allocateUDATA(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 UDATA Sections and assign this variable |
| // to the first available section having enough space. |
| PIC16Section *Found = NULL; |
| for (unsigned i = 0; i < UDATASections_.size(); i++) { |
| if (DataBankSize - UDATASections_[i]->getSize() >= ValSize) { |
| Found = UDATASections_[i]; |
| break; |
| } |
| } |
| |
| // No UDATA section spacious enough was found. Crate a new one. |
| if (!Found) { |
| std::string name = PAN::getUdataSectionName(UDATASections_.size()); |
| Found = getPIC16DataSection(name.c_str(), UDATA); |
| } |
| |
| // Insert the GV into this UDATA section. |
| Found->Items.push_back(GV); |
| Found->setSize(Found->getSize() + ValSize); |
| return Found; |
| } |
| |
| /// allocateIDATA - allocate an initialized global into an existing |
| /// or new section and return that section. |
| const MCSection * |
| PIC16TargetObjectFile::allocateIDATA(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 allocate 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 *Found = NULL; |
| for (unsigned i = 0; i < IDATASections_.size(); i++) { |
| if (DataBankSize - IDATASections_[i]->getSize() >= ValSize) { |
| Found = IDATASections_[i]; |
| break; |
| } |
| } |
| |
| // No IDATA section spacious enough was found. Crate a new one. |
| if (!Found) { |
| std::string name = PAN::getIdataSectionName(IDATASections_.size()); |
| Found = getPIC16DataSection(name.c_str(), IDATA); |
| } |
| |
| // Insert the GV into this IDATA. |
| Found->Items.push_back(GV); |
| Found->setSize(Found->getSize() + ValSize); |
| return Found; |
| } |
| |
| // Allocate a program memory variable into ROMDATA section. |
| const MCSection * |
| PIC16TargetObjectFile::allocateROMDATA(const GlobalVariable *GV) const { |
| |
| std::string name = PAN::getRomdataSectionName(); |
| PIC16Section *S = getPIC16DataSection(name.c_str(), ROMDATA); |
| |
| S->Items.push_back(GV); |
| return S; |
| } |
| |
| // Get the section for an automatic variable of a function. |
| // For PIC16 they are globals only with mangled names. |
| const MCSection * |
| PIC16TargetObjectFile::allocateAUTO(const GlobalVariable *GV) const { |
| |
| const std::string name = PAN::getSectionNameForSym(GV->getName()); |
| PIC16Section *S = getPIC16AutoSection(name.c_str()); |
| |
| S->Items.push_back(GV); |
| return 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<GlobalVariable>(GV1); |
| if (!GV) |
| return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM); |
| |
| 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 allocateAUTO(GV); |
| |
| // See if this is an uninitialized global. |
| const Constant *C = GV->getInitializer(); |
| if (C->isNullValue()) |
| return allocateUDATA(GV); |
| |
| // If this is initialized data in RAM. Put it in the correct IDATA section. |
| if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) |
| return allocateIDATA(GV); |
| |
| // This is initialized data in rom, put it in the readonly section. |
| if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) |
| return allocateROMDATA(GV); |
| |
| // Else let the default implementation take care of it. |
| return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM); |
| } |
| |
| |
| |
| |
| /// getExplicitSectionGlobal - 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<GlobalVariable>(GV)) { |
| std::string SectName = GVar->getSection(); |
| // If address for a variable is specified, get the address and create |
| // section. |
| // FIXME: move this attribute checking in PAN. |
| std::string AddrStr = "Address="; |
| if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) { |
| std::string SectAddr = SectName.substr(AddrStr.length()); |
| if (SectAddr.compare("NEAR") == 0) |
| return allocateSHARED(GVar, Mang); |
| else |
| return allocateAtGivenAddress(GVar, SectAddr); |
| } |
| |
| // Create the section specified with section attribute. |
| return allocateInGivenSection(GVar); |
| } |
| |
| return getPIC16DataSection(GV->getSection().c_str(), UDATA); |
| } |
| |
| const MCSection * |
| PIC16TargetObjectFile::allocateSHARED(const GlobalVariable *GV, |
| Mangler *Mang) const { |
| // Make sure that this is an uninitialized global. |
| assert(GV->hasInitializer() && "This global doesn't need space"); |
| if (!GV->getInitializer()->isNullValue()) { |
| // FIXME: Generate a warning in this case that near qualifier will be |
| // ignored. |
| return SelectSectionForGlobal(GV, SectionKind::getDataRel(), Mang, *TM); |
| } |
| std::string Name = PAN::getSharedUDataSectionName(); |
| |
| PIC16Section *SharedUDataSect = getPIC16DataSection(Name.c_str(), UDATA_SHR); |
| // Insert the GV into shared section. |
| SharedUDataSect->Items.push_back(GV); |
| return SharedUDataSect; |
| } |
| |
| |
| // Interface used by AsmPrinter to get a code section for a function. |
| const PIC16Section * |
| PIC16TargetObjectFile::SectionForCode(const std::string &FnName) const { |
| const std::string &sec_name = PAN::getCodeSectionName(FnName); |
| return getPIC16Section(sec_name, CODE); |
| } |
| |
| // Interface used by AsmPrinter to get a frame section for a function. |
| const PIC16Section * |
| PIC16TargetObjectFile::SectionForFrame(const std::string &FnName) const { |
| const std::string &sec_name = PAN::getFrameSectionName(FnName); |
| return getPIC16Section(sec_name, UDATA_OVR); |
| } |
| |
| // Allocate a global var in existing or new section of given name. |
| const MCSection * |
| PIC16TargetObjectFile::allocateInGivenSection(const GlobalVariable *GV) const { |
| // Determine the type of section that we need to create. |
| PIC16SectionType SecTy; |
| |
| // See if this is an uninitialized global. |
| const Constant *C = GV->getInitializer(); |
| if (C->isNullValue()) |
| SecTy = UDATA; |
| // If this is initialized data in RAM. Put it in the correct IDATA section. |
| else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) |
| SecTy = IDATA; |
| // This is initialized data in rom, put it in the readonly section. |
| else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) |
| SecTy = ROMDATA; |
| else |
| llvm_unreachable ("Could not determine section type for global"); |
| |
| PIC16Section *S = getPIC16UserSection(GV->getSection().c_str(), SecTy); |
| S->Items.push_back(GV); |
| return S; |
| } |
| |
| // Allocate a global var in a new absolute sections at given address. |
| const MCSection * |
| PIC16TargetObjectFile::allocateAtGivenAddress(const GlobalVariable *GV, |
| const std::string &Addr) const { |
| // Determine the type of section that we need to create. |
| PIC16SectionType SecTy; |
| |
| // See if this is an uninitialized global. |
| const Constant *C = GV->getInitializer(); |
| if (C->isNullValue()) |
| SecTy = UDATA; |
| // If this is initialized data in RAM. Put it in the correct IDATA section. |
| else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) |
| SecTy = IDATA; |
| // This is initialized data in rom, put it in the readonly section. |
| else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) |
| SecTy = ROMDATA; |
| else |
| llvm_unreachable ("Could not determine section type for global"); |
| |
| std::string Prefix = GV->getNameStr() + "." + Addr + "."; |
| std::string SName = PAN::getUserSectionName(Prefix); |
| PIC16Section *S = getPIC16UserSection(SName.c_str(), SecTy, Addr.c_str()); |
| S->Items.push_back(GV); |
| return S; |
| } |
| |
| |