Mercurial > projects > ldc
view gen/toobj.cpp @ 117:56a21f3e5d3e trunk
[svn r121] Finished ModuleInfo implementation.
Static ctors/dtors now work according to spec.
Changed class vtable types slightly in some cases. Overridden functions now always take the the type of the first class declaring the method as this parameter. This helps when using headers (w. implementation somewhere else)
author | lindquist |
---|---|
date | Mon, 26 Nov 2007 04:49:23 +0100 |
parents | fd7ad91fd713 |
children | 9c79b61fb638 |
line wrap: on
line source
// Copyright (c) 1999-2004 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include <cstddef> #include <iostream> #include <fstream> #include "gen/llvm.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachineRegistry.h" #include "mars.h" #include "module.h" #include "mtype.h" #include "declaration.h" #include "statement.h" #include "enum.h" #include "aggregate.h" #include "init.h" #include "attrib.h" #include "id.h" #include "import.h" #include "template.h" #include "scope.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/arrays.h" #include "gen/structs.h" #include "gen/classes.h" #include "gen/functions.h" #include "gen/todebug.h" #include "gen/runtime.h" ////////////////////////////////////////////////////////////////////////////////////////// void Module::genobjfile() { Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n'; LOG_SCOPE; // start by deleting the old object file deleteObjFile(); // create a new ir state IRState ir; gIR = &ir; ir.dmodule = this; // name the module std::string mname(toChars()); if (md != 0) mname = md->toChars(); ir.module = new llvm::Module(mname); // set target stuff std::string target_triple(global.params.tt_arch); target_triple.append(global.params.tt_os); ir.module->setTargetTriple(target_triple); ir.module->setDataLayout(global.params.data_layout); // heavily inspired by tools/llc/llc.cpp:200-230 const llvm::TargetMachineRegistry::Entry* targetEntry; std::string targetError; targetEntry = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, targetError); assert(targetEntry && "Failed to find a static target for module"); std::auto_ptr<llvm::TargetMachine> targetPtr(targetEntry->CtorFn(*ir.module, "")); // TODO: replace "" with features assert(targetPtr.get() && "Could not allocate target machine!"); llvm::TargetMachine &targetMachine = *targetPtr.get(); gTargetData = targetMachine.getTargetData(); // debug info if (global.params.symdebug) { RegisterDwarfSymbols(ir.module); ir.dmodule->llvmCompileUnit = DtoDwarfCompileUnit(this,true); } // start out by providing opaque for the built-in class types if (!ClassDeclaration::object->type->llvmType) ClassDeclaration::object->type->llvmType = new llvm::PATypeHolder(llvm::OpaqueType::get()); if (!Type::typeinfo->type->llvmType) Type::typeinfo->type->llvmType = new llvm::PATypeHolder(llvm::OpaqueType::get()); if (!ClassDeclaration::classinfo->type->llvmType) ClassDeclaration::classinfo->type->llvmType = new llvm::PATypeHolder(llvm::OpaqueType::get()); /*if (!Type::typeinfoclass->type->llvmType) Type::typeinfoclass->type->llvmType = new llvm::PATypeHolder(llvm::OpaqueType::get());*/ // process module members for (int k=0; k < members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(members->data[k]); assert(dsym); dsym->toObjFile(); } // main driver loop DtoEmptyAllLists(); // generate ModuleInfo genmoduleinfo(); // do this again as moduleinfo might have pulled something in! DtoEmptyAllLists(); gTargetData = 0; // emit the llvm main function if necessary if (ir.emitMain) { DtoMain(); } // verify the llvm if (!global.params.novalidate) { std::string verifyErr; Logger::println("Verifying module..."); LOG_SCOPE; if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) { error("%s", verifyErr.c_str()); fatal(); } else { Logger::println("Verification passed!"); } } // run passes // TODO // write bytecode { Logger::println("Writing LLVM bitcode\n"); std::ofstream bos(bcfile->name->toChars(), std::ios::binary); llvm::WriteBitcodeToFile(ir.module, bos); } // disassemble ? if (global.params.disassemble) { Logger::println("Writing LLVM asm to: %s\n", llfile->name->toChars()); std::ofstream aos(llfile->name->toChars()); ir.module->print(aos); } delete ir.module; gIR = NULL; } /* ================================================================== */ // build module ctor static llvm::Function* build_module_ctor() { if (gIR->ctors.empty()) return NULL; size_t n = gIR->ctors.size(); if (n == 1) return llvm::cast<llvm::Function>(gIR->ctors[0]->llvmValue); std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__ctorZ"); std::vector<const llvm::Type*> argsTy; const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy,argsTy,false); llvm::Function* fn = new llvm::Function(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); fn->setCallingConv(llvm::CallingConv::Fast); llvm::BasicBlock* bb = new llvm::BasicBlock("entry", fn); LLVMBuilder builder(bb); for (size_t i=0; i<n; i++) { llvm::Function* f = llvm::cast<llvm::Function>(gIR->ctors[i]->llvmValue); llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(llvm::CallingConv::Fast); } builder.CreateRetVoid(); return fn; } // build module dtor static llvm::Function* build_module_dtor() { if (gIR->dtors.empty()) return NULL; size_t n = gIR->dtors.size(); if (n == 1) return llvm::cast<llvm::Function>(gIR->dtors[0]->llvmValue); std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__dtorZ"); std::vector<const llvm::Type*> argsTy; const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy,argsTy,false); llvm::Function* fn = new llvm::Function(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); fn->setCallingConv(llvm::CallingConv::Fast); llvm::BasicBlock* bb = new llvm::BasicBlock("entry", fn); LLVMBuilder builder(bb); for (size_t i=0; i<n; i++) { llvm::Function* f = llvm::cast<llvm::Function>(gIR->dtors[i]->llvmValue); llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(llvm::CallingConv::Fast); } builder.CreateRetVoid(); return fn; } // Put out instance of ModuleInfo for this Module void Module::genmoduleinfo() { // The layout is: // { // void **vptr; // monitor_t monitor; // char[] name; // class name // ModuleInfo importedModules[]; // ClassInfo localClasses[]; // uint flags; // initialization state // void *ctor; // void *dtor; // void *unitTest; // } // resolve ModuleInfo assert(moduleinfo); DtoForceConstInitDsymbol(moduleinfo); // moduleinfo llvm struct type const llvm::StructType* moduleinfoTy = isaStruct(moduleinfo->type->llvmType->get()); // classinfo llvm struct type const llvm::StructType* classinfoTy = isaStruct(ClassDeclaration::classinfo->type->llvmType->get()); // initializer vector std::vector<llvm::Constant*> initVec; llvm::Constant* c = 0; // vtable c = moduleinfo->llvmVtbl; initVec.push_back(c); // monitor c = llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)); initVec.push_back(c); // name char *name = toPrettyChars(); c = DtoConstString(name); initVec.push_back(c); // importedModules[] int aimports_dim = aimports.dim; std::vector<llvm::Constant*> importInits; for (size_t i = 0; i < aimports.dim; i++) { Module *m = (Module *)aimports.data[i]; if (!m->needModuleInfo()) aimports_dim--; else { // declare // create name std::string m_name("_D"); m_name.append(m->mangle()); m_name.append("8__ModuleZ"); llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name, gIR->module); importInits.push_back(m_gvar); } } // has import array? if (!importInits.empty()) { const llvm::ArrayType* importArrTy = llvm::ArrayType::get(llvm::PointerType::get(moduleinfoTy), importInits.size()); c = llvm::ConstantArray::get(importArrTy, importInits); std::string m_name("_D"); m_name.append(mangle()); m_name.append("9__importsZ"); llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(importArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module); c = llvm::ConstantExpr::getBitCast(m_gvar, llvm::PointerType::get(importArrTy->getElementType())); c = DtoConstSlice(DtoConstSize_t(importInits.size()), c); } else c = moduleinfo->llvmInitZ->getOperand(3); initVec.push_back(c); // localClasses[] ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member; member = (Dsymbol *)members->data[i]; //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // fill inits std::vector<llvm::Constant*> classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration* cd = (ClassDeclaration*)aclasses.data[i]; assert(cd->llvmClass); classInits.push_back(cd->llvmClass); } // has class array? if (!classInits.empty()) { const llvm::ArrayType* classArrTy = llvm::ArrayType::get(llvm::PointerType::get(classinfoTy), classInits.size()); c = llvm::ConstantArray::get(classArrTy, classInits); std::string m_name("_D"); m_name.append(mangle()); m_name.append("9__classesZ"); llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(classArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module); c = llvm::ConstantExpr::getBitCast(m_gvar, llvm::PointerType::get(classArrTy->getElementType())); c = DtoConstSlice(DtoConstSize_t(classInits.size()), c); } else c = moduleinfo->llvmInitZ->getOperand(4); initVec.push_back(c); // flags if (needmoduleinfo) c = DtoConstUint(0); // flags (4 means MIstandalone) else c = DtoConstUint(4); // flags (4 means MIstandalone) initVec.push_back(c); // ctor llvm::Function* fctor = build_module_ctor(); c = fctor ? fctor : moduleinfo->llvmInitZ->getOperand(6); initVec.push_back(c); // dtor llvm::Function* fdtor = build_module_dtor(); c = fdtor ? fdtor : moduleinfo->llvmInitZ->getOperand(7); initVec.push_back(c); // unitTest c = moduleinfo->llvmInitZ->getOperand(8); initVec.push_back(c); // create initializer llvm::Constant* constMI = llvm::ConstantStruct::get(moduleinfoTy, initVec); // create name std::string MIname("_D"); MIname.append(mangle()); MIname.append("8__ModuleZ"); // declare // flags will be modified at runtime so can't make it constant llvm::GlobalVariable* gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, constMI, MIname, gIR->module); // declare the appending array const llvm::ArrayType* appendArrTy = llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty), 1); std::vector<llvm::Constant*> appendInits; appendInits.push_back(llvm::ConstantExpr::getBitCast(gvar, llvm::PointerType::get(llvm::Type::Int8Ty))); llvm::Constant* appendInit = llvm::ConstantArray::get(appendArrTy, appendInits); std::string appendName("_d_moduleinfo_array"); llvm::GlobalVariable* appendVar = new llvm::GlobalVariable(appendArrTy, true, llvm::GlobalValue::AppendingLinkage, appendInit, appendName, gIR->module); } /* ================================================================== */ void Dsymbol::toObjFile() { Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars()); } /* ================================================================== */ void Declaration::toObjFile() { Logger::println("Ignoring Declaration::toObjFile for %s", toChars()); } /* ================================================================== */ void InterfaceDeclaration::toObjFile() { Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars()); } /* ================================================================== */ void StructDeclaration::toObjFile() { gIR->resolveList.push_back(this); } /* ================================================================== */ static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) { // start at the bottom of the inheritance chain if (cd->baseClass != 0) { unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx); if (o != (unsigned)-1) return o; } // check this class unsigned i; for (i=0; i<cd->fields.dim; ++i) { VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; if (os == vd->offset) return i+idx; } idx += i; return (unsigned)-1; } void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result) { unsigned idx = 0; unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); // vtable is 0, monitor is 1 r += 2; // interface offset further r += vtblInterfaces->dim; // the final index was not pushed result.push_back(r); } /* ================================================================== */ void ClassDeclaration::toObjFile() { gIR->resolveList.push_back(this); } /****************************************** * Get offset of base class's vtbl[] initializer from start of csym. * Returns ~0 if not this csym. */ unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc) { return ~0; } /* ================================================================== */ void VarDeclaration::toObjFile() { Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (aliassym) { Logger::println("alias sym"); toAlias()->toObjFile(); return; } // global variable or magic if (isDataseg()) { if (llvmResolved) return; llvmResolved = true; llvmDeclared = true; llvmIRGlobal = new IRGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); bool _isconst = isConst(); if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) _isconst = false; llvm::GlobalValue::LinkageTypes _linkage; bool istempl = false; bool static_local = false; if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) { _linkage = llvm::GlobalValue::WeakLinkage; istempl = true; } else if (parent && parent->isFuncDeclaration()) { _linkage = llvm::GlobalValue::InternalLinkage; static_local = true; } else _linkage = DtoLinkage(protection, storage_class); const llvm::Type* _type = llvmIRGlobal->type.get(); Logger::println("Creating global variable"); std::string _name(mangle()); llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module); llvmValue = gvar; if (static_local) DtoConstInitGlobal(this); else gIR->constInitList.push_back(this); //if (storage_class & STCprivate) // gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility); } // inside aggregate declaration. declare a field. else { Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset); const llvm::Type* _type = DtoType(type); // add the field in the IRStruct gIR->topstruct()->offsets.insert(std::make_pair(offset, IRStruct::Offset(this, _type))); } Logger::println("VarDeclaration::toObjFile is done"); } /* ================================================================== */ void TypedefDeclaration::toObjFile() { static int tdi = 0; Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); LOG_SCOPE; // generate typeinfo type->getTypeInfo(NULL); } /* ================================================================== */ void EnumDeclaration::toObjFile() { Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars()); } /* ================================================================== */ void FuncDeclaration::toObjFile() { gIR->resolveList.push_back(this); }