Mercurial > projects > ldc
annotate gen/toobj.c @ 7:7a155ba88c53 trunk
[svn r11] added another struct sample
author | lindquist |
---|---|
date | Wed, 26 Sep 2007 19:17:54 +0200 |
parents | 35d93ce68cf4 |
children | 5e69b77a5c51 |
rev | line source |
---|---|
1 | 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 "llvm/Type.h" | |
15 #include "llvm/Constants.h" | |
16 #include "llvm/DerivedTypes.h" | |
17 #include "llvm/Instructions.h" | |
18 #include "llvm/Analysis/Verifier.h" | |
19 #include "llvm/Bitcode/ReaderWriter.h" | |
20 | |
21 #include "llvm/Target/TargetData.h" | |
22 #include "llvm/Target/TargetMachine.h" | |
23 #include "llvm/Target/TargetMachineRegistry.h" | |
24 | |
25 #include "mars.h" | |
26 #include "module.h" | |
27 #include "mtype.h" | |
28 #include "declaration.h" | |
29 #include "statement.h" | |
30 #include "enum.h" | |
31 #include "aggregate.h" | |
32 #include "init.h" | |
33 #include "attrib.h" | |
34 #include "id.h" | |
35 #include "import.h" | |
36 #include "template.h" | |
37 | |
4
e116aa1488e6
[svn r8] changed backend includes to always use the gen/<foo>.h prefix
lindquist
parents:
1
diff
changeset
|
38 #include "gen/irstate.h" |
e116aa1488e6
[svn r8] changed backend includes to always use the gen/<foo>.h prefix
lindquist
parents:
1
diff
changeset
|
39 #include "gen/elem.h" |
e116aa1488e6
[svn r8] changed backend includes to always use the gen/<foo>.h prefix
lindquist
parents:
1
diff
changeset
|
40 #include "gen/logger.h" |
e116aa1488e6
[svn r8] changed backend includes to always use the gen/<foo>.h prefix
lindquist
parents:
1
diff
changeset
|
41 #include "gen/tollvm.h" |
1 | 42 |
43 ////////////////////////////////////////////////////////////////////////////////////////// | |
44 | |
45 void | |
46 Module::genobjfile() | |
47 { | |
48 Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n'; | |
49 LOG_SCOPE; | |
50 | |
6 | 51 // start by deleting the old object file |
1 | 52 deleteObjFile(); |
53 | |
6 | 54 // creaet a new ir state |
1 | 55 IRState ir; |
56 gIR = &ir; | |
57 ir.dmodule = this; | |
58 | |
6 | 59 // name the module |
1 | 60 std::string mname(toChars()); |
61 if (md != 0) | |
62 mname = md->toChars(); | |
63 ir.module = new llvm::Module(mname); | |
64 | |
6 | 65 // set target stuff |
1 | 66 std::string target_triple(global.params.tt_arch); |
67 target_triple.append(global.params.tt_os); | |
68 ir.module->setTargetTriple(target_triple); | |
69 ir.module->setDataLayout(global.params.data_layout); | |
70 | |
71 gTargetData = new llvm::TargetData(ir.module); | |
72 | |
6 | 73 // process module members |
1 | 74 for (int k=0; k < members->dim; k++) { |
75 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
76 assert(dsym); | |
77 dsym->toObjFile(); | |
78 } | |
79 | |
80 delete gTargetData; | |
81 gTargetData = 0; | |
82 | |
6 | 83 // verify the llvm |
1 | 84 std::string verifyErr; |
85 if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) | |
86 { | |
87 error("%s", verifyErr.c_str()); | |
88 fatal(); | |
89 } | |
90 | |
6 | 91 // emit the llvm main function if necessary |
1 | 92 if (ir.emitMain) { |
93 LLVM_DtoMain(); | |
94 } | |
95 | |
96 // run passes | |
97 // TODO | |
98 | |
99 /*if (global.params.llvmLL) { | |
100 //assert(0); | |
101 std::ofstream os(llfile->name->toChars()); | |
102 //llvm::WriteAssemblyToFile(ir.module, os); | |
103 ir.module->print(os); | |
104 }*/ | |
105 | |
6 | 106 // write bytecode |
1 | 107 //if (global.params.llvmBC) { |
108 Logger::println("Writing LLVM bitcode\n"); | |
109 std::ofstream os(bcfile->name->toChars(), std::ios::binary); | |
110 llvm::WriteBitcodeToFile(ir.module, os); | |
111 //} | |
112 | |
113 delete ir.module; | |
114 gIR = NULL; | |
115 } | |
116 | |
117 /* ================================================================== */ | |
118 | |
119 // Put out instance of ModuleInfo for this Module | |
120 | |
121 void Module::genmoduleinfo() | |
122 { | |
123 } | |
124 | |
125 /* ================================================================== */ | |
126 | |
127 void Dsymbol::toObjFile() | |
128 { | |
129 warning("Ignoring Dsymbol::toObjFile for %s", toChars()); | |
130 } | |
131 | |
132 /* ================================================================== */ | |
133 | |
134 void Declaration::toObjFile() | |
135 { | |
136 warning("Ignoring Declaration::toObjFile for %s", toChars()); | |
137 } | |
138 | |
139 /* ================================================================== */ | |
140 | |
6 | 141 /// Returns the LLVM style index from a DMD style offset |
1 | 142 unsigned AggregateDeclaration::offsetToIndex(unsigned os) |
143 { | |
144 for (unsigned i=0; i<fields.dim; ++i) { | |
145 VarDeclaration* vd = (VarDeclaration*)fields.data[i]; | |
146 if (os == vd->offset) | |
147 return i; | |
148 } | |
149 assert(0 && "Offset not found in any aggregate field"); | |
150 return 0; | |
151 } | |
152 | |
153 /* ================================================================== */ | |
154 | |
155 static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) | |
156 { | |
157 // start at the bottom of the inheritance chain | |
158 if (cd->baseClass != 0) { | |
159 unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx); | |
160 if (o != (unsigned)-1) | |
161 return o; | |
162 } | |
163 | |
164 // check this class | |
165 unsigned i; | |
166 for (i=0; i<cd->fields.dim; ++i) { | |
167 VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; | |
168 if (os == vd->offset) | |
169 return i+idx; | |
170 } | |
171 idx += i; | |
172 | |
173 return (unsigned)-1; | |
174 } | |
175 | |
6 | 176 /// Returns the LLVM style index from a DMD style offset |
177 /// Handles class inheritance | |
1 | 178 unsigned ClassDeclaration::offsetToIndex(unsigned os) |
179 { | |
180 unsigned idx = 0; | |
181 unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); | |
182 assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); | |
183 return r+1; // vtable is 0 | |
184 } | |
185 | |
186 /* ================================================================== */ | |
187 | |
188 void InterfaceDeclaration::toObjFile() | |
189 { | |
190 warning("Ignoring InterfaceDeclaration::toObjFile for %s", toChars()); | |
191 } | |
192 | |
193 /* ================================================================== */ | |
194 | |
195 void StructDeclaration::toObjFile() | |
196 { | |
197 TypeStruct* ts = (TypeStruct*)type; | |
198 if (llvmType != 0) | |
199 return; | |
200 | |
201 static int sdi = 0; | |
202 Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars()); | |
203 LOG_SCOPE; | |
204 | |
205 gIR->structs.push_back(IRStruct(ts)); | |
206 | |
207 std::vector<FuncDeclaration*> mfs; | |
208 | |
209 for (int k=0; k < members->dim; k++) { | |
210 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
211 | |
212 // need late generation of member functions | |
213 // they need the llvm::StructType to exist to take the 'this' parameter | |
214 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
215 mfs.push_back(fd); | |
216 } | |
217 else { | |
218 dsym->toObjFile(); | |
219 } | |
220 } | |
221 | |
222 llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields); | |
223 | |
224 // refine abstract types for stuff like: struct S{S* next;} | |
225 if (gIR->topstruct().recty != 0) | |
226 { | |
227 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
228 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
229 structtype = llvm::cast<llvm::StructType>(pa.get()); | |
230 } | |
231 | |
232 ts->llvmType = structtype; | |
233 llvmType = structtype; | |
234 | |
235 if (parent->isModule()) { | |
236 gIR->module->addTypeName(mangle(),ts->llvmType); | |
237 } | |
238 | |
239 // generate static data | |
240 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
241 llvm::Constant* _init = 0; | |
242 | |
243 // always generate the constant initalizer | |
244 if (!zeroInit) { | |
245 Logger::println("Not zero initialized"); | |
246 //assert(tk == gIR->topstruct().size()); | |
247 #ifndef LLVMD_NO_LOGGER | |
248 Logger::cout() << *structtype << '\n'; | |
249 for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) { | |
250 Logger::cout() << "Type:" << '\n'; | |
251 Logger::cout() << *gIR->topstruct().inits[k]->getType() << '\n'; | |
252 Logger::cout() << "Value:" << '\n'; | |
253 Logger::cout() << *gIR->topstruct().inits[k] << '\n'; | |
254 } | |
255 Logger::cout() << "Initializer printed" << '\n'; | |
256 #endif | |
257 llvmInitZ = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); | |
258 } | |
259 else { | |
260 Logger::println("Zero initialized"); | |
261 llvmInitZ = llvm::ConstantAggregateZero::get(structtype); | |
262 } | |
263 | |
264 // only provide the constant initializer for the defining module | |
265 if (getModule() == gIR->dmodule) | |
266 { | |
267 _init = llvmInitZ; | |
268 } | |
269 | |
270 std::string initname(mangle()); | |
271 initname.append("__initZ"); | |
272 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module); | |
273 ts->llvmInit = initvar; | |
274 | |
275 // generate member functions | |
276 size_t n = mfs.size(); | |
277 for (size_t i=0; i<n; ++i) { | |
278 mfs[i]->toObjFile(); | |
279 } | |
280 | |
281 llvmDModule = gIR->dmodule; | |
282 | |
283 gIR->structs.pop_back(); | |
284 | |
285 // generate typeinfo | |
286 type->getTypeInfo(NULL); // generate TypeInfo | |
287 } | |
288 | |
289 /* ================================================================== */ | |
290 | |
291 static void LLVM_AddBaseClassData(BaseClasses* bcs) | |
292 { | |
293 // add base class data members first | |
294 for (int j=0; j<bcs->dim; j++) | |
295 { | |
296 BaseClass* bc = (BaseClass*)(bcs->data[j]); | |
297 assert(bc); | |
298 LLVM_AddBaseClassData(&bc->base->baseclasses); | |
299 for (int k=0; k < bc->base->members->dim; k++) { | |
300 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); | |
301 if (dsym->isVarDeclaration()) | |
302 { | |
303 dsym->toObjFile(); | |
304 } | |
305 } | |
306 } | |
307 } | |
308 | |
309 void ClassDeclaration::toObjFile() | |
310 { | |
311 TypeClass* ts = (TypeClass*)type; | |
312 if (ts->llvmType != 0 || llvmInProgress) | |
313 return; | |
314 | |
315 llvmInProgress = true; | |
316 | |
317 static int fdi = 0; | |
318 Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars()); | |
319 LOG_SCOPE; | |
320 | |
6 | 321 gIR->structs.push_back(IRStruct(ts)); |
1 | 322 gIR->classes.push_back(this); |
323 gIR->classmethods.push_back(IRState::FuncDeclVec()); | |
324 gIR->queueClassMethods.push_back(true); | |
325 | |
326 // add vtable | |
327 const llvm::Type* vtabty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
328 gIR->topstruct().fields.push_back(vtabty); | |
329 gIR->topstruct().inits.push_back(0); | |
330 | |
331 // base classes first | |
332 LLVM_AddBaseClassData(&baseclasses); | |
333 | |
334 // then add own members | |
335 for (int k=0; k < members->dim; k++) { | |
336 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
337 dsym->toObjFile(); | |
338 } | |
339 | |
340 llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields); | |
6 | 341 // refine abstract types for stuff like: class C {C next;} |
342 if (gIR->topstruct().recty != 0) | |
343 { | |
344 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
345 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
346 structtype = llvm::cast<llvm::StructType>(pa.get()); | |
347 } | |
348 | |
1 | 349 ts->llvmType = structtype; |
350 llvmType = structtype; | |
351 | |
352 bool emit_vtable = false; | |
353 bool define_vtable = false; | |
354 if (parent->isModule()) { | |
355 gIR->module->addTypeName(mangle(),ts->llvmType); | |
356 emit_vtable = true; | |
357 define_vtable = (getModule() == gIR->dmodule); | |
358 } | |
359 else { | |
360 assert(0 && "class parent is not a module"); | |
361 } | |
362 | |
363 // generate member functions | |
364 gIR->queueClassMethods.back() = false; | |
365 IRState::FuncDeclVec& mfs = gIR->classmethods.back(); | |
366 size_t n = mfs.size(); | |
367 for (size_t i=0; i<n; ++i) { | |
368 mfs[i]->toObjFile(); | |
369 } | |
370 | |
371 // create vtable initializer | |
372 if (emit_vtable) | |
373 { | |
374 llvm::GlobalVariable* vtblVar = 0; | |
375 std::vector<llvm::Constant*> inits; | |
376 inits.reserve(vtbl.dim); | |
377 for (int k=0; k < vtbl.dim; k++) | |
378 { | |
379 Dsymbol* dsym = (Dsymbol*)vtbl.data[k]; | |
380 assert(dsym); | |
381 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
382 | |
383 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
384 fd->toObjFile(); | |
385 Logger::cout() << "casting to constant" << *fd->llvmValue << '\n'; | |
386 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
387 c = llvm::ConstantExpr::getBitCast(c, llvm::PointerType::get(llvm::Type::Int8Ty)); | |
388 inits.push_back(c); | |
389 } | |
390 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
391 llvm::Constant* c = llvm::Constant::getNullValue(llvm::PointerType::get(llvm::Type::Int8Ty)); | |
392 inits.push_back(c); | |
393 } | |
394 else | |
395 assert(0); | |
396 } | |
397 if (!inits.empty()) | |
398 { | |
399 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
400 std::string varname(mangle()); | |
401 varname.append("__vtblZ"); | |
402 const llvm::ArrayType* vtbl_ty = llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty), inits.size()); | |
403 vtblVar = new llvm::GlobalVariable(vtbl_ty, true, _linkage, 0, varname, gIR->module); | |
404 if (define_vtable) { | |
405 //Logger::cout() << "vtbl:::" << '\n' << *vtbl_st << '\n';// << " == | == " << _init << '\n'; | |
406 llvm::Constant* _init = llvm::ConstantArray::get(vtbl_ty, inits); | |
407 vtblVar->setInitializer(_init); | |
408 } | |
409 llvmVtbl = vtblVar; | |
410 } | |
411 | |
412 //////////////////////////////////////////////////////////////////////////////// | |
413 | |
414 // generate initializer | |
415 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
416 llvm::Constant* _init = 0; | |
417 | |
418 // first field is always the vtable | |
419 assert(vtblVar != 0); | |
420 llvm::Constant* vtbl_init_var = llvm::ConstantExpr::getBitCast(vtblVar, llvm::PointerType::get(llvm::Type::Int8Ty)); | |
421 gIR->topstruct().inits[0] = vtbl_init_var; | |
422 | |
423 //assert(tk == gIR->topstruct().size()); | |
424 #ifndef LLVMD_NO_LOGGER | |
425 Logger::cout() << *structtype << '\n'; | |
426 for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) | |
427 Logger::cout() << *gIR->topstruct().inits[k] << '\n'; | |
428 #endif | |
429 _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); | |
430 assert(_init); | |
431 std::string initname(mangle()); | |
432 initname.append("__initZ"); | |
433 Logger::cout() << *_init << '\n'; | |
434 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module); | |
435 ts->llvmInit = initvar; | |
436 if (define_vtable) { | |
437 initvar->setInitializer(_init); | |
438 } | |
439 } | |
440 | |
441 gIR->queueClassMethods.pop_back(); | |
442 gIR->classmethods.pop_back(); | |
443 gIR->classes.pop_back(); | |
444 gIR->structs.pop_back(); | |
445 | |
446 llvmInProgress = false; | |
447 } | |
448 | |
449 /****************************************** | |
450 * Get offset of base class's vtbl[] initializer from start of csym. | |
451 * Returns ~0 if not this csym. | |
452 */ | |
453 | |
454 unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc) | |
455 { | |
456 return ~0; | |
457 } | |
458 | |
459 /* ================================================================== */ | |
460 | |
461 void VarDeclaration::toObjFile() | |
462 { | |
463 static int vdi = 0; | |
464 Logger::print("VarDeclaration::toObjFile(%d): %s | %s\n", vdi++, toChars(), type->toChars()); | |
465 LOG_SCOPE; | |
466 llvm::Module* M = gIR->module; | |
467 | |
468 // handle bind pragma | |
469 if (llvmInternal == LLVMbind) { | |
470 Logger::println("var is bound: %s", llvmInternal1); | |
471 llvmValue = M->getGlobalVariable(llvmInternal1); | |
472 assert(llvmValue); | |
473 return; | |
474 } | |
475 | |
476 // global variable or magic | |
477 if (!parent || parent->isModule()) | |
478 { | |
479 bool _isconst = isConst(); | |
480 if (!_isconst) | |
481 _isconst = (storage_class & STCconst) ? true : false; // doesn't seem to work ): | |
482 llvm::GlobalValue::LinkageTypes _linkage = LLVM_DtoLinkage(protection, storage_class); | |
483 const llvm::Type* _type = LLVM_DtoType(type); | |
484 | |
485 llvm::Constant* _init = 0; | |
486 bool _signed = !type->isunsigned(); | |
487 | |
488 _init = LLVM_DtoInitializer(type, init); | |
489 | |
490 assert(_type); | |
491 assert(_init); | |
492 //Logger::cout() << "initializer: " << *_init << '\n'; | |
493 if (_type != _init->getType()) { | |
494 Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n"; | |
495 // zero initalizer | |
496 if (_init->isNullValue()) | |
497 _init = llvm::Constant::getNullValue(_type); | |
498 // pointer to global constant (struct.init) | |
499 else if (llvm::isa<llvm::GlobalVariable>(_init)) | |
500 { | |
501 assert(_init->getType()->getContainedType(0) == _type); | |
502 llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init); | |
503 assert(type->ty == Tstruct); | |
504 TypeStruct* ts = (TypeStruct*)type; | |
505 assert(ts->sym->llvmInitZ); | |
506 _init = ts->sym->llvmInitZ; | |
507 } | |
508 // array single value init | |
509 else if (llvm::isa<llvm::ArrayType>(_type)) | |
510 { | |
511 const llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(_type); | |
512 assert(_type->getContainedType(0) == _init->getType()); | |
513 std::vector<llvm::Constant*> initvals; | |
514 initvals.resize(at->getNumElements(), _init); | |
515 _init = llvm::ConstantArray::get(at, initvals); | |
516 } | |
517 else | |
518 assert(0); | |
519 } | |
520 | |
521 Logger::println("Creating global variable"); | |
522 std::string _name(mangle()); | |
523 llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M); | |
524 llvmValue = gvar; | |
525 | |
526 //if (storage_class & STCprivate) | |
527 // gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility); | |
528 } | |
529 | |
530 // inside aggregate declaration. declare a field. | |
531 else | |
532 { | |
533 Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset); | |
534 | |
535 const llvm::Type* _type = LLVM_DtoType(type); | |
536 gIR->topstruct().fields.push_back(_type); | |
537 | |
538 llvm::Constant* _init = LLVM_DtoInitializer(type, init); | |
539 if (_type != _init->getType()) | |
540 { | |
541 if (llvm::isa<llvm::ArrayType>(_type)) | |
542 { | |
543 const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(_type); | |
544 uint64_t n = arrty->getNumElements(); | |
545 std::vector<llvm::Constant*> vals(n,_init); | |
546 _init = llvm::ConstantArray::get(arrty, vals); | |
547 } | |
6 | 548 else if (llvm::isa<llvm::StructType>(_type)) { |
549 const llvm::StructType* structty = llvm::cast<llvm::StructType>(_type); | |
550 TypeStruct* ts = (TypeStruct*)type; | |
551 assert(ts->sym->llvmInitZ); | |
552 _init = ts->sym->llvmInitZ; | |
553 } | |
1 | 554 else |
555 assert(0); | |
556 } | |
557 gIR->topstruct().inits.push_back(_init); | |
558 } | |
559 | |
560 Logger::println("VarDeclaration::toObjFile is done"); | |
561 } | |
562 | |
563 /* ================================================================== */ | |
564 | |
565 void TypedefDeclaration::toObjFile() | |
566 { | |
567 static int tdi = 0; | |
568 Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); | |
569 LOG_SCOPE; | |
570 | |
571 // TODO | |
572 } | |
573 | |
574 /* ================================================================== */ | |
575 | |
576 void EnumDeclaration::toObjFile() | |
577 { | |
578 warning("Ignoring EnumDeclaration::toObjFile for %s", toChars()); | |
579 } | |
580 | |
581 /* ================================================================== */ | |
582 | |
583 void FuncDeclaration::toObjFile() | |
584 { | |
585 if (llvmValue != 0 && llvmDModule == gIR->dmodule) { | |
586 return; | |
587 } | |
588 | |
589 // has already been pulled in by a reference to ( | |
590 if (!gIR->queueClassMethods.empty() && gIR->queueClassMethods.back()) { | |
591 Logger::println("queueing %s", toChars()); | |
592 assert(!gIR->classmethods.empty()); | |
593 gIR->classmethods.back().push_back(this); | |
594 return; // will be generated later when the this parameter has a type | |
595 } | |
596 | |
597 static int fdi = 0; | |
598 Logger::print("FuncDeclaration::toObjFile(%d,%s): %s\n", fdi++, needThis()?"this":"static",toChars()); | |
599 LOG_SCOPE; | |
600 | |
601 if (llvmInternal == LLVMintrinsic && fbody) { | |
602 error("intrinsics cannot have function bodies"); | |
603 fatal(); | |
604 } | |
605 | |
606 TypeFunction* f = (TypeFunction*)type; | |
607 assert(f != 0); | |
608 | |
609 // return value type | |
610 const llvm::Type* rettype; | |
611 const llvm::Type* actualRettype; | |
612 Type* rt = f->next; | |
613 bool retinptr = false; | |
614 bool usesthis = false; | |
615 | |
616 if (isMain()) { | |
617 rettype = llvm::Type::Int32Ty; | |
618 actualRettype = rettype; | |
619 gIR->emitMain = true; | |
620 } | |
621 else if (rt) { | |
622 if (rt->ty == Tstruct || rt->ty == Tdelegate || rt->ty == Tarray) { | |
623 rettype = llvm::PointerType::get(LLVM_DtoType(rt)); | |
624 actualRettype = llvm::Type::VoidTy; | |
625 f->llvmRetInPtr = retinptr = true; | |
626 } | |
627 else { | |
628 rettype = LLVM_DtoType(rt); | |
629 actualRettype = rettype; | |
630 } | |
631 } | |
632 else { | |
633 assert(0); | |
634 } | |
635 | |
636 // parameter types | |
637 std::vector<const llvm::Type*> paramvec; | |
638 | |
639 if (retinptr) { | |
640 Logger::print("returning through pointer parameter\n"); | |
641 paramvec.push_back(rettype); | |
642 } | |
643 | |
644 if (needThis()) { | |
645 if (AggregateDeclaration* ad = isMember()) { | |
646 Logger::print("isMember = this is: %s\n", ad->type->toChars()); | |
647 const llvm::Type* thisty = LLVM_DtoType(ad->type); | |
648 if (llvm::isa<llvm::StructType>(thisty)) | |
649 thisty = llvm::PointerType::get(thisty); | |
650 paramvec.push_back(thisty); | |
651 usesthis = true; | |
652 } | |
653 else | |
654 assert(0); | |
655 } | |
656 | |
657 size_t n = Argument::dim(f->parameters); | |
658 for (int i=0; i < n; ++i) { | |
659 Argument* arg = Argument::getNth(f->parameters, i); | |
660 // ensure scalar | |
661 Type* argT = arg->type; | |
662 assert(argT); | |
663 | |
664 if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) { | |
665 //assert(arg->vardecl); | |
666 //arg->vardecl->refparam = true; | |
667 } | |
668 else | |
669 arg->llvmCopy = true; | |
670 | |
671 const llvm::Type* at = LLVM_DtoType(argT); | |
672 if (llvm::isa<llvm::StructType>(at)) { | |
673 Logger::println("struct param"); | |
674 paramvec.push_back(llvm::PointerType::get(at)); | |
675 } | |
676 else if (llvm::isa<llvm::ArrayType>(at)) { | |
677 Logger::println("sarray param"); | |
678 assert(argT->ty == Tsarray); | |
679 //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0))); | |
680 paramvec.push_back(llvm::PointerType::get(at)); | |
681 } | |
682 else { | |
683 if (!arg->llvmCopy) { | |
684 Logger::println("ref param"); | |
685 at = llvm::PointerType::get(at); | |
686 } | |
687 else { | |
688 Logger::println("in param"); | |
689 } | |
690 paramvec.push_back(at); | |
691 } | |
692 } | |
693 | |
694 // construct function | |
695 bool isvararg = f->varargs; | |
696 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
697 | |
698 // mangled name | |
699 char* mangled_name = (llvmInternal == LLVMintrinsic) ? llvmInternal1 : mangle(); | |
700 llvm::Function* func = gIR->module->getFunction(mangled_name); | |
701 | |
702 // make the function | |
703 /*if (func != 0) { | |
704 llvmValue = func; | |
705 f->llvmType = functype; | |
706 return; // already pulled in from a forward declaration | |
707 } | |
708 else */ | |
709 if (func == 0) { | |
710 func = new llvm::Function(functype,LLVM_DtoLinkage(protection, storage_class),mangled_name,gIR->module); | |
711 } | |
712 | |
713 if (llvmInternal != LLVMintrinsic) | |
714 func->setCallingConv(LLVM_DtoCallingConv(f->linkage)); | |
715 | |
716 llvmValue = func; | |
717 f->llvmType = functype; | |
718 | |
719 if (isMain()) { | |
720 gIR->mainFunc = func; | |
721 } | |
722 | |
723 // name parameters | |
724 llvm::Function::arg_iterator iarg = func->arg_begin(); | |
725 int k = 0; | |
726 int nunnamed = 0; | |
727 if (retinptr) { | |
728 iarg->setName("retval"); | |
729 f->llvmRetArg = iarg; | |
730 ++iarg; | |
731 } | |
732 if (usesthis) { | |
733 iarg->setName("this"); | |
734 ++iarg; | |
735 } | |
736 for (; iarg != func->arg_end(); ++iarg) | |
737 { | |
738 Argument* arg = Argument::getNth(f->parameters, k++); | |
739 //arg->llvmValue = iarg; | |
740 //printf("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident); | |
741 if (arg->ident != 0) { | |
742 if (arg->vardecl) { | |
743 arg->vardecl->llvmValue = iarg; | |
744 } | |
745 iarg->setName(arg->ident->toChars()); | |
746 } | |
747 else { | |
748 ++nunnamed; | |
749 } | |
750 } | |
751 | |
752 // only members of the current module maybe be defined | |
753 if (getModule() == gIR->dmodule) | |
754 { | |
755 bool allow_fbody = true; | |
756 // handle static constructor / destructor | |
757 if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) { | |
758 const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1); | |
759 //Logger::cout() << "static ctor type: " << *sctor_type << '\n'; | |
760 | |
761 llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue); | |
762 //Logger::cout() << "static ctor func: " << *sctor_func << '\n'; | |
763 | |
764 llvm::Constant* sctor_init = 0; | |
765 if (llvmInternal == LLVMnull) | |
766 { | |
767 llvm::Constant* sctor_init_null = llvm::Constant::getNullValue(sctor_func->getType()); | |
768 sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_init_null,1); | |
769 allow_fbody = false; | |
770 } | |
771 else | |
772 { | |
773 sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1); | |
774 } | |
775 | |
776 //Logger::cout() << "static ctor init: " << *sctor_init << '\n'; | |
777 | |
778 | |
779 // output the llvm.global_ctors array | |
780 const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array"; | |
781 llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module); | |
782 } | |
783 | |
784 // function definition | |
785 if (allow_fbody && fbody != 0) | |
786 { | |
787 assert(nunnamed == 0); | |
788 gIR->funcs.push(func); | |
789 gIR->functypes.push(f); | |
790 | |
791 IRScope irs; | |
792 irs.begin = new llvm::BasicBlock("entry",func); | |
793 irs.end = new llvm::BasicBlock("endentry",func); | |
794 | |
795 //assert(gIR->scopes.empty()); | |
796 gIR->scopes.push_back(irs); | |
797 | |
798 // create alloca point | |
799 f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); | |
800 | |
801 // output function body | |
802 fbody->toIR(gIR); | |
803 | |
804 // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement | |
805 // in automatically, so we do it here. | |
806 if (!isMain() && (gIR->scopebb()->empty() || !llvm::isa<llvm::TerminatorInst>(gIR->scopebb()->back()))) { | |
807 // pass the previous block into this block | |
808 //new llvm::BranchInst(irs.end, irs.begin); | |
809 new llvm::ReturnInst(gIR->scopebb()); | |
810 } | |
811 | |
812 // erase alloca point | |
813 f->llvmAllocaPoint->eraseFromParent(); | |
814 f->llvmAllocaPoint = 0; | |
815 | |
816 gIR->scopes.pop_back(); | |
817 //assert(gIR->scopes.empty()); | |
818 | |
819 gIR->functypes.pop(); | |
820 gIR->funcs.pop(); | |
821 | |
822 // get rid of the endentry block, it's never used | |
823 func->getBasicBlockList().pop_back(); | |
824 | |
825 // if the last block is empty now, it must be unreachable or it's a bug somewhere else | |
826 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); | |
827 if (lastbb->empty()) { | |
828 new llvm::UnreachableInst(lastbb); | |
829 } | |
830 } | |
831 } | |
832 else | |
833 { | |
834 Logger::println("only declaration"); | |
835 } | |
836 | |
837 llvmDModule = gIR->dmodule; | |
838 | |
839 Logger::println("FuncDeclaration done\n"); | |
840 } |