1 //===-- PIC16TargetObjectFile.cpp - PIC16 object files --------------------===//
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 #include "PIC16TargetObjectFile.h"
11 #include "PIC16TargetMachine.h"
12 #include "PIC16Section.h"
13 #include "llvm/DerivedTypes.h"
14 #include "llvm/Module.h"
15 #include "llvm/MC/MCSection.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/Support/raw_ostream.h"
21 PIC16TargetObjectFile::PIC16TargetObjectFile() {
24 PIC16TargetObjectFile::~PIC16TargetObjectFile() {
27 /// Find a pic16 section. Return null if not found. Do not create one.
28 PIC16Section *PIC16TargetObjectFile::
29 findPIC16Section(const std::string &Name) const {
30 /// Return if we have an already existing one.
31 PIC16Section *Entry = SectionsByName[Name];
39 /// Find a pic16 section. If not found, create one.
40 PIC16Section *PIC16TargetObjectFile::
41 getPIC16Section(const std::string &Name, PIC16SectionType Ty,
42 const std::string &Address, int Color) const {
44 /// Return if we have an already existing one.
45 PIC16Section *&Entry = SectionsByName[Name];
50 Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext());
54 /// Find a standard pic16 data section. If not found, create one and keep
55 /// track of it by adding it to appropriate std section list.
56 PIC16Section *PIC16TargetObjectFile::
57 getPIC16DataSection(const std::string &Name, PIC16SectionType Ty,
58 const std::string &Address, int Color) const {
60 /// Return if we have an already existing one.
61 PIC16Section *&Entry = SectionsByName[Name];
66 /// Else create a new one and add it to appropriate section list.
67 Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext());
70 default: llvm_unreachable ("unknow standard section type.");
71 case UDATA: UDATASections_.push_back(Entry); break;
72 case IDATA: IDATASections_.push_back(Entry); break;
73 case ROMDATA: ROMDATASection_ = Entry; break;
74 case UDATA_SHR: SHAREDUDATASection_ = Entry; break;
81 /// Find a standard pic16 autos section. If not found, create one and keep
82 /// track of it by adding it to appropriate std section list.
83 PIC16Section *PIC16TargetObjectFile::
84 getPIC16AutoSection(const std::string &Name, PIC16SectionType Ty,
85 const std::string &Address, int Color) const {
87 /// Return if we have an already existing one.
88 PIC16Section *&Entry = SectionsByName[Name];
93 /// Else create a new one and add it to appropriate section list.
94 Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext());
96 assert (Ty == UDATA_OVR && "incorrect section type for autos");
97 AUTOSections_.push_back(Entry);
102 /// Find a pic16 user section. If not found, create one and keep
103 /// track of it by adding it to appropriate std section list.
104 PIC16Section *PIC16TargetObjectFile::
105 getPIC16UserSection(const std::string &Name, PIC16SectionType Ty,
106 const std::string &Address, int Color) const {
108 /// Return if we have an already existing one.
109 PIC16Section *&Entry = SectionsByName[Name];
114 /// Else create a new one and add it to appropriate section list.
115 Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext());
117 USERSections_.push_back(Entry);
122 /// Do some standard initialization.
123 void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){
124 TargetLoweringObjectFile::Initialize(Ctx, tm);
127 ROMDATASection_ = NULL;
128 SHAREDUDATASection_ = NULL;
131 /// allocateUDATA - Allocate a un-initialized global to an existing or new UDATA
132 /// section and return that section.
134 PIC16TargetObjectFile::allocateUDATA(const GlobalVariable *GV) const {
135 assert(GV->hasInitializer() && "This global doesn't need space");
136 const Constant *C = GV->getInitializer();
137 assert(C->isNullValue() && "Unitialized globals has non-zero initializer");
139 // Find how much space this global needs.
140 const TargetData *TD = TM->getTargetData();
141 const Type *Ty = C->getType();
142 unsigned ValSize = TD->getTypeAllocSize(Ty);
144 // Go through all UDATA Sections and assign this variable
145 // to the first available section having enough space.
146 PIC16Section *Found = NULL;
147 for (unsigned i = 0; i < UDATASections_.size(); i++) {
148 if (DataBankSize - UDATASections_[i]->getSize() >= ValSize) {
149 Found = UDATASections_[i];
154 // No UDATA section spacious enough was found. Crate a new one.
156 std::string name = PAN::getUdataSectionName(UDATASections_.size());
157 Found = getPIC16DataSection(name.c_str(), UDATA);
160 // Insert the GV into this UDATA section.
161 Found->Items.push_back(GV);
162 Found->setSize(Found->getSize() + ValSize);
166 /// allocateIDATA - allocate an initialized global into an existing
167 /// or new section and return that section.
169 PIC16TargetObjectFile::allocateIDATA(const GlobalVariable *GV) const{
170 assert(GV->hasInitializer() && "This global doesn't need space");
171 const Constant *C = GV->getInitializer();
172 assert(!C->isNullValue() && "initialized globals has zero initializer");
173 assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE &&
174 "can allocate initialized RAM data only");
176 // Find how much space this global needs.
177 const TargetData *TD = TM->getTargetData();
178 const Type *Ty = C->getType();
179 unsigned ValSize = TD->getTypeAllocSize(Ty);
181 // Go through all IDATA Sections and assign this variable
182 // to the first available section having enough space.
183 PIC16Section *Found = NULL;
184 for (unsigned i = 0; i < IDATASections_.size(); i++) {
185 if (DataBankSize - IDATASections_[i]->getSize() >= ValSize) {
186 Found = IDATASections_[i];
191 // No IDATA section spacious enough was found. Crate a new one.
193 std::string name = PAN::getIdataSectionName(IDATASections_.size());
194 Found = getPIC16DataSection(name.c_str(), IDATA);
197 // Insert the GV into this IDATA.
198 Found->Items.push_back(GV);
199 Found->setSize(Found->getSize() + ValSize);
203 // Allocate a program memory variable into ROMDATA section.
205 PIC16TargetObjectFile::allocateROMDATA(const GlobalVariable *GV) const {
207 std::string name = PAN::getRomdataSectionName();
208 PIC16Section *S = getPIC16DataSection(name.c_str(), ROMDATA);
210 S->Items.push_back(GV);
214 // Get the section for an automatic variable of a function.
215 // For PIC16 they are globals only with mangled names.
217 PIC16TargetObjectFile::allocateAUTO(const GlobalVariable *GV) const {
219 const std::string name = PAN::getSectionNameForSym(GV->getName());
220 PIC16Section *S = getPIC16AutoSection(name.c_str());
222 S->Items.push_back(GV);
227 // Override default implementation to put the true globals into
228 // multiple data sections if required.
230 PIC16TargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV1,
233 const TargetMachine &TM) const {
234 // We select the section based on the initializer here, so it really
235 // has to be a GlobalVariable.
236 const GlobalVariable *GV = dyn_cast<GlobalVariable>(GV1);
238 return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM);
240 assert(GV->hasInitializer() && "A def without initializer?");
242 // First, if this is an automatic variable for a function, get the section
243 // name for it and return.
244 std::string name = GV->getName();
245 if (PAN::isLocalName(name))
246 return allocateAUTO(GV);
248 // See if this is an uninitialized global.
249 const Constant *C = GV->getInitializer();
250 if (C->isNullValue())
251 return allocateUDATA(GV);
253 // If this is initialized data in RAM. Put it in the correct IDATA section.
254 if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE)
255 return allocateIDATA(GV);
257 // This is initialized data in rom, put it in the readonly section.
258 if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE)
259 return allocateROMDATA(GV);
261 // Else let the default implementation take care of it.
262 return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM);
268 /// getExplicitSectionGlobal - Allow the target to completely override
269 /// section assignment of a global.
270 const MCSection *PIC16TargetObjectFile::
271 getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind,
272 Mangler *Mang, const TargetMachine &TM) const {
273 assert(GV->hasSection());
275 if (const GlobalVariable *GVar = cast<GlobalVariable>(GV)) {
276 std::string SectName = GVar->getSection();
277 // If address for a variable is specified, get the address and create
279 // FIXME: move this attribute checking in PAN.
280 std::string AddrStr = "Address=";
281 if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) {
282 std::string SectAddr = SectName.substr(AddrStr.length());
283 if (SectAddr.compare("NEAR") == 0)
284 return allocateSHARED(GVar, Mang);
286 return allocateAtGivenAddress(GVar, SectAddr);
289 // Create the section specified with section attribute.
290 return allocateInGivenSection(GVar);
293 return getPIC16DataSection(GV->getSection().c_str(), UDATA);
297 PIC16TargetObjectFile::allocateSHARED(const GlobalVariable *GV,
298 Mangler *Mang) const {
299 // Make sure that this is an uninitialized global.
300 assert(GV->hasInitializer() && "This global doesn't need space");
301 if (!GV->getInitializer()->isNullValue()) {
302 // FIXME: Generate a warning in this case that near qualifier will be
304 return SelectSectionForGlobal(GV, SectionKind::getDataRel(), Mang, *TM);
306 std::string Name = PAN::getSharedUDataSectionName();
308 PIC16Section *SharedUDataSect = getPIC16DataSection(Name.c_str(), UDATA_SHR);
309 // Insert the GV into shared section.
310 SharedUDataSect->Items.push_back(GV);
311 return SharedUDataSect;
315 // Interface used by AsmPrinter to get a code section for a function.
317 PIC16TargetObjectFile::SectionForCode(const std::string &FnName,
319 const std::string &sec_name = PAN::getCodeSectionName(FnName);
320 // If it is ISR, its code section starts at a specific address.
322 return getPIC16Section(sec_name, CODE, PAN::getISRAddr());
323 return getPIC16Section(sec_name, CODE);
326 // Interface used by AsmPrinter to get a frame section for a function.
328 PIC16TargetObjectFile::SectionForFrame(const std::string &FnName) const {
329 const std::string &sec_name = PAN::getFrameSectionName(FnName);
330 return getPIC16Section(sec_name, UDATA_OVR);
333 // Allocate a global var in existing or new section of given name.
335 PIC16TargetObjectFile::allocateInGivenSection(const GlobalVariable *GV) const {
336 // Determine the type of section that we need to create.
337 PIC16SectionType SecTy;
339 // See if this is an uninitialized global.
340 const Constant *C = GV->getInitializer();
341 if (C->isNullValue())
343 // If this is initialized data in RAM. Put it in the correct IDATA section.
344 else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE)
346 // This is initialized data in rom, put it in the readonly section.
347 else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE)
350 llvm_unreachable ("Could not determine section type for global");
352 PIC16Section *S = getPIC16UserSection(GV->getSection().c_str(), SecTy);
353 S->Items.push_back(GV);
357 // Allocate a global var in a new absolute sections at given address.
359 PIC16TargetObjectFile::allocateAtGivenAddress(const GlobalVariable *GV,
360 const std::string &Addr) const {
361 // Determine the type of section that we need to create.
362 PIC16SectionType SecTy;
364 // See if this is an uninitialized global.
365 const Constant *C = GV->getInitializer();
366 if (C->isNullValue())
368 // If this is initialized data in RAM. Put it in the correct IDATA section.
369 else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE)
371 // This is initialized data in rom, put it in the readonly section.
372 else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE)
375 llvm_unreachable ("Could not determine section type for global");
377 std::string Prefix = GV->getNameStr() + "." + Addr + ".";
378 std::string SName = PAN::getUserSectionName(Prefix);
379 PIC16Section *S = getPIC16UserSection(SName.c_str(), SecTy, Addr.c_str());
380 S->Items.push_back(GV);