Mercurial > projects > ldc
comparison gen/toobj.cpp @ 100:5071469303d4 trunk
[svn r104] TONS OF FIXES.
Split up declaration, constant initializer gen and definition for globals, structs, classes and functions.
Improved ClassInfo support (not complete), not in vtable yet.
Fixed a bunch of forward reference problems.
Much more. Major commit! :)
author | lindquist |
---|---|
date | Fri, 16 Nov 2007 08:21:47 +0100 |
parents | 6789050b5ad1 |
children | 027b8d8b71ec |
comparison
equal
deleted
inserted
replaced
99:a676a7743642 | 100:5071469303d4 |
---|---|
34 #include "gen/irstate.h" | 34 #include "gen/irstate.h" |
35 #include "gen/logger.h" | 35 #include "gen/logger.h" |
36 #include "gen/tollvm.h" | 36 #include "gen/tollvm.h" |
37 #include "gen/arrays.h" | 37 #include "gen/arrays.h" |
38 #include "gen/structs.h" | 38 #include "gen/structs.h" |
39 #include "gen/classes.h" | |
40 #include "gen/functions.h" | |
39 #include "gen/todebug.h" | 41 #include "gen/todebug.h" |
40 #include "gen/runtime.h" | 42 #include "gen/runtime.h" |
41 | 43 |
42 ////////////////////////////////////////////////////////////////////////////////////////// | 44 ////////////////////////////////////////////////////////////////////////////////////////// |
43 | 45 |
88 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | 90 Dsymbol* dsym = (Dsymbol*)(members->data[k]); |
89 assert(dsym); | 91 assert(dsym); |
90 dsym->toObjFile(); | 92 dsym->toObjFile(); |
91 } | 93 } |
92 | 94 |
93 // check if there are queued function definitions, if so process their bodies now | 95 // process deferred const initializers |
94 if (!ir.funcQueue.empty()) { | 96 for (size_t i=0; i<ir.constInitQueue.size(); ++i) { |
95 size_t n = ir.funcQueue.size(); | 97 DtoConstInitDsymbol(ir.constInitQueue[i]); |
96 for (size_t i=0; i<n; ++i) { | 98 } |
97 ir.funcQueue[i]->toObjFile(); | 99 |
98 } | 100 // process deferred definitions |
101 for (size_t i=0; i<ir.defineQueue.size(); ++i) { | |
102 DtoDefineDsymbol(ir.defineQueue[i]); | |
99 } | 103 } |
100 | 104 |
101 // generate ModuleInfo | 105 // generate ModuleInfo |
102 genmoduleinfo(); | 106 genmoduleinfo(); |
103 | 107 |
320 | 324 |
321 /* ================================================================== */ | 325 /* ================================================================== */ |
322 | 326 |
323 void StructDeclaration::toObjFile() | 327 void StructDeclaration::toObjFile() |
324 { | 328 { |
325 TypeStruct* ts = (TypeStruct*)DtoDType(type); | 329 DtoDeclareStruct(this); |
326 if (llvmType != 0) | |
327 return; | |
328 | |
329 static int sdi = 0; | |
330 Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars()); | |
331 LOG_SCOPE; | |
332 | |
333 gIR->structs.push_back(IRStruct(ts)); | |
334 | |
335 for (int k=0; k < members->dim; k++) { | |
336 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
337 dsym->toObjFile(); | |
338 } | |
339 | |
340 Logger::println("doing struct fields"); | |
341 | |
342 const llvm::StructType* structtype = 0; | |
343 std::vector<llvm::Constant*> fieldinits; | |
344 | |
345 if (gIR->topstruct().offsets.empty()) | |
346 { | |
347 std::vector<const llvm::Type*> fieldtypes; | |
348 Logger::println("has no fields"); | |
349 fieldtypes.push_back(llvm::Type::Int8Ty); | |
350 fieldinits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
351 structtype = llvm::StructType::get(fieldtypes); | |
352 } | |
353 else | |
354 { | |
355 Logger::println("has fields"); | |
356 std::vector<const llvm::Type*> fieldtypes; | |
357 unsigned prevsize = (unsigned)-1; | |
358 unsigned lastoffset = (unsigned)-1; | |
359 const llvm::Type* fieldtype = NULL; | |
360 llvm::Constant* fieldinit = NULL; | |
361 size_t fieldpad = 0; | |
362 int idx = 0; | |
363 for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) { | |
364 // first iteration | |
365 if (lastoffset == (unsigned)-1) { | |
366 lastoffset = i->first; | |
367 assert(lastoffset == 0); | |
368 fieldtype = DtoType(i->second.var->type); | |
369 fieldinit = i->second.init; | |
370 prevsize = gTargetData->getTypeSize(fieldtype); | |
371 i->second.var->llvmFieldIndex = idx; | |
372 } | |
373 // colliding offset? | |
374 else if (lastoffset == i->first) { | |
375 const llvm::Type* t = DtoType(i->second.var->type); | |
376 size_t s = gTargetData->getTypeSize(t); | |
377 if (s > prevsize) { | |
378 fieldpad += s - prevsize; | |
379 prevsize = s; | |
380 } | |
381 llvmHasUnions = true; | |
382 i->second.var->llvmFieldIndex = idx; | |
383 } | |
384 // intersecting offset? | |
385 else if (i->first < (lastoffset + prevsize)) { | |
386 const llvm::Type* t = DtoType(i->second.var->type); | |
387 size_t s = gTargetData->getTypeSize(t); | |
388 assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size | |
389 llvmHasUnions = true; | |
390 i->second.var->llvmFieldIndex = idx; | |
391 i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s; | |
392 } | |
393 // fresh offset | |
394 else { | |
395 // commit the field | |
396 fieldtypes.push_back(fieldtype); | |
397 fieldinits.push_back(fieldinit); | |
398 if (fieldpad) { | |
399 // match up with below | |
400 std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
401 llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals); | |
402 fieldtypes.push_back(c->getType()); | |
403 fieldinits.push_back(c); | |
404 idx++; | |
405 } | |
406 | |
407 idx++; | |
408 | |
409 // start new | |
410 lastoffset = i->first; | |
411 fieldtype = DtoType(i->second.var->type); | |
412 fieldinit = i->second.init; | |
413 prevsize = gTargetData->getTypeSize(fieldtype); | |
414 i->second.var->llvmFieldIndex = idx; | |
415 fieldpad = 0; | |
416 } | |
417 } | |
418 fieldtypes.push_back(fieldtype); | |
419 fieldinits.push_back(fieldinit); | |
420 if (fieldpad) { | |
421 // match up with above | |
422 std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
423 llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals); | |
424 fieldtypes.push_back(c->getType()); | |
425 fieldinits.push_back(c); | |
426 } | |
427 | |
428 Logger::println("creating struct type"); | |
429 structtype = llvm::StructType::get(fieldtypes); | |
430 } | |
431 | |
432 // refine abstract types for stuff like: struct S{S* next;} | |
433 if (gIR->topstruct().recty != 0) | |
434 { | |
435 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
436 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
437 structtype = isaStruct(pa.get()); | |
438 } | |
439 | |
440 ts->llvmType = structtype; | |
441 llvmType = structtype; | |
442 | |
443 if (parent->isModule()) { | |
444 gIR->module->addTypeName(mangle(),ts->llvmType); | |
445 } | |
446 | |
447 llvmUnion = new DUnion; // uses gIR->topstruct() | |
448 | |
449 // generate static data | |
450 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
451 llvm::Constant* _init = 0; | |
452 | |
453 // always generate the constant initalizer | |
454 if (!zeroInit) { | |
455 Logger::println("Not zero initialized"); | |
456 //assert(tk == gIR->gIR->topstruct()().size()); | |
457 #ifndef LLVMD_NO_LOGGER | |
458 Logger::cout() << "struct type: " << *structtype << '\n'; | |
459 for (size_t k=0; k<fieldinits.size(); ++k) { | |
460 Logger::cout() << "Type:" << '\n'; | |
461 Logger::cout() << *fieldinits[k]->getType() << '\n'; | |
462 Logger::cout() << "Value:" << '\n'; | |
463 Logger::cout() << *fieldinits[k] << '\n'; | |
464 } | |
465 Logger::cout() << "Initializer printed" << '\n'; | |
466 #endif | |
467 llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits); | |
468 } | |
469 else { | |
470 Logger::println("Zero initialized"); | |
471 llvmInitZ = llvm::ConstantAggregateZero::get(structtype); | |
472 } | |
473 | |
474 // only provide the constant initializer for the defining module | |
475 if (getModule() == gIR->dmodule) | |
476 { | |
477 _init = llvmInitZ; | |
478 } | |
479 | |
480 std::string initname("_D"); | |
481 initname.append(mangle()); | |
482 initname.append("6__initZ"); | |
483 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module); | |
484 ts->llvmInit = initvar; | |
485 | |
486 // generate member function definitions | |
487 gIR->topstruct().queueFuncs = false; | |
488 IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs; | |
489 size_t n = mfs.size(); | |
490 for (size_t i=0; i<n; ++i) { | |
491 //mfs[i]->toObjFile(); | |
492 gIR->funcQueue.push_back(mfs[i]); | |
493 } | |
494 | |
495 llvmDModule = gIR->dmodule; | |
496 | |
497 gIR->structs.pop_back(); | |
498 | |
499 // generate typeinfo | |
500 if (getModule() == gIR->dmodule && llvmInternal != LLVMnotypeinfo) | |
501 type->getTypeInfo(NULL); | |
502 } | 330 } |
503 | 331 |
504 /* ================================================================== */ | 332 /* ================================================================== */ |
505 | 333 |
506 static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) | 334 static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) |
532 result.push_back(r+1); // vtable is 0 | 360 result.push_back(r+1); // vtable is 0 |
533 } | 361 } |
534 | 362 |
535 /* ================================================================== */ | 363 /* ================================================================== */ |
536 | 364 |
537 static void LLVM_AddBaseClassData(BaseClasses* bcs) | |
538 { | |
539 // add base class data members first | |
540 for (int j=0; j<bcs->dim; j++) | |
541 { | |
542 BaseClass* bc = (BaseClass*)(bcs->data[j]); | |
543 assert(bc); | |
544 Logger::println("Adding base class members of %s", bc->base->toChars()); | |
545 LOG_SCOPE; | |
546 | |
547 LLVM_AddBaseClassData(&bc->base->baseclasses); | |
548 for (int k=0; k < bc->base->members->dim; k++) { | |
549 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); | |
550 if (dsym->isVarDeclaration()) | |
551 { | |
552 dsym->toObjFile(); | |
553 } | |
554 } | |
555 } | |
556 } | |
557 | |
558 void ClassDeclaration::toObjFile() | 365 void ClassDeclaration::toObjFile() |
559 { | 366 { |
560 TypeClass* ts = (TypeClass*)DtoDType(type); | 367 DtoDeclareClass(this); |
561 if (ts->llvmType != 0 || llvmInProgress) | |
562 return; | |
563 | |
564 llvmInProgress = true; | |
565 | |
566 static int fdi = 0; | |
567 Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars()); | |
568 LOG_SCOPE; | |
569 | |
570 gIR->structs.push_back(IRStruct(ts)); | |
571 gIR->classes.push_back(this); | |
572 | |
573 // add vtable | |
574 llvm::PATypeHolder pa = llvm::OpaqueType::get(); | |
575 const llvm::Type* vtabty = llvm::PointerType::get(pa); | |
576 | |
577 std::vector<const llvm::Type*> fieldtypes; | |
578 fieldtypes.push_back(vtabty); | |
579 | |
580 std::vector<llvm::Constant*> fieldinits; | |
581 fieldinits.push_back(0); | |
582 | |
583 // base classes first | |
584 LLVM_AddBaseClassData(&baseclasses); | |
585 | |
586 // then add own members | |
587 for (int k=0; k < members->dim; k++) { | |
588 Dsymbol* dsym = (Dsymbol*)(members->data[k]); | |
589 dsym->toObjFile(); | |
590 } | |
591 | |
592 // fill out fieldtypes/inits | |
593 for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) { | |
594 fieldtypes.push_back(DtoType(i->second.var->type)); | |
595 fieldinits.push_back(i->second.init); | |
596 } | |
597 | |
598 const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); | |
599 // refine abstract types for stuff like: class C {C next;} | |
600 if (gIR->topstruct().recty != 0) | |
601 { | |
602 llvm::PATypeHolder& pa = gIR->topstruct().recty; | |
603 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | |
604 structtype = isaStruct(pa.get()); | |
605 } | |
606 | |
607 ts->llvmType = structtype; | |
608 llvmType = structtype; | |
609 | |
610 bool needs_definition = false; | |
611 if (parent->isModule()) { | |
612 gIR->module->addTypeName(mangle(),ts->llvmType); | |
613 needs_definition = (getModule() == gIR->dmodule); | |
614 } | |
615 else { | |
616 assert(0 && "class parent is not a module"); | |
617 } | |
618 | |
619 // generate vtable | |
620 llvm::GlobalVariable* svtblVar = 0; | |
621 std::vector<llvm::Constant*> sinits; | |
622 std::vector<const llvm::Type*> sinits_ty; | |
623 sinits.reserve(vtbl.dim); | |
624 sinits_ty.reserve(vtbl.dim); | |
625 | |
626 for (int k=0; k < vtbl.dim; k++) | |
627 { | |
628 Dsymbol* dsym = (Dsymbol*)vtbl.data[k]; | |
629 assert(dsym); | |
630 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
631 | |
632 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
633 fd->toObjFile(); | |
634 assert(fd->llvmValue); | |
635 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
636 sinits.push_back(c); | |
637 sinits_ty.push_back(c->getType()); | |
638 } | |
639 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
640 const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
641 llvm::Constant* c = llvm::Constant::getNullValue(cty); | |
642 sinits.push_back(c); | |
643 sinits_ty.push_back(cty); | |
644 } | |
645 else | |
646 assert(0); | |
647 } | |
648 | |
649 const llvm::StructType* svtbl_ty = 0; | |
650 if (!sinits.empty()) | |
651 { | |
652 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
653 | |
654 std::string varname("_D"); | |
655 varname.append(mangle()); | |
656 varname.append("6__vtblZ"); | |
657 | |
658 std::string styname(mangle()); | |
659 styname.append("__vtblTy"); | |
660 | |
661 svtbl_ty = llvm::StructType::get(sinits_ty); | |
662 gIR->module->addTypeName(styname, svtbl_ty); | |
663 svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); | |
664 | |
665 llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits)); | |
666 if (needs_definition) | |
667 svtblVar->setInitializer(llvmConstVtbl); | |
668 llvmVtbl = svtblVar; | |
669 } | |
670 | |
671 //////////////////////////////////////////////////////////////////////////////// | |
672 | |
673 // refine for final vtable type | |
674 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty); | |
675 svtbl_ty = isaStruct(pa.get()); | |
676 structtype = isaStruct(gIR->topstruct().recty.get()); | |
677 ts->llvmType = structtype; | |
678 llvmType = structtype; | |
679 | |
680 // generate initializer | |
681 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
682 llvm::Constant* _init = 0; | |
683 | |
684 // first field is always the vtable | |
685 assert(svtblVar != 0); | |
686 fieldinits[0] = svtblVar; | |
687 | |
688 llvmInitZ = _init = llvm::ConstantStruct::get(structtype,fieldinits); | |
689 assert(_init); | |
690 | |
691 std::string initname("_D"); | |
692 initname.append(mangle()); | |
693 initname.append("6__initZ"); | |
694 //Logger::cout() << *_init << '\n'; | |
695 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, NULL, initname, gIR->module); | |
696 ts->llvmInit = initvar; | |
697 | |
698 if (needs_definition) { | |
699 initvar->setInitializer(_init); | |
700 // generate member functions | |
701 gIR->topstruct().queueFuncs = false; | |
702 IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs; | |
703 size_t n = mfs.size(); | |
704 for (size_t i=0; i<n; ++i) { | |
705 //mfs[i]->toObjFile(); | |
706 gIR->funcQueue.push_back(mfs[i]); | |
707 } | |
708 } | |
709 | |
710 gIR->classes.pop_back(); | |
711 gIR->structs.pop_back(); | |
712 | |
713 llvmInProgress = false; | |
714 | |
715 // if (ClassDeclaration::classinfo != this) | |
716 // DtoClassInfo(this); | |
717 } | 368 } |
718 | 369 |
719 /****************************************** | 370 /****************************************** |
720 * Get offset of base class's vtbl[] initializer from start of csym. | 371 * Get offset of base class's vtbl[] initializer from start of csym. |
721 * Returns ~0 if not this csym. | 372 * Returns ~0 if not this csym. |
730 | 381 |
731 void VarDeclaration::toObjFile() | 382 void VarDeclaration::toObjFile() |
732 { | 383 { |
733 Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); | 384 Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); |
734 LOG_SCOPE; | 385 LOG_SCOPE; |
735 llvm::Module* M = gIR->module; | |
736 | 386 |
737 if (aliassym) | 387 if (aliassym) |
738 { | 388 { |
739 Logger::println("alias sym"); | 389 Logger::println("alias sym"); |
740 toAlias()->toObjFile(); | 390 toAlias()->toObjFile(); |
745 if (isDataseg()) | 395 if (isDataseg()) |
746 { | 396 { |
747 if (llvmTouched) return; | 397 if (llvmTouched) return; |
748 else llvmTouched = true; | 398 else llvmTouched = true; |
749 | 399 |
750 bool _isconst = false; | 400 llvmIRGlobal = new IRGlobal(this); |
751 if (isConst() && (init && !init->isExpInitializer())) | 401 |
752 _isconst = true; | 402 Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); |
403 | |
404 bool _isconst = isConst(); | |
405 if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) | |
406 _isconst = false; | |
753 | 407 |
754 llvm::GlobalValue::LinkageTypes _linkage; | 408 llvm::GlobalValue::LinkageTypes _linkage; |
755 bool istempl = false; | 409 bool istempl = false; |
410 bool static_local = false; | |
756 if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) { | 411 if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) { |
757 _linkage = llvm::GlobalValue::WeakLinkage; | 412 _linkage = llvm::GlobalValue::WeakLinkage; |
758 istempl = true; | 413 istempl = true; |
759 } | 414 } |
760 else if (parent && parent->isFuncDeclaration()) | 415 else if (parent && parent->isFuncDeclaration()) { |
761 _linkage = llvm::GlobalValue::InternalLinkage; | 416 _linkage = llvm::GlobalValue::InternalLinkage; |
417 static_local = true; | |
418 } | |
762 else | 419 else |
763 _linkage = DtoLinkage(protection, storage_class); | 420 _linkage = DtoLinkage(protection, storage_class); |
764 | 421 |
765 Type* t = DtoDType(type); | 422 const llvm::Type* _type = llvmIRGlobal->type.get(); |
766 | |
767 const llvm::Type* _type = DtoType(t); | |
768 assert(_type); | |
769 | |
770 llvm::Constant* _init = 0; | |
771 bool _signed = !type->isunsigned(); | |
772 | 423 |
773 Logger::println("Creating global variable"); | 424 Logger::println("Creating global variable"); |
774 std::string _name(mangle()); | 425 std::string _name(mangle()); |
775 | 426 |
776 bool emitRTstaticInit = false; | 427 llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module); |
777 | |
778 if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl)) | |
779 { | |
780 if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) { | |
781 _init = DtoConstInitializer(t, NULL); | |
782 emitRTstaticInit = true; | |
783 } | |
784 else { | |
785 _init = DtoConstInitializer(t, init); | |
786 } | |
787 | |
788 //Logger::cout() << "initializer: " << *_init << '\n'; | |
789 if (_type != _init->getType()) { | |
790 Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n"; | |
791 // zero initalizer | |
792 if (_init->isNullValue()) | |
793 _init = llvm::Constant::getNullValue(_type); | |
794 // pointer to global constant (struct.init) | |
795 else if (llvm::isa<llvm::GlobalVariable>(_init)) | |
796 { | |
797 assert(_init->getType()->getContainedType(0) == _type); | |
798 llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init); | |
799 assert(t->ty == Tstruct); | |
800 TypeStruct* ts = (TypeStruct*)t; | |
801 assert(ts->sym->llvmInitZ); | |
802 _init = ts->sym->llvmInitZ; | |
803 } | |
804 // array single value init | |
805 else if (isaArray(_type)) | |
806 { | |
807 _init = DtoConstStaticArray(_type, _init); | |
808 } | |
809 else { | |
810 Logger::cout() << "Unexpected initializer type: " << *_type << '\n'; | |
811 //assert(0); | |
812 } | |
813 } | |
814 } | |
815 | |
816 if (_init && _init->getType() != _type) | |
817 _type = _init->getType(); | |
818 llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M); | |
819 llvmValue = gvar; | 428 llvmValue = gvar; |
820 | 429 |
821 if (emitRTstaticInit) | 430 if (static_local) |
822 DtoLazyStaticInit(istempl, gvar, init, t); | 431 DtoConstInitGlobal(this); |
823 | 432 else |
824 llvmDModule = gIR->dmodule; | 433 gIR->constInitQueue.push_back(this); |
825 | 434 |
826 //if (storage_class & STCprivate) | 435 //if (storage_class & STCprivate) |
827 // gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility); | 436 // gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility); |
828 } | 437 } |
829 | 438 |
830 // inside aggregate declaration. declare a field. | 439 // inside aggregate declaration. declare a field. |
831 else | 440 else |
832 { | 441 { |
833 Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset); | 442 Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset); |
834 | 443 |
835 Type* t = DtoDType(type); | 444 const llvm::Type* _type = DtoType(type); |
836 const llvm::Type* _type = DtoType(t); | |
837 | |
838 llvm::Constant*_init = DtoConstInitializer(t, init); | |
839 assert(_init); | |
840 Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n'; | |
841 if (_type != _init->getType()) | |
842 { | |
843 if (t->ty == Tsarray) | |
844 { | |
845 const llvm::ArrayType* arrty = isaArray(_type); | |
846 uint64_t n = arrty->getNumElements(); | |
847 std::vector<llvm::Constant*> vals(n,_init); | |
848 _init = llvm::ConstantArray::get(arrty, vals); | |
849 } | |
850 else if (t->ty == Tarray) | |
851 { | |
852 assert(isaStruct(_type)); | |
853 _init = llvm::ConstantAggregateZero::get(_type); | |
854 } | |
855 else if (t->ty == Tstruct) | |
856 { | |
857 const llvm::StructType* structty = isaStruct(_type); | |
858 TypeStruct* ts = (TypeStruct*)t; | |
859 assert(ts); | |
860 assert(ts->sym); | |
861 assert(ts->sym->llvmInitZ); | |
862 _init = ts->sym->llvmInitZ; | |
863 } | |
864 else if (t->ty == Tclass) | |
865 { | |
866 _init = llvm::Constant::getNullValue(_type); | |
867 } | |
868 else { | |
869 Logger::println("failed for type %s", type->toChars()); | |
870 assert(0); | |
871 } | |
872 } | |
873 | 445 |
874 // add the field in the IRStruct | 446 // add the field in the IRStruct |
875 gIR->topstruct().offsets.insert(std::make_pair(offset, IRStruct::Offset(this,_init))); | 447 gIR->topstruct()->offsets.insert(std::make_pair(offset, IRStruct::Offset(this, _type))); |
876 } | 448 } |
877 | 449 |
878 Logger::println("VarDeclaration::toObjFile is done"); | 450 Logger::println("VarDeclaration::toObjFile is done"); |
879 } | 451 } |
880 | 452 |
899 | 471 |
900 /* ================================================================== */ | 472 /* ================================================================== */ |
901 | 473 |
902 void FuncDeclaration::toObjFile() | 474 void FuncDeclaration::toObjFile() |
903 { | 475 { |
904 if (llvmDModule) { | 476 DtoDeclareFunction(this); |
905 assert(llvmValue != 0); | 477 } |
906 return; | |
907 } | |
908 | |
909 if (llvmRunTimeHack) { | |
910 Logger::println("runtime hack func chars: %s", toChars()); | |
911 if (!llvmValue) | |
912 llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars()); | |
913 return; | |
914 } | |
915 | |
916 if (isUnitTestDeclaration()) { | |
917 Logger::attention("ignoring unittest declaration: %s", toChars()); | |
918 return; | |
919 } | |
920 | |
921 Type* t = DtoDType(type); | |
922 TypeFunction* f = (TypeFunction*)t; | |
923 | |
924 bool declareOnly = false; | |
925 if (parent) | |
926 { | |
927 if (TemplateInstance* tinst = parent->isTemplateInstance()) { | |
928 TemplateDeclaration* tempdecl = tinst->tempdecl; | |
929 if (tempdecl->llvmInternal == LLVMva_start) | |
930 { | |
931 Logger::println("magic va_start found"); | |
932 llvmInternal = LLVMva_start; | |
933 declareOnly = true; | |
934 } | |
935 else if (tempdecl->llvmInternal == LLVMva_arg) | |
936 { | |
937 Logger::println("magic va_arg found"); | |
938 llvmInternal = LLVMva_arg; | |
939 return; | |
940 } | |
941 } | |
942 } | |
943 | |
944 llvm::Function* func = DtoDeclareFunction(this); | |
945 | |
946 if (declareOnly) | |
947 return; | |
948 | |
949 if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) { | |
950 if (!llvmQueued) { | |
951 Logger::println("queueing %s", toChars()); | |
952 gIR->topstruct().funcs.push_back(this); | |
953 llvmQueued = true; | |
954 } | |
955 return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete | |
956 } | |
957 | |
958 // debug info | |
959 if (global.params.symdebug) { | |
960 Module* mo = getModule(); | |
961 if (!mo->llvmCompileUnit) { | |
962 mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false); | |
963 } | |
964 llvmDwarfSubProgram = DtoDwarfSubProgram(this, mo->llvmCompileUnit); | |
965 } | |
966 | |
967 assert(f->llvmType); | |
968 const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0)); | |
969 | |
970 // template instances should have weak linkage | |
971 if (parent && DtoIsTemplateInstance(parent)) { | |
972 func->setLinkage(llvm::GlobalValue::WeakLinkage); | |
973 } | |
974 | |
975 // only members of the current module maybe be defined | |
976 if (getModule() == gIR->dmodule || DtoIsTemplateInstance(parent)) | |
977 { | |
978 llvmDModule = gIR->dmodule; | |
979 | |
980 // handle static constructor / destructor | |
981 if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) { | |
982 const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1); | |
983 //Logger::cout() << "static ctor type: " << *sctor_type << '\n'; | |
984 | |
985 llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue); | |
986 //Logger::cout() << "static ctor func: " << *sctor_func << '\n'; | |
987 | |
988 llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1); | |
989 | |
990 //Logger::cout() << "static ctor init: " << *sctor_init << '\n'; | |
991 | |
992 // output the llvm.global_ctors array | |
993 const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array"; | |
994 llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module); | |
995 } | |
996 | |
997 // function definition | |
998 if (fbody != 0) | |
999 { | |
1000 gIR->functions.push_back(IRFunction(this)); | |
1001 gIR->func().func = func; | |
1002 | |
1003 // first make absolutely sure the type is up to date | |
1004 f->llvmType = llvmValue->getType()->getContainedType(0); | |
1005 | |
1006 //Logger::cout() << "func type: " << *f->llvmType << '\n'; | |
1007 | |
1008 // this handling | |
1009 if (f->llvmUsesThis) { | |
1010 Logger::println("uses this"); | |
1011 if (f->llvmRetInPtr) | |
1012 llvmThisVar = ++func->arg_begin(); | |
1013 else | |
1014 llvmThisVar = func->arg_begin(); | |
1015 assert(llvmThisVar != 0); | |
1016 } | |
1017 | |
1018 if (isMain()) | |
1019 gIR->emitMain = true; | |
1020 | |
1021 llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func); | |
1022 llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func); | |
1023 | |
1024 //assert(gIR->scopes.empty()); | |
1025 gIR->scopes.push_back(IRScope(beginbb, endbb)); | |
1026 | |
1027 // create alloca point | |
1028 f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); | |
1029 gIR->func().allocapoint = f->llvmAllocaPoint; | |
1030 | |
1031 // give arguments storage | |
1032 size_t n = Argument::dim(f->parameters); | |
1033 for (int i=0; i < n; ++i) { | |
1034 Argument* arg = Argument::getNth(f->parameters, i); | |
1035 if (arg && arg->vardecl) { | |
1036 VarDeclaration* vd = arg->vardecl; | |
1037 if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)) | |
1038 continue; | |
1039 llvm::Value* a = vd->llvmValue; | |
1040 assert(a); | |
1041 std::string s(a->getName()); | |
1042 Logger::println("giving argument '%s' storage", s.c_str()); | |
1043 s.append("_storage"); | |
1044 llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint); | |
1045 gIR->ir->CreateStore(a,v); | |
1046 vd->llvmValue = v; | |
1047 } | |
1048 else { | |
1049 Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0); | |
1050 } | |
1051 } | |
1052 | |
1053 // debug info | |
1054 if (global.params.symdebug) DtoDwarfFuncStart(this); | |
1055 | |
1056 llvm::Value* parentNested = NULL; | |
1057 if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) { | |
1058 parentNested = fd->llvmNested; | |
1059 } | |
1060 | |
1061 // construct nested variables struct | |
1062 if (!llvmNestedVars.empty() || parentNested) { | |
1063 std::vector<const llvm::Type*> nestTypes; | |
1064 int j = 0; | |
1065 if (parentNested) { | |
1066 nestTypes.push_back(parentNested->getType()); | |
1067 j++; | |
1068 } | |
1069 for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) { | |
1070 VarDeclaration* vd = *i; | |
1071 vd->llvmNestedIndex = j++; | |
1072 if (vd->isParameter()) { | |
1073 assert(vd->llvmValue); | |
1074 nestTypes.push_back(vd->llvmValue->getType()); | |
1075 } | |
1076 else { | |
1077 nestTypes.push_back(DtoType(vd->type)); | |
1078 } | |
1079 } | |
1080 const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); | |
1081 Logger::cout() << "nested var struct has type:" << '\n' << *nestSType; | |
1082 llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint); | |
1083 if (parentNested) { | |
1084 assert(llvmThisVar); | |
1085 llvm::Value* ptr = gIR->ir->CreateBitCast(llvmThisVar, parentNested->getType(), "tmp"); | |
1086 gIR->ir->CreateStore(ptr, DtoGEPi(llvmNested, 0,0, "tmp")); | |
1087 } | |
1088 for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) { | |
1089 VarDeclaration* vd = *i; | |
1090 if (vd->isParameter()) { | |
1091 gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(llvmNested, 0, vd->llvmNestedIndex, "tmp")); | |
1092 vd->llvmValue = llvmNested; | |
1093 } | |
1094 } | |
1095 } | |
1096 | |
1097 // copy _argptr to a memory location | |
1098 if (f->linkage == LINKd && f->varargs == 1) | |
1099 { | |
1100 llvm::Value* argptrmem = new llvm::AllocaInst(llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint()); | |
1101 new llvm::StoreInst(llvmArgPtr, argptrmem, gIR->scopebb()); | |
1102 llvmArgPtr = argptrmem; | |
1103 } | |
1104 | |
1105 // output function body | |
1106 fbody->toIR(gIR); | |
1107 | |
1108 // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement | |
1109 // in automatically, so we do it here. | |
1110 if (!isMain()) { | |
1111 if (!gIR->scopereturned()) { | |
1112 // pass the previous block into this block | |
1113 if (global.params.symdebug) DtoDwarfFuncEnd(this); | |
1114 if (func->getReturnType() == llvm::Type::VoidTy) { | |
1115 new llvm::ReturnInst(gIR->scopebb()); | |
1116 } | |
1117 else { | |
1118 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); | |
1119 } | |
1120 } | |
1121 } | |
1122 | |
1123 // erase alloca point | |
1124 f->llvmAllocaPoint->eraseFromParent(); | |
1125 f->llvmAllocaPoint = 0; | |
1126 gIR->func().allocapoint = 0; | |
1127 | |
1128 gIR->scopes.pop_back(); | |
1129 | |
1130 // get rid of the endentry block, it's never used | |
1131 assert(!func->getBasicBlockList().empty()); | |
1132 func->getBasicBlockList().pop_back(); | |
1133 | |
1134 // if the last block is empty now, it must be unreachable or it's a bug somewhere else | |
1135 // would be nice to figure out how to assert that this is correct | |
1136 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); | |
1137 if (lastbb->empty()) { | |
1138 if (lastbb->getNumUses() == 0) | |
1139 lastbb->eraseFromParent(); | |
1140 else { | |
1141 new llvm::UnreachableInst(lastbb); | |
1142 /*if (func->getReturnType() == llvm::Type::VoidTy) { | |
1143 new llvm::ReturnInst(lastbb); | |
1144 } | |
1145 else { | |
1146 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb); | |
1147 }*/ | |
1148 } | |
1149 } | |
1150 | |
1151 gIR->functions.pop_back(); | |
1152 } | |
1153 } | |
1154 } |