Mercurial > projects > ldc
view gen/toobj.cpp @ 116:fd7ad91fd713 trunk
[svn r120] ModuleInfo implementation is now almost complete.
Fixed some nasty static array-initializer bugs.
Fixed bug in DtoArrayLen and DtoArrayPtr for full slices of static arrays.
author | lindquist |
---|---|
date | Sun, 25 Nov 2007 18:55:52 +0100 |
parents | 5ba6d286c941 |
children | 56a21f3e5d3e |
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..."); 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); } /* ================================================================== */ 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); }