Mercurial > projects > ldc
comparison gen/toobj.cpp @ 86:fd32135dca3e trunk
[svn r90] Major updates to the gen directory. Redesigned the 'elem' struct. Much more... !!!
Lots of bugfixes.
Added support for special foreach on strings.
Added std.array, std.utf, std.ctype and std.uni to phobos.
Changed all the .c files in the gen dir to .cpp (it *is* C++ after all)
author | lindquist |
---|---|
date | Sat, 03 Nov 2007 14:44:58 +0100 |
parents | gen/toobj.c@f869c636a113 |
children | 058d3925950e |
comparison
equal
deleted
inserted
replaced
85:f869c636a113 | 86:fd32135dca3e |
---|---|
1 | |
2 // Copyright (c) 1999-2004 by Digital Mars | |
3 // All Rights Reserved | |
4 // written by Walter Bright | |
5 // www.digitalmars.com | |
6 // License for redistribution is by either the Artistic License | |
7 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
8 // See the included readme.txt for details. | |
9 | |
10 #include <cstddef> | |
11 #include <iostream> | |
12 #include <fstream> | |
13 | |
14 #include "gen/llvm.h" | |
15 #include "llvm/Analysis/Verifier.h" | |
16 #include "llvm/Bitcode/ReaderWriter.h" | |
17 #include "llvm/Target/TargetMachine.h" | |
18 #include "llvm/Target/TargetMachineRegistry.h" | |
19 | |
20 #include "mars.h" | |
21 #include "module.h" | |
22 #include "mtype.h" | |
23 #include "declaration.h" | |
24 #include "statement.h" | |
25 #include "enum.h" | |
26 #include "aggregate.h" | |
27 #include "init.h" | |
28 #include "attrib.h" | |
29 #include "id.h" | |
30 #include "import.h" | |
31 #include "template.h" | |
32 #include "scope.h" | |
33 | |
34 #include "gen/irstate.h" | |
35 #include "gen/elem.h" | |
36 #include "gen/logger.h" | |
37 #include "gen/tollvm.h" | |
38 #include "gen/arrays.h" | |
39 #include "gen/todebug.h" | |
40 #include "gen/runtime.h" | |
41 | |
42 ////////////////////////////////////////////////////////////////////////////////////////// | |
43 | |
44 void | |
45 Module::genobjfile() | |
46 { | |
47 Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n'; | |
48 LOG_SCOPE; | |
49 | |
50 // start by deleting the old object file | |
51 deleteObjFile(); | |
52 | |
53 // create a new ir state | |
54 IRState ir; | |
55 gIR = &ir; | |
56 ir.dmodule = this; | |
57 | |
58 // name the module | |
59 std::string mname(toChars()); | |
60 if (md != 0) | |
61 mname = md->toChars(); | |
62 ir.module = new llvm::Module(mname); | |
63 | |
64 // set target stuff | |
65 std::string target_triple(global.params.tt_arch); | |
66 target_triple.append(global.params.tt_os); | |
67 ir.module->setTargetTriple(target_triple); | |
68 ir.module->setDataLayout(global.params.data_layout); | |
69 | |
70 // heavily inspired by tools/llc/llc.cpp:200-230 | |
71 const llvm::TargetMachineRegistry::Entry* targetEntry; | |
72 std::string targetError; | |
73 targetEntry = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, targetError); | |
74 assert(targetEntry && "Failed to find a static target for module"); | |
75 std::auto_ptr<llvm::TargetMachine> targetPtr(targetEntry->CtorFn(*ir.module, "")); // TODO: replace "" with features | |
76 assert(targetPtr.get() && "Could not allocate target machine!"); | |
77 llvm::TargetMachine &targetMachine = *targetPtr.get(); | |
78 gTargetData = targetMachine.getTargetData(); | |
79 | |
80 // debug info | |
81 if (global.params.symdebug) { | |
82 RegisterDwarfSymbols(ir.module); | |
83 ir.dwarfCompileUnit = DtoDwarfCompileUnit(this); | |
84 } | |
85 | |
86 // process module members | |
87 for (int k=0; k < members->dim; k++) { | |
88 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
89 assert(dsym); | |
90 dsym->toObjFile(); | |
91 } | |
92 | |
93 gTargetData = 0; | |
94 | |
95 // emit the llvm main function if necessary | |
96 if (ir.emitMain) { | |
97 DtoMain(); | |
98 } | |
99 | |
100 // verify the llvm | |
101 if (!global.params.novalidate) { | |
102 std::string verifyErr; | |
103 Logger::println("Verifying module..."); | |
104 if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) | |
105 { | |
106 error("%s", verifyErr.c_str()); | |
107 fatal(); | |
108 } | |
109 else { | |
110 Logger::println("Verification passed!"); | |
111 } | |
112 } | |
113 | |
114 // run passes | |
115 // TODO | |
116 | |
117 // write bytecode | |
118 { | |
119 Logger::println("Writing LLVM bitcode\n"); | |
120 std::ofstream bos(bcfile->name->toChars(), std::ios::binary); | |
121 llvm::WriteBitcodeToFile(ir.module, bos); | |
122 } | |
123 | |
124 // disassemble ? | |
125 if (global.params.disassemble) { | |
126 Logger::println("Writing LLVM asm to: %s\n", llfile->name->toChars()); | |
127 std::ofstream aos(llfile->name->toChars()); | |
128 ir.module->print(aos); | |
129 } | |
130 | |
131 delete ir.module; | |
132 gIR = NULL; | |
133 } | |
134 | |
135 /* ================================================================== */ | |
136 | |
137 // Put out instance of ModuleInfo for this Module | |
138 | |
139 void Module::genmoduleinfo() | |
140 { | |
141 } | |
142 | |
143 /* ================================================================== */ | |
144 | |
145 void Dsymbol::toObjFile() | |
146 { | |
147 Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars()); | |
148 } | |
149 | |
150 /* ================================================================== */ | |
151 | |
152 void Declaration::toObjFile() | |
153 { | |
154 Logger::println("Ignoring Declaration::toObjFile for %s", toChars()); | |
155 } | |
156 | |
157 /* ================================================================== */ | |
158 | |
159 void InterfaceDeclaration::toObjFile() | |
160 { | |
161 Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars()); | |
162 } | |
163 | |
164 /* ================================================================== */ | |
165 | |
166 void StructDeclaration::toObjFile() | |
167 { | |
168 TypeStruct* ts = (TypeStruct*)DtoDType(type); | |
169 if (llvmType != 0) | |
170 return; | |
171 | |
172 static int sdi = 0; | |
173 Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars()); | |
174 LOG_SCOPE; | |
175 | |
176 gIR->structs.push_back(IRStruct(ts)); | |
177 | |
178 for (int k=0; k < members->dim; k++) { | |
179 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
180 dsym->toObjFile(); | |
181 } | |
182 | |
183 Logger::println("doing struct fields"); | |
184 | |
185 llvm::StructType* structtype = 0; | |
186 std::vector<llvm::Constant*> fieldinits; | |
187 | |
188 if (gIR->topstruct().offsets.empty()) | |
189 { | |
190 std::vector<const llvm::Type*> fieldtypes; | |
191 Logger::println("has no fields"); | |
192 fieldtypes.push_back(llvm::Type::Int8Ty); | |
193 fieldinits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
194 structtype = llvm::StructType::get(fieldtypes); | |
195 } | |
196 else | |
197 { | |
198 Logger::println("has fields"); | |
199 std::vector<const llvm::Type*> fieldtypes; | |
200 unsigned prevsize = (unsigned)-1; | |
201 unsigned lastoffset = (unsigned)-1; | |
202 const llvm::Type* fieldtype = NULL; | |
203 llvm::Constant* fieldinit = NULL; | |
204 size_t fieldpad = 0; | |
205 int idx = 0; | |
206 for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) { | |
207 // first iteration | |
208 if (lastoffset == (unsigned)-1) { | |
209 lastoffset = i->first; | |
210 assert(lastoffset == 0); | |
211 fieldtype = DtoType(i->second.var->type); | |
212 fieldinit = i->second.init; | |
213 prevsize = gTargetData->getTypeSize(fieldtype); | |
214 i->second.var->llvmFieldIndex = idx; | |
215 } | |
216 // colliding offset? | |
217 else if (lastoffset == i->first) { | |
218 const llvm::Type* t = DtoType(i->second.var->type); | |
219 size_t s = gTargetData->getTypeSize(t); | |
220 if (s > prevsize) { | |
221 fieldpad += s - prevsize; | |
222 prevsize = s; | |
223 } | |
224 llvmHasUnions = true; | |
225 i->second.var->llvmFieldIndex = idx; | |
226 } | |
227 // intersecting offset? | |
228 else if (i->first < (lastoffset + prevsize)) { | |
229 const llvm::Type* t = DtoType(i->second.var->type); | |
230 size_t s = gTargetData->getTypeSize(t); | |
231 assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size | |
232 llvmHasUnions = true; | |
233 i->second.var->llvmFieldIndex = idx; | |
234 i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s; | |
235 } | |
236 // fresh offset | |
237 else { | |
238 // commit the field | |
239 fieldtypes.push_back(fieldtype); | |
240 fieldinits.push_back(fieldinit); | |
241 if (fieldpad) { | |
242 // match up with below | |
243 std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
244 llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals); | |
245 fieldtypes.push_back(c->getType()); | |
246 fieldinits.push_back(c); | |
247 idx++; | |
248 } | |
249 | |
250 idx++; | |
251 | |
252 // start new | |
253 lastoffset = i->first; | |
254 fieldtype = DtoType(i->second.var->type); | |
255 fieldinit = i->second.init; | |
256 prevsize = gTargetData->getTypeSize(fieldtype); | |
257 i->second.var->llvmFieldIndex = idx; | |
258 fieldpad = 0; | |
259 } | |
260 } | |
261 fieldtypes.push_back(fieldtype); | |
262 fieldinits.push_back(fieldinit); | |
263 if (fieldpad) { | |
264 // match up with above | |
265 std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
266 llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals); | |
267 fieldtypes.push_back(c->getType()); | |
268 fieldinits.push_back(c); | |
269 } | |
270 | |
271 Logger::println("creating struct type"); | |
272 structtype = llvm::StructType::get(fieldtypes); | |
273 } | |
274 | |
275 // refine abstract types for stuff like: struct S{S* next;} | |
276 if (gIR->topstruct().recty != 0) | |
277 { | |
278 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
279 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
280 structtype = llvm::cast<llvm::StructType>(pa.get()); | |
281 } | |
282 | |
283 ts->llvmType = structtype; | |
284 llvmType = structtype; | |
285 | |
286 if (parent->isModule()) { | |
287 gIR->module->addTypeName(mangle(),ts->llvmType); | |
288 } | |
289 | |
290 // generate static data | |
291 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
292 llvm::Constant* _init = 0; | |
293 | |
294 // always generate the constant initalizer | |
295 if (!zeroInit) { | |
296 Logger::println("Not zero initialized"); | |
297 //assert(tk == gIR->gIR->topstruct()().size()); | |
298 #ifndef LLVMD_NO_LOGGER | |
299 Logger::cout() << "struct type: " << *structtype << '\n'; | |
300 for (size_t k=0; k<fieldinits.size(); ++k) { | |
301 Logger::cout() << "Type:" << '\n'; | |
302 Logger::cout() << *fieldinits[k]->getType() << '\n'; | |
303 Logger::cout() << "Value:" << '\n'; | |
304 Logger::cout() << *fieldinits[k] << '\n'; | |
305 } | |
306 Logger::cout() << "Initializer printed" << '\n'; | |
307 #endif | |
308 llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits); | |
309 } | |
310 else { | |
311 Logger::println("Zero initialized"); | |
312 llvmInitZ = llvm::ConstantAggregateZero::get(structtype); | |
313 } | |
314 | |
315 // only provide the constant initializer for the defining module | |
316 if (getModule() == gIR->dmodule) | |
317 { | |
318 _init = llvmInitZ; | |
319 } | |
320 | |
321 std::string initname("_D"); | |
322 initname.append(mangle()); | |
323 initname.append("6__initZ"); | |
324 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module); | |
325 ts->llvmInit = initvar; | |
326 | |
327 // generate member function definitions | |
328 gIR->topstruct().queueFuncs = false; | |
329 IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs; | |
330 size_t n = mfs.size(); | |
331 for (size_t i=0; i<n; ++i) { | |
332 mfs[i]->toObjFile(); | |
333 } | |
334 | |
335 llvmDModule = gIR->dmodule; | |
336 | |
337 gIR->structs.pop_back(); | |
338 | |
339 // generate typeinfo | |
340 if (getModule() == gIR->dmodule && llvmInternal != LLVMnotypeinfo) | |
341 type->getTypeInfo(NULL); | |
342 } | |
343 | |
344 /* ================================================================== */ | |
345 | |
346 static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) | |
347 { | |
348 // start at the bottom of the inheritance chain | |
349 if (cd->baseClass != 0) { | |
350 unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx); | |
351 if (o != (unsigned)-1) | |
352 return o; | |
353 } | |
354 | |
355 // check this class | |
356 unsigned i; | |
357 for (i=0; i<cd->fields.dim; ++i) { | |
358 VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; | |
359 if (os == vd->offset) | |
360 return i+idx; | |
361 } | |
362 idx += i; | |
363 | |
364 return (unsigned)-1; | |
365 } | |
366 | |
367 void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result) | |
368 { | |
369 unsigned idx = 0; | |
370 unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); | |
371 assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); | |
372 result.push_back(r+1); // vtable is 0 | |
373 } | |
374 | |
375 /* ================================================================== */ | |
376 | |
377 static void LLVM_AddBaseClassData(BaseClasses* bcs) | |
378 { | |
379 // add base class data members first | |
380 for (int j=0; j<bcs->dim; j++) | |
381 { | |
382 BaseClass* bc = (BaseClass*)(bcs->data[j]); | |
383 assert(bc); | |
384 Logger::println("Adding base class members of %s", bc->base->toChars()); | |
385 LOG_SCOPE; | |
386 | |
387 LLVM_AddBaseClassData(&bc->base->baseclasses); | |
388 for (int k=0; k < bc->base->members->dim; k++) { | |
389 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); | |
390 if (dsym->isVarDeclaration()) | |
391 { | |
392 dsym->toObjFile(); | |
393 } | |
394 } | |
395 } | |
396 } | |
397 | |
398 void ClassDeclaration::toObjFile() | |
399 { | |
400 TypeClass* ts = (TypeClass*)DtoDType(type); | |
401 if (ts->llvmType != 0 || llvmInProgress) | |
402 return; | |
403 | |
404 llvmInProgress = true; | |
405 | |
406 static int fdi = 0; | |
407 Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars()); | |
408 LOG_SCOPE; | |
409 | |
410 gIR->structs.push_back(IRStruct(ts)); | |
411 gIR->classes.push_back(this); | |
412 | |
413 // add vtable | |
414 llvm::PATypeHolder pa = llvm::OpaqueType::get(); | |
415 const llvm::Type* vtabty = llvm::PointerType::get(pa); | |
416 | |
417 std::vector<const llvm::Type*> fieldtypes; | |
418 fieldtypes.push_back(vtabty); | |
419 | |
420 std::vector<llvm::Constant*> fieldinits; | |
421 fieldinits.push_back(0); | |
422 | |
423 // base classes first | |
424 LLVM_AddBaseClassData(&baseclasses); | |
425 | |
426 // then add own members | |
427 for (int k=0; k < members->dim; k++) { | |
428 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
429 dsym->toObjFile(); | |
430 } | |
431 | |
432 // fill out fieldtypes/inits | |
433 for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) { | |
434 fieldtypes.push_back(DtoType(i->second.var->type)); | |
435 fieldinits.push_back(i->second.init); | |
436 } | |
437 | |
438 llvm::StructType* structtype = llvm::StructType::get(fieldtypes); | |
439 // refine abstract types for stuff like: class C {C next;} | |
440 if (gIR->topstruct().recty != 0) | |
441 { | |
442 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
443 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
444 structtype = llvm::cast<llvm::StructType>(pa.get()); | |
445 } | |
446 | |
447 ts->llvmType = structtype; | |
448 llvmType = structtype; | |
449 | |
450 bool needs_definition = false; | |
451 if (parent->isModule()) { | |
452 gIR->module->addTypeName(mangle(),ts->llvmType); | |
453 needs_definition = (getModule() == gIR->dmodule); | |
454 } | |
455 else { | |
456 assert(0 && "class parent is not a module"); | |
457 } | |
458 | |
459 // generate vtable | |
460 llvm::GlobalVariable* svtblVar = 0; | |
461 std::vector<llvm::Constant*> sinits; | |
462 std::vector<const llvm::Type*> sinits_ty; | |
463 sinits.reserve(vtbl.dim); | |
464 sinits_ty.reserve(vtbl.dim); | |
465 | |
466 for (int k=0; k < vtbl.dim; k++) | |
467 { | |
468 Dsymbol* dsym = (Dsymbol*)vtbl.data[k]; | |
469 assert(dsym); | |
470 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
471 | |
472 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
473 fd->toObjFile(); | |
474 assert(fd->llvmValue); | |
475 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
476 sinits.push_back(c); | |
477 sinits_ty.push_back(c->getType()); | |
478 } | |
479 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
480 const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
481 llvm::Constant* c = llvm::Constant::getNullValue(cty); | |
482 sinits.push_back(c); | |
483 sinits_ty.push_back(cty); | |
484 } | |
485 else | |
486 assert(0); | |
487 } | |
488 | |
489 const llvm::StructType* svtbl_ty = 0; | |
490 if (!sinits.empty()) | |
491 { | |
492 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
493 | |
494 std::string varname("_D"); | |
495 varname.append(mangle()); | |
496 varname.append("6__vtblZ"); | |
497 | |
498 std::string styname(mangle()); | |
499 styname.append("__vtblTy"); | |
500 | |
501 svtbl_ty = llvm::StructType::get(sinits_ty); | |
502 gIR->module->addTypeName(styname, svtbl_ty); | |
503 svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); | |
504 | |
505 llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits)); | |
506 if (needs_definition) | |
507 svtblVar->setInitializer(llvmConstVtbl); | |
508 llvmVtbl = svtblVar; | |
509 } | |
510 | |
511 //////////////////////////////////////////////////////////////////////////////// | |
512 | |
513 // refine for final vtable type | |
514 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty); | |
515 svtbl_ty = llvm::cast<llvm::StructType>(pa.get()); | |
516 structtype = llvm::cast<llvm::StructType>(gIR->topstruct().recty.get()); | |
517 ts->llvmType = structtype; | |
518 llvmType = structtype; | |
519 | |
520 // generate initializer | |
521 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
522 llvm::Constant* _init = 0; | |
523 | |
524 // first field is always the vtable | |
525 assert(svtblVar != 0); | |
526 fieldinits[0] = svtblVar; | |
527 | |
528 llvmInitZ = _init = llvm::ConstantStruct::get(structtype,fieldinits); | |
529 assert(_init); | |
530 | |
531 std::string initname("_D"); | |
532 initname.append(mangle()); | |
533 initname.append("6__initZ"); | |
534 //Logger::cout() << *_init << '\n'; | |
535 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, NULL, initname, gIR->module); | |
536 ts->llvmInit = initvar; | |
537 | |
538 if (needs_definition) { | |
539 initvar->setInitializer(_init); | |
540 // generate member functions | |
541 gIR->topstruct().queueFuncs = false; | |
542 IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs; | |
543 size_t n = mfs.size(); | |
544 for (size_t i=0; i<n; ++i) { | |
545 mfs[i]->toObjFile(); | |
546 } | |
547 } | |
548 | |
549 gIR->classes.pop_back(); | |
550 gIR->structs.pop_back(); | |
551 | |
552 llvmInProgress = false; | |
553 } | |
554 | |
555 /****************************************** | |
556 * Get offset of base class's vtbl[] initializer from start of csym. | |
557 * Returns ~0 if not this csym. | |
558 */ | |
559 | |
560 unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc) | |
561 { | |
562 return ~0; | |
563 } | |
564 | |
565 /* ================================================================== */ | |
566 | |
567 void VarDeclaration::toObjFile() | |
568 { | |
569 Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); | |
570 LOG_SCOPE; | |
571 llvm::Module* M = gIR->module; | |
572 | |
573 if (aliassym) | |
574 { | |
575 toAlias()->toObjFile(); | |
576 return; | |
577 } | |
578 | |
579 // global variable or magic | |
580 if (isDataseg()) | |
581 { | |
582 if (llvmTouched) return; | |
583 else llvmTouched = true; | |
584 | |
585 bool _isconst = false; | |
586 if (isConst() && (init && !init->isExpInitializer())) | |
587 _isconst = true; | |
588 | |
589 llvm::GlobalValue::LinkageTypes _linkage; | |
590 bool istempl = false; | |
591 if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) { | |
592 _linkage = llvm::GlobalValue::WeakLinkage; | |
593 istempl = true; | |
594 } | |
595 else if (parent && parent->isFuncDeclaration()) | |
596 _linkage = llvm::GlobalValue::InternalLinkage; | |
597 else | |
598 _linkage = DtoLinkage(protection, storage_class); | |
599 | |
600 Type* t = DtoDType(type); | |
601 | |
602 const llvm::Type* _type = DtoType(t); | |
603 assert(_type); | |
604 | |
605 llvm::Constant* _init = 0; | |
606 bool _signed = !type->isunsigned(); | |
607 | |
608 Logger::println("Creating global variable"); | |
609 std::string _name(mangle()); | |
610 | |
611 llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,0,_name,M); | |
612 llvmValue = gvar; | |
613 | |
614 if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl)) | |
615 { | |
616 if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) { | |
617 _init = DtoConstInitializer(t, NULL); | |
618 // create a flag to make sure initialization only happens once | |
619 llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage; | |
620 std::string gflagname(_name); | |
621 gflagname.append("__initflag"); | |
622 llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,M); | |
623 | |
624 // check flag and do init if not already done | |
625 llvm::BasicBlock* oldend = gIR->scopeend(); | |
626 llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend); | |
627 llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend); | |
628 llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false)); | |
629 gIR->ir->CreateCondBr(cond, initbb, endinitbb); | |
630 gIR->scope() = IRScope(initbb,endinitbb); | |
631 elem* ie = DtoInitializer(init); | |
632 if (!ie->inPlace()) { | |
633 DValue* dst = new DVarValue(t, gvar, true); | |
634 DtoAssign(dst, ie); | |
635 delete dst; | |
636 } | |
637 gIR->ir->CreateStore(DtoConstBool(true), gflag); | |
638 gIR->ir->CreateBr(endinitbb); | |
639 gIR->scope() = IRScope(endinitbb,oldend); | |
640 } | |
641 else { | |
642 _init = DtoConstInitializer(t, init); | |
643 } | |
644 | |
645 //Logger::cout() << "initializer: " << *_init << '\n'; | |
646 if (_type != _init->getType()) { | |
647 Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n"; | |
648 // zero initalizer | |
649 if (_init->isNullValue()) | |
650 _init = llvm::Constant::getNullValue(_type); | |
651 // pointer to global constant (struct.init) | |
652 else if (llvm::isa<llvm::GlobalVariable>(_init)) | |
653 { | |
654 assert(_init->getType()->getContainedType(0) == _type); | |
655 llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init); | |
656 assert(t->ty == Tstruct); | |
657 TypeStruct* ts = (TypeStruct*)t; | |
658 assert(ts->sym->llvmInitZ); | |
659 _init = ts->sym->llvmInitZ; | |
660 } | |
661 // array single value init | |
662 else if (llvm::isa<llvm::ArrayType>(_type)) | |
663 { | |
664 _init = DtoConstStaticArray(_type, _init); | |
665 } | |
666 else { | |
667 Logger::cout() << "Unexpected initializer type: " << *_type << '\n'; | |
668 //assert(0); | |
669 } | |
670 } | |
671 | |
672 Logger::cout() << "final init = " << *_init << '\n'; | |
673 gvar->setInitializer(_init); | |
674 } | |
675 | |
676 llvmDModule = gIR->dmodule; | |
677 | |
678 //if (storage_class & STCprivate) | |
679 // gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility); | |
680 } | |
681 | |
682 // inside aggregate declaration. declare a field. | |
683 else | |
684 { | |
685 Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset); | |
686 | |
687 Type* t = DtoDType(type); | |
688 const llvm::Type* _type = DtoType(t); | |
689 | |
690 llvm::Constant*_init = DtoConstInitializer(t, init); | |
691 assert(_init); | |
692 Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n'; | |
693 if (_type != _init->getType()) | |
694 { | |
695 if (t->ty == Tsarray) | |
696 { | |
697 const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(_type); | |
698 uint64_t n = arrty->getNumElements(); | |
699 std::vector<llvm::Constant*> vals(n,_init); | |
700 _init = llvm::ConstantArray::get(arrty, vals); | |
701 } | |
702 else if (t->ty == Tarray) | |
703 { | |
704 assert(llvm::isa<llvm::StructType>(_type)); | |
705 _init = llvm::ConstantAggregateZero::get(_type); | |
706 } | |
707 else if (t->ty == Tstruct) | |
708 { | |
709 const llvm::StructType* structty = llvm::cast<llvm::StructType>(_type); | |
710 TypeStruct* ts = (TypeStruct*)t; | |
711 assert(ts); | |
712 assert(ts->sym); | |
713 assert(ts->sym->llvmInitZ); | |
714 _init = ts->sym->llvmInitZ; | |
715 } | |
716 else if (t->ty == Tclass) | |
717 { | |
718 _init = llvm::Constant::getNullValue(_type); | |
719 } | |
720 else { | |
721 Logger::println("failed for type %s", type->toChars()); | |
722 assert(0); | |
723 } | |
724 } | |
725 | |
726 // add the field in the IRStruct | |
727 gIR->topstruct().offsets.insert(std::make_pair(offset, IRStruct::Offset(this,_init))); | |
728 } | |
729 | |
730 Logger::println("VarDeclaration::toObjFile is done"); | |
731 } | |
732 | |
733 /* ================================================================== */ | |
734 | |
735 void TypedefDeclaration::toObjFile() | |
736 { | |
737 static int tdi = 0; | |
738 Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); | |
739 LOG_SCOPE; | |
740 | |
741 // generate typeinfo | |
742 type->getTypeInfo(NULL); | |
743 } | |
744 | |
745 /* ================================================================== */ | |
746 | |
747 void EnumDeclaration::toObjFile() | |
748 { | |
749 Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars()); | |
750 } | |
751 | |
752 /* ================================================================== */ | |
753 | |
754 void FuncDeclaration::toObjFile() | |
755 { | |
756 if (llvmDModule) { | |
757 assert(llvmValue != 0); | |
758 return; | |
759 } | |
760 | |
761 if (llvmRunTimeHack) { | |
762 Logger::println("runtime hack func chars: %s", toChars()); | |
763 if (!llvmValue) | |
764 llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars()); | |
765 return; | |
766 } | |
767 | |
768 if (isUnitTestDeclaration()) { | |
769 Logger::println("*** ATTENTION: ignoring unittest declaration: %s", toChars()); | |
770 return; | |
771 } | |
772 | |
773 Type* t = DtoDType(type); | |
774 TypeFunction* f = (TypeFunction*)t; | |
775 | |
776 bool declareOnly = false; | |
777 if (parent) | |
778 { | |
779 if (TemplateInstance* tinst = parent->isTemplateInstance()) { | |
780 TemplateDeclaration* tempdecl = tinst->tempdecl; | |
781 if (tempdecl->llvmInternal == LLVMva_start) | |
782 { | |
783 Logger::println("magic va_start found"); | |
784 llvmInternal = LLVMva_start; | |
785 declareOnly = true; | |
786 } | |
787 else if (tempdecl->llvmInternal == LLVMva_arg) | |
788 { | |
789 Logger::println("magic va_arg found"); | |
790 llvmInternal = LLVMva_arg; | |
791 return; | |
792 } | |
793 } | |
794 } | |
795 | |
796 llvm::Function* func = DtoDeclareFunction(this); | |
797 | |
798 if (declareOnly) | |
799 return; | |
800 | |
801 if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) { | |
802 if (!llvmQueued) { | |
803 Logger::println("queueing %s", toChars()); | |
804 gIR->topstruct().funcs.push_back(this); | |
805 llvmQueued = true; | |
806 } | |
807 return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete | |
808 } | |
809 | |
810 // debug info | |
811 if (global.params.symdebug) { | |
812 llvmDwarfSubProgram = DtoDwarfSubProgram(this); | |
813 } | |
814 | |
815 assert(f->llvmType); | |
816 const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0)); | |
817 | |
818 // template instances should have weak linkage | |
819 if (parent && DtoIsTemplateInstance(parent)) { | |
820 func->setLinkage(llvm::GlobalValue::WeakLinkage); | |
821 } | |
822 | |
823 // only members of the current module maybe be defined | |
824 if (getModule() == gIR->dmodule || DtoIsTemplateInstance(parent)) | |
825 { | |
826 llvmDModule = gIR->dmodule; | |
827 | |
828 // handle static constructor / destructor | |
829 if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) { | |
830 const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1); | |
831 //Logger::cout() << "static ctor type: " << *sctor_type << '\n'; | |
832 | |
833 llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue); | |
834 //Logger::cout() << "static ctor func: " << *sctor_func << '\n'; | |
835 | |
836 llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1); | |
837 | |
838 //Logger::cout() << "static ctor init: " << *sctor_init << '\n'; | |
839 | |
840 // output the llvm.global_ctors array | |
841 const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array"; | |
842 llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module); | |
843 } | |
844 | |
845 // function definition | |
846 if (fbody != 0) | |
847 { | |
848 gIR->functions.push_back(IRFunction(this)); | |
849 gIR->func().func = func; | |
850 | |
851 // first make absolutely sure the type is up to date | |
852 f->llvmType = llvmValue->getType()->getContainedType(0); | |
853 | |
854 //Logger::cout() << "func type: " << *f->llvmType << '\n'; | |
855 | |
856 // this handling | |
857 if (f->llvmUsesThis) { | |
858 Logger::println("uses this"); | |
859 if (f->llvmRetInPtr) | |
860 llvmThisVar = ++func->arg_begin(); | |
861 else | |
862 llvmThisVar = func->arg_begin(); | |
863 assert(llvmThisVar != 0); | |
864 } | |
865 | |
866 if (isMain()) | |
867 gIR->emitMain = true; | |
868 | |
869 llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func); | |
870 llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func); | |
871 | |
872 //assert(gIR->scopes.empty()); | |
873 gIR->scopes.push_back(IRScope(beginbb, endbb)); | |
874 | |
875 // create alloca point | |
876 f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); | |
877 gIR->func().allocapoint = f->llvmAllocaPoint; | |
878 | |
879 // give arguments storage | |
880 size_t n = Argument::dim(f->parameters); | |
881 for (int i=0; i < n; ++i) { | |
882 Argument* arg = Argument::getNth(f->parameters, i); | |
883 if (arg && arg->vardecl) { | |
884 VarDeclaration* vd = arg->vardecl; | |
885 if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)) | |
886 continue; | |
887 llvm::Value* a = vd->llvmValue; | |
888 assert(a); | |
889 std::string s(a->getName()); | |
890 Logger::println("giving argument '%s' storage", s.c_str()); | |
891 s.append("_storage"); | |
892 llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint); | |
893 gIR->ir->CreateStore(a,v); | |
894 vd->llvmValue = v; | |
895 } | |
896 else { | |
897 Logger::println("*** ATTENTION: some unknown argument: %s", arg ? arg->toChars() : 0); | |
898 } | |
899 } | |
900 | |
901 // debug info | |
902 if (global.params.symdebug) DtoDwarfFuncStart(this); | |
903 | |
904 llvm::Value* parentNested = NULL; | |
905 if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) { | |
906 parentNested = fd->llvmNested; | |
907 } | |
908 | |
909 // construct nested variables struct | |
910 if (!llvmNestedVars.empty() || parentNested) { | |
911 std::vector<const llvm::Type*> nestTypes; | |
912 int j = 0; | |
913 if (parentNested) { | |
914 nestTypes.push_back(parentNested->getType()); | |
915 j++; | |
916 } | |
917 for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) { | |
918 VarDeclaration* vd = *i; | |
919 vd->llvmNestedIndex = j++; | |
920 if (vd->isParameter()) { | |
921 assert(vd->llvmValue); | |
922 nestTypes.push_back(vd->llvmValue->getType()); | |
923 } | |
924 else { | |
925 nestTypes.push_back(DtoType(vd->type)); | |
926 } | |
927 } | |
928 const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); | |
929 Logger::cout() << "nested var struct has type:" << '\n' << *nestSType; | |
930 llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint); | |
931 if (parentNested) { | |
932 assert(llvmThisVar); | |
933 llvm::Value* ptr = gIR->ir->CreateBitCast(llvmThisVar, parentNested->getType(), "tmp"); | |
934 gIR->ir->CreateStore(ptr, DtoGEPi(llvmNested, 0,0, "tmp")); | |
935 } | |
936 for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) { | |
937 VarDeclaration* vd = *i; | |
938 if (vd->isParameter()) { | |
939 gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(llvmNested, 0, vd->llvmNestedIndex, "tmp")); | |
940 vd->llvmValue = llvmNested; | |
941 } | |
942 } | |
943 } | |
944 | |
945 // copy _argptr to a memory location | |
946 if (f->linkage == LINKd && f->varargs == 1) | |
947 { | |
948 llvm::Value* argptrmem = new llvm::AllocaInst(llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint()); | |
949 new llvm::StoreInst(llvmArgPtr, argptrmem, gIR->scopebb()); | |
950 llvmArgPtr = argptrmem; | |
951 } | |
952 | |
953 // output function body | |
954 fbody->toIR(gIR); | |
955 | |
956 // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement | |
957 // in automatically, so we do it here. | |
958 if (!isMain()) { | |
959 if (!gIR->scopereturned()) { | |
960 // pass the previous block into this block | |
961 if (global.params.symdebug) DtoDwarfFuncEnd(this); | |
962 if (func->getReturnType() == llvm::Type::VoidTy) { | |
963 new llvm::ReturnInst(gIR->scopebb()); | |
964 } | |
965 else { | |
966 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); | |
967 } | |
968 } | |
969 } | |
970 | |
971 // erase alloca point | |
972 f->llvmAllocaPoint->eraseFromParent(); | |
973 f->llvmAllocaPoint = 0; | |
974 gIR->func().allocapoint = 0; | |
975 | |
976 gIR->scopes.pop_back(); | |
977 | |
978 // get rid of the endentry block, it's never used | |
979 assert(!func->getBasicBlockList().empty()); | |
980 func->getBasicBlockList().pop_back(); | |
981 | |
982 // if the last block is empty now, it must be unreachable or it's a bug somewhere else | |
983 // would be nice to figure out how to assert that this is correct | |
984 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); | |
985 if (lastbb->empty()) { | |
986 if (lastbb->getNumUses() == 0) | |
987 lastbb->eraseFromParent(); | |
988 else { | |
989 new llvm::UnreachableInst(lastbb); | |
990 /*if (func->getReturnType() == llvm::Type::VoidTy) { | |
991 new llvm::ReturnInst(lastbb); | |
992 } | |
993 else { | |
994 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb); | |
995 }*/ | |
996 } | |
997 } | |
998 | |
999 gIR->functions.pop_back(); | |
1000 } | |
1001 } | |
1002 } |