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