Mercurial > projects > ldc
comparison gen/toobj.c @ 9:dafae18f9c08 trunk
[svn r13] * Updated for LLVM 2.1
* Class v-tables are now typesafe
* Code cleanups
author | lindquist |
---|---|
date | Mon, 01 Oct 2007 21:19:53 +0200 |
parents | 5e69b77a5c51 |
children | c0f2c47e5034 |
comparison
equal
deleted
inserted
replaced
8:5e69b77a5c51 | 9:dafae18f9c08 |
---|---|
334 gIR->classes.push_back(this); | 334 gIR->classes.push_back(this); |
335 gIR->classmethods.push_back(IRState::FuncDeclVec()); | 335 gIR->classmethods.push_back(IRState::FuncDeclVec()); |
336 gIR->queueClassMethods.push_back(true); | 336 gIR->queueClassMethods.push_back(true); |
337 | 337 |
338 // add vtable | 338 // add vtable |
339 const llvm::Type* vtabty = llvm::PointerType::get(llvm::Type::Int8Ty); | 339 llvm::PATypeHolder pa = llvm::OpaqueType::get(); |
340 const llvm::Type* vtabty = llvm::PointerType::get(pa); | |
340 gIR->topstruct().fields.push_back(vtabty); | 341 gIR->topstruct().fields.push_back(vtabty); |
341 gIR->topstruct().inits.push_back(0); | 342 gIR->topstruct().inits.push_back(0); |
342 | 343 |
343 // base classes first | 344 // base classes first |
344 LLVM_AddBaseClassData(&baseclasses); | 345 LLVM_AddBaseClassData(&baseclasses); |
359 } | 360 } |
360 | 361 |
361 ts->llvmType = structtype; | 362 ts->llvmType = structtype; |
362 llvmType = structtype; | 363 llvmType = structtype; |
363 | 364 |
364 bool emit_vtable = false; | |
365 bool define_vtable = false; | 365 bool define_vtable = false; |
366 if (parent->isModule()) { | 366 if (parent->isModule()) { |
367 gIR->module->addTypeName(mangle(),ts->llvmType); | 367 gIR->module->addTypeName(mangle(),ts->llvmType); |
368 emit_vtable = true; | |
369 define_vtable = (getModule() == gIR->dmodule); | 368 define_vtable = (getModule() == gIR->dmodule); |
370 } | 369 } |
371 else { | 370 else { |
372 assert(0 && "class parent is not a module"); | 371 assert(0 && "class parent is not a module"); |
373 } | 372 } |
374 | 373 |
375 // generate member functions | 374 // generate vtable |
375 llvm::GlobalVariable* svtblVar = 0; | |
376 std::vector<llvm::Constant*> sinits; | |
377 std::vector<const llvm::Type*> sinits_ty; | |
378 sinits.reserve(vtbl.dim); | |
379 sinits_ty.reserve(vtbl.dim); | |
380 | |
381 for (int k=0; k < vtbl.dim; k++) | |
382 { | |
383 Dsymbol* dsym = (Dsymbol*)vtbl.data[k]; | |
384 assert(dsym); | |
385 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
386 | |
387 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
388 fd->toObjFile(); | |
389 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
390 sinits.push_back(c); | |
391 sinits_ty.push_back(c->getType()); | |
392 } | |
393 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
394 const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
395 llvm::Constant* c = llvm::Constant::getNullValue(cty); | |
396 sinits.push_back(c); | |
397 sinits_ty.push_back(cty); | |
398 } | |
399 else | |
400 assert(0); | |
401 } | |
402 | |
403 const llvm::StructType* svtbl_ty = 0; | |
404 if (!sinits.empty()) | |
405 { | |
406 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
407 | |
408 std::string varname(mangle()); | |
409 varname.append("__vtblZ"); | |
410 std::string styname(mangle()); | |
411 styname.append("__vtblTy"); | |
412 | |
413 svtbl_ty = llvm::StructType::get(sinits_ty); | |
414 gIR->module->addTypeName(styname, svtbl_ty); | |
415 svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); | |
416 | |
417 if (define_vtable) { | |
418 svtblVar->setInitializer(llvm::ConstantStruct::get(svtbl_ty, sinits)); | |
419 } | |
420 llvmVtbl = svtblVar; | |
421 } | |
422 | |
423 //////////////////////////////////////////////////////////////////////////////// | |
424 | |
425 // refine for final vtable type | |
426 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty); | |
427 svtbl_ty = llvm::cast<llvm::StructType>(pa.get()); | |
428 structtype = llvm::cast<llvm::StructType>(gIR->topstruct().recty.get()); | |
429 ts->llvmType = structtype; | |
430 llvmType = structtype; | |
431 | |
432 // generate initializer | |
433 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
434 llvm::Constant* _init = 0; | |
435 | |
436 // first field is always the vtable | |
437 assert(svtblVar != 0); | |
438 gIR->topstruct().inits[0] = svtblVar; | |
439 | |
440 //assert(tk == gIR->topstruct().size()); | |
441 #ifndef LLVMD_NO_LOGGER | |
442 Logger::cout() << *structtype << '\n'; | |
443 //for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) | |
444 // Logger::cout() << *gIR->topstruct().inits[k] << '\n'; | |
445 #endif | |
446 _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); | |
447 assert(_init); | |
448 std::string initname(mangle()); | |
449 initname.append("__initZ"); | |
450 Logger::cout() << *_init << '\n'; | |
451 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module); | |
452 ts->llvmInit = initvar; | |
453 if (define_vtable) { | |
454 initvar->setInitializer(_init); | |
455 } | |
456 | |
457 // generate member function definitions | |
376 gIR->queueClassMethods.back() = false; | 458 gIR->queueClassMethods.back() = false; |
377 IRState::FuncDeclVec& mfs = gIR->classmethods.back(); | 459 IRState::FuncDeclVec& mfs = gIR->classmethods.back(); |
378 size_t n = mfs.size(); | 460 size_t n = mfs.size(); |
379 for (size_t i=0; i<n; ++i) { | 461 for (size_t i=0; i<n; ++i) { |
380 mfs[i]->toObjFile(); | 462 mfs[i]->toObjFile(); |
381 } | |
382 | |
383 // create vtable initializer | |
384 if (emit_vtable) | |
385 { | |
386 llvm::GlobalVariable* vtblVar = 0; | |
387 std::vector<llvm::Constant*> inits; | |
388 inits.reserve(vtbl.dim); | |
389 for (int k=0; k < vtbl.dim; k++) | |
390 { | |
391 Dsymbol* dsym = (Dsymbol*)vtbl.data[k]; | |
392 assert(dsym); | |
393 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
394 | |
395 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
396 fd->toObjFile(); | |
397 Logger::cout() << "casting to constant" << *fd->llvmValue << '\n'; | |
398 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
399 c = llvm::ConstantExpr::getBitCast(c, llvm::PointerType::get(llvm::Type::Int8Ty)); | |
400 inits.push_back(c); | |
401 } | |
402 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
403 llvm::Constant* c = llvm::Constant::getNullValue(llvm::PointerType::get(llvm::Type::Int8Ty)); | |
404 inits.push_back(c); | |
405 } | |
406 else | |
407 assert(0); | |
408 } | |
409 if (!inits.empty()) | |
410 { | |
411 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
412 std::string varname(mangle()); | |
413 varname.append("__vtblZ"); | |
414 const llvm::ArrayType* vtbl_ty = llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty), inits.size()); | |
415 vtblVar = new llvm::GlobalVariable(vtbl_ty, true, _linkage, 0, varname, gIR->module); | |
416 if (define_vtable) { | |
417 //Logger::cout() << "vtbl:::" << '\n' << *vtbl_st << '\n';// << " == | == " << _init << '\n'; | |
418 llvm::Constant* _init = llvm::ConstantArray::get(vtbl_ty, inits); | |
419 vtblVar->setInitializer(_init); | |
420 } | |
421 llvmVtbl = vtblVar; | |
422 } | |
423 | |
424 //////////////////////////////////////////////////////////////////////////////// | |
425 | |
426 // generate initializer | |
427 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
428 llvm::Constant* _init = 0; | |
429 | |
430 // first field is always the vtable | |
431 assert(vtblVar != 0); | |
432 llvm::Constant* vtbl_init_var = llvm::ConstantExpr::getBitCast(vtblVar, llvm::PointerType::get(llvm::Type::Int8Ty)); | |
433 gIR->topstruct().inits[0] = vtbl_init_var; | |
434 | |
435 //assert(tk == gIR->topstruct().size()); | |
436 #ifndef LLVMD_NO_LOGGER | |
437 Logger::cout() << *structtype << '\n'; | |
438 for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) | |
439 Logger::cout() << *gIR->topstruct().inits[k] << '\n'; | |
440 #endif | |
441 _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); | |
442 assert(_init); | |
443 std::string initname(mangle()); | |
444 initname.append("__initZ"); | |
445 Logger::cout() << *_init << '\n'; | |
446 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module); | |
447 ts->llvmInit = initvar; | |
448 if (define_vtable) { | |
449 initvar->setInitializer(_init); | |
450 } | |
451 } | 463 } |
452 | 464 |
453 gIR->queueClassMethods.pop_back(); | 465 gIR->queueClassMethods.pop_back(); |
454 gIR->classmethods.pop_back(); | 466 gIR->classmethods.pop_back(); |
455 gIR->classes.pop_back(); | 467 gIR->classes.pop_back(); |
558 _init = llvm::ConstantArray::get(arrty, vals); | 570 _init = llvm::ConstantArray::get(arrty, vals); |
559 } | 571 } |
560 else if (llvm::isa<llvm::StructType>(_type)) { | 572 else if (llvm::isa<llvm::StructType>(_type)) { |
561 const llvm::StructType* structty = llvm::cast<llvm::StructType>(_type); | 573 const llvm::StructType* structty = llvm::cast<llvm::StructType>(_type); |
562 TypeStruct* ts = (TypeStruct*)type; | 574 TypeStruct* ts = (TypeStruct*)type; |
575 assert(ts); | |
576 assert(ts->sym); | |
563 assert(ts->sym->llvmInitZ); | 577 assert(ts->sym->llvmInitZ); |
564 _init = ts->sym->llvmInitZ; | 578 _init = ts->sym->llvmInitZ; |
565 } | 579 } |
566 else | 580 else |
567 assert(0); | 581 assert(0); |
592 | 606 |
593 /* ================================================================== */ | 607 /* ================================================================== */ |
594 | 608 |
595 void FuncDeclaration::toObjFile() | 609 void FuncDeclaration::toObjFile() |
596 { | 610 { |
597 if (llvmValue != 0 && llvmDModule == gIR->dmodule) { | 611 if (llvmDModule == gIR->dmodule) { |
612 assert(llvmValue != 0); | |
598 return; | 613 return; |
599 } | 614 } |
600 | 615 |
601 // has already been pulled in by a reference to ( | 616 llvm::Function* func = LLVM_DtoDeclareFunction(this); |
617 | |
602 if (!gIR->queueClassMethods.empty() && gIR->queueClassMethods.back()) { | 618 if (!gIR->queueClassMethods.empty() && gIR->queueClassMethods.back()) { |
603 Logger::println("queueing %s", toChars()); | 619 Logger::println("queueing %s", toChars()); |
604 assert(!gIR->classmethods.empty()); | 620 assert(!gIR->classmethods.empty()); |
605 gIR->classmethods.back().push_back(this); | 621 gIR->classmethods.back().push_back(this); |
606 return; // will be generated later when the this parameter has a type | 622 return; // will be generated later when the this parameter has a type |
607 } | 623 } |
608 | 624 |
609 static int fdi = 0; | 625 if (llvmNeedsDefinition) |
610 Logger::print("FuncDeclaration::toObjFile(%d,%s): %s\n", fdi++, needThis()?"this":"static",toChars()); | 626 { |
611 LOG_SCOPE; | |
612 | |
613 if (llvmInternal == LLVMintrinsic && fbody) { | |
614 error("intrinsics cannot have function bodies"); | |
615 fatal(); | |
616 } | |
617 | 627 |
618 TypeFunction* f = (TypeFunction*)type; | 628 TypeFunction* f = (TypeFunction*)type; |
619 assert(f != 0); | 629 llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(f->llvmType); |
620 | |
621 // return value type | |
622 const llvm::Type* rettype; | |
623 const llvm::Type* actualRettype; | |
624 Type* rt = f->next; | |
625 bool retinptr = false; | |
626 bool usesthis = false; | |
627 | |
628 if (isMain()) { | |
629 rettype = llvm::Type::Int32Ty; | |
630 actualRettype = rettype; | |
631 gIR->emitMain = true; | |
632 } | |
633 else if (rt) { | |
634 if (rt->ty == Tstruct || rt->ty == Tdelegate || rt->ty == Tarray) { | |
635 rettype = llvm::PointerType::get(LLVM_DtoType(rt)); | |
636 actualRettype = llvm::Type::VoidTy; | |
637 f->llvmRetInPtr = retinptr = true; | |
638 } | |
639 else { | |
640 rettype = LLVM_DtoType(rt); | |
641 actualRettype = rettype; | |
642 } | |
643 } | |
644 else { | |
645 assert(0); | |
646 } | |
647 | |
648 // parameter types | |
649 std::vector<const llvm::Type*> paramvec; | |
650 | |
651 if (retinptr) { | |
652 Logger::print("returning through pointer parameter\n"); | |
653 paramvec.push_back(rettype); | |
654 } | |
655 | |
656 if (needThis()) { | |
657 if (AggregateDeclaration* ad = isMember()) { | |
658 Logger::print("isMember = this is: %s\n", ad->type->toChars()); | |
659 const llvm::Type* thisty = LLVM_DtoType(ad->type); | |
660 if (llvm::isa<llvm::StructType>(thisty)) | |
661 thisty = llvm::PointerType::get(thisty); | |
662 paramvec.push_back(thisty); | |
663 usesthis = true; | |
664 } | |
665 else | |
666 assert(0); | |
667 } | |
668 | |
669 size_t n = Argument::dim(f->parameters); | |
670 for (int i=0; i < n; ++i) { | |
671 Argument* arg = Argument::getNth(f->parameters, i); | |
672 // ensure scalar | |
673 Type* argT = arg->type; | |
674 assert(argT); | |
675 | |
676 if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) { | |
677 //assert(arg->vardecl); | |
678 //arg->vardecl->refparam = true; | |
679 } | |
680 else | |
681 arg->llvmCopy = true; | |
682 | |
683 const llvm::Type* at = LLVM_DtoType(argT); | |
684 if (llvm::isa<llvm::StructType>(at)) { | |
685 Logger::println("struct param"); | |
686 paramvec.push_back(llvm::PointerType::get(at)); | |
687 } | |
688 else if (llvm::isa<llvm::ArrayType>(at)) { | |
689 Logger::println("sarray param"); | |
690 assert(argT->ty == Tsarray); | |
691 //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0))); | |
692 paramvec.push_back(llvm::PointerType::get(at)); | |
693 } | |
694 else { | |
695 if (!arg->llvmCopy) { | |
696 Logger::println("ref param"); | |
697 at = llvm::PointerType::get(at); | |
698 } | |
699 else { | |
700 Logger::println("in param"); | |
701 } | |
702 paramvec.push_back(at); | |
703 } | |
704 } | |
705 | |
706 // construct function | |
707 bool isvararg = f->varargs; | |
708 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
709 | |
710 // mangled name | |
711 char* mangled_name = (llvmInternal == LLVMintrinsic) ? llvmInternal1 : mangle(); | |
712 llvm::Function* func = gIR->module->getFunction(mangled_name); | |
713 | |
714 // make the function | |
715 /*if (func != 0) { | |
716 llvmValue = func; | |
717 f->llvmType = functype; | |
718 return; // already pulled in from a forward declaration | |
719 } | |
720 else */ | |
721 if (func == 0) { | |
722 func = new llvm::Function(functype,LLVM_DtoLinkage(protection, storage_class),mangled_name,gIR->module); | |
723 } | |
724 | |
725 if (llvmInternal != LLVMintrinsic) | |
726 func->setCallingConv(LLVM_DtoCallingConv(f->linkage)); | |
727 | |
728 llvmValue = func; | |
729 f->llvmType = functype; | |
730 | |
731 if (isMain()) { | |
732 gIR->mainFunc = func; | |
733 } | |
734 | |
735 // name parameters | |
736 llvm::Function::arg_iterator iarg = func->arg_begin(); | |
737 int k = 0; | |
738 int nunnamed = 0; | |
739 if (retinptr) { | |
740 iarg->setName("retval"); | |
741 f->llvmRetArg = iarg; | |
742 ++iarg; | |
743 } | |
744 if (usesthis) { | |
745 iarg->setName("this"); | |
746 ++iarg; | |
747 } | |
748 for (; iarg != func->arg_end(); ++iarg) | |
749 { | |
750 Argument* arg = Argument::getNth(f->parameters, k++); | |
751 //arg->llvmValue = iarg; | |
752 //printf("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident); | |
753 if (arg->ident != 0) { | |
754 if (arg->vardecl) { | |
755 arg->vardecl->llvmValue = iarg; | |
756 } | |
757 iarg->setName(arg->ident->toChars()); | |
758 } | |
759 else { | |
760 ++nunnamed; | |
761 } | |
762 } | |
763 | 630 |
764 // only members of the current module maybe be defined | 631 // only members of the current module maybe be defined |
765 if (getModule() == gIR->dmodule) | 632 if (getModule() == gIR->dmodule) |
766 { | 633 { |
767 bool allow_fbody = true; | 634 bool allow_fbody = true; |
794 } | 661 } |
795 | 662 |
796 // function definition | 663 // function definition |
797 if (allow_fbody && fbody != 0) | 664 if (allow_fbody && fbody != 0) |
798 { | 665 { |
799 assert(nunnamed == 0); | 666 if (isMain()) |
667 gIR->emitMain = true; | |
668 | |
800 gIR->funcs.push(func); | 669 gIR->funcs.push(func); |
801 gIR->functypes.push(f); | 670 gIR->functypes.push(f); |
802 | 671 |
803 IRScope irs; | 672 IRScope irs; |
804 irs.begin = new llvm::BasicBlock("entry",func); | 673 irs.begin = new llvm::BasicBlock("entry",func); |
830 | 699 |
831 gIR->functypes.pop(); | 700 gIR->functypes.pop(); |
832 gIR->funcs.pop(); | 701 gIR->funcs.pop(); |
833 | 702 |
834 // get rid of the endentry block, it's never used | 703 // get rid of the endentry block, it's never used |
704 assert(!func->getBasicBlockList().empty()); | |
835 func->getBasicBlockList().pop_back(); | 705 func->getBasicBlockList().pop_back(); |
836 | 706 |
837 // if the last block is empty now, it must be unreachable or it's a bug somewhere else | 707 // if the last block is empty now, it must be unreachable or it's a bug somewhere else |
708 // would be nice to figure out how to assert that this is correct | |
838 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); | 709 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); |
839 if (lastbb->empty()) { | 710 if (lastbb->empty()) { |
711 // possibly assert(lastbb->getNumPredecessors() == 0); ??? try it out sometime ... | |
840 new llvm::UnreachableInst(lastbb); | 712 new llvm::UnreachableInst(lastbb); |
841 } | 713 } |
842 } | 714 } |
843 } | 715 } |
844 else | 716 |
845 { | |
846 Logger::println("only declaration"); | |
847 } | 717 } |
848 | 718 |
849 llvmDModule = gIR->dmodule; | 719 llvmDModule = gIR->dmodule; |
850 | 720 |
851 Logger::println("FuncDeclaration done\n"); | 721 Logger::println("FuncDeclaration done\n"); |