//===-- module.cpp --------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "aggregate.h" #include "attrib.h" #include "declaration.h" #include "enum.h" #include "id.h" #include "import.h" #include "init.h" #include "mars.h" #include "module.h" #include "mtype.h" #include "scope.h" #include "statement.h" #include "target.h" #include "template.h" #include "gen/abi.h" #include "gen/arrays.h" #include "gen/classes.h" #include "gen/functions.h" #include "gen/irstate.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/objcgen.h" #include "gen/optimizer.h" #include "gen/programs.h" #include "gen/rttibuilder.h" #include "gen/runtime.h" #include "gen/structs.h" #include "gen/tollvm.h" #include "ir/irdsymbol.h" #include "ir/irfunction.h" #include "ir/irmodule.h" #include "ir/irtype.h" #include "ir/irvar.h" #include "llvm/Support/CommandLine.h" #include "llvm/IR/Verifier.h" #include "llvm/LinkAllPasses.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/IR/Module.h" #include "llvm/IR/DataLayout.h" #if _AIX || __sun #include #endif static llvm::cl::opt preservePaths("op", llvm::cl::desc("Do not strip paths from source file"), llvm::cl::ZeroOrMore); static llvm::cl::opt fqnNames("oq", llvm::cl::desc("Write object files with fully qualified names"), llvm::cl::ZeroOrMore); static void check_and_add_output_file(Module *NewMod, const std::string &str) { static std::map files; auto i = files.find(str); if (i != files.end()) { Module *ThisMod = i->second; error(Loc(), "Output file '%s' for module '%s' collides with previous " "module '%s'. See the -oq option", str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); fatal(); } files.insert(std::make_pair(str, NewMod)); } void buildTargetFiles(Module *m, bool singleObj, bool library) { if (m->objfile && (!m->doDocComment || m->docfile) && (!m->doHdrGen || m->hdrfile)) { return; } if (!m->objfile) { const char *objname = library ? nullptr : global.params.objname; if (global.params.output_o) { m->objfile = m->buildFilePath(objname, global.params.objdir, global.params.targetTriple->isOSWindows() ? global.obj_ext_alt : global.obj_ext, library, fqnNames); } else if (global.params.output_bc) { m->objfile = m->buildFilePath(objname, global.params.objdir, global.bc_ext, library, fqnNames); } else if (global.params.output_ll) { m->objfile = m->buildFilePath(objname, global.params.objdir, global.ll_ext, library, fqnNames); } else if (global.params.output_s) { m->objfile = m->buildFilePath(objname, global.params.objdir, global.s_ext, library, fqnNames); } } if (m->doDocComment && !m->docfile) { m->docfile = m->buildFilePath(global.params.docname, global.params.docdir, global.doc_ext, library, fqnNames); } if (m->doHdrGen && !m->hdrfile) { m->hdrfile = m->buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext, library, fqnNames); } // safety check: never allow obj, doc or hdr file to have the source file's // name if (Port::stricmp(FileName::name(m->objfile->name->str), FileName::name(m->arg)) == 0) { m->error("Output object files with the same name as the source file are " "forbidden"); fatal(); } if (m->docfile && Port::stricmp(FileName::name(m->docfile->name->str), FileName::name(m->arg)) == 0) { m->error( "Output doc files with the same name as the source file are forbidden"); fatal(); } if (m->hdrfile && Port::stricmp(FileName::name(m->hdrfile->name->str), FileName::name(m->arg)) == 0) { m->error("Output header files with the same name as the source file are " "forbidden"); fatal(); } // LDC // another safety check to make sure we don't overwrite previous output files if (!singleObj && global.params.obj) { check_and_add_output_file(m, m->objfile->name->str); } if (m->docfile) { check_and_add_output_file(m, m->docfile->name->str); } // FIXME: DMD overwrites header files. This should be done only in a DMD mode. // if (hdrfile) // check_and_add_output_file(m, hdrfile->name->str); } static llvm::Function *build_module_function( const std::string &name, const std::list &funcs, const std::list &gates = std::list()) { if (gates.empty()) { if (funcs.empty()) { return nullptr; } if (funcs.size() == 1) { return getIrFunc(funcs.front())->func; } } // build ctor type LLFunctionType *fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector(), false); std::string const symbolName = gABI->mangleForLLVM(name, LINKd); assert(gIR->module.getFunction(symbolName) == NULL); llvm::Function *fn = llvm::Function::Create( fnTy, llvm::GlobalValue::InternalLinkage, symbolName, &gIR->module); fn->setCallingConv(gABI->callingConv(fn->getFunctionType(), LINKd)); llvm::BasicBlock *bb = llvm::BasicBlock::Create(gIR->context(), "", fn); IRBuilder<> builder(bb); // debug info ldc::DISubprogram dis = gIR->DBuilder.EmitModuleCTor(fn, name.c_str()); if (global.params.symdebug) { // Need _some_ debug info to avoid inliner bug, see GitHub issue #998. builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, dis)); } // Call ctor's for (auto func : funcs) { llvm::Function *f = getIrFunc(func)->func; #if LDC_LLVM_VER >= 307 llvm::CallInst *call = builder.CreateCall(f, {}); #else llvm::CallInst *call = builder.CreateCall(f, ""); #endif call->setCallingConv(gABI->callingConv(call-> #if LDC_LLVM_VER < 307 getCalledFunction() -> #endif getFunctionType(), LINKd)); } // Increment vgate's for (auto gate : gates) { assert(getIrGlobal(gate)); llvm::Value *val = getIrGlobal(gate)->value; llvm::Value *rval = builder.CreateLoad(val, "vgate"); llvm::Value *res = builder.CreateAdd(rval, DtoConstUint(1), "vgate"); builder.CreateStore(res, val); } builder.CreateRetVoid(); return fn; } // build module ctor static llvm::Function *build_module_ctor(Module *m) { std::string name("_D"); name.append(mangle(m)); name.append("6__ctorZ"); IrModule *irm = getIrModule(m); return build_module_function(name, irm->ctors, irm->gates); } // build module dtor static llvm::Function *build_module_dtor(Module *m) { std::string name("_D"); name.append(mangle(m)); name.append("6__dtorZ"); return build_module_function(name, getIrModule(m)->dtors); } // build module unittest static llvm::Function *build_module_unittest(Module *m) { std::string name("_D"); name.append(mangle(m)); name.append("10__unittestZ"); return build_module_function(name, getIrModule(m)->unitTests); } // build module shared ctor static llvm::Function *build_module_shared_ctor(Module *m) { std::string name("_D"); name.append(mangle(m)); name.append("13__shared_ctorZ"); IrModule *irm = getIrModule(m); return build_module_function(name, irm->sharedCtors, irm->sharedGates); } // build module shared dtor static llvm::Function *build_module_shared_dtor(Module *m) { std::string name("_D"); name.append(mangle(m)); name.append("13__shared_dtorZ"); return build_module_function(name, getIrModule(m)->sharedDtors); } // build ModuleReference and register function, to register the module info in // the global linked list static LLFunction *build_module_reference_and_ctor(const char *moduleMangle, LLConstant *moduleinfo) { // build ctor type LLFunctionType *fty = LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector(), false); // build ctor name std::string fname = "_D"; fname += moduleMangle; fname += "16__moduleinfoCtorZ"; // build a function that registers the moduleinfo in the global moduleinfo // linked list LLFunction *ctor = LLFunction::Create(fty, LLGlobalValue::InternalLinkage, fname, &gIR->module); // provide the default initializer LLStructType *modulerefTy = DtoModuleReferenceType(); LLConstant *mrefvalues[] = { LLConstant::getNullValue(modulerefTy->getContainedType(0)), llvm::ConstantExpr::getBitCast(moduleinfo, modulerefTy->getContainedType(1))}; LLConstant *thismrefinit = LLConstantStruct::get( modulerefTy, llvm::ArrayRef(mrefvalues)); // create the ModuleReference node for this module std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; Loc loc; LLGlobalVariable *thismref = getOrCreateGlobal( loc, gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname); // make sure _Dmodule_ref is declared LLConstant *mref = gIR->module.getNamedGlobal("_Dmodule_ref"); LLType *modulerefPtrTy = getPtrToType(modulerefTy); if (!mref) { mref = new LLGlobalVariable(gIR->module, modulerefPtrTy, false, LLGlobalValue::ExternalLinkage, nullptr, "_Dmodule_ref"); } mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy)); // make the function insert this moduleinfo as the beginning of the // _Dmodule_ref linked list llvm::BasicBlock *bb = llvm::BasicBlock::Create(gIR->context(), "moduleinfoCtorEntry", ctor); IRBuilder<> builder(bb); // debug info gIR->DBuilder.EmitModuleCTor(ctor, fname.c_str()); // get current beginning LLValue *curbeg = builder.CreateLoad(mref, "current"); // put current beginning as the next of this one LLValue *gep = builder.CreateStructGEP( #if LDC_LLVM_VER >= 307 modulerefTy, #endif thismref, 0, "next"); builder.CreateStore(curbeg, gep); // replace beginning builder.CreateStore(thismref, mref); // return builder.CreateRetVoid(); return ctor; } /// Builds the body for the ldc.dso_ctor and ldc.dso_dtor functions. /// /// Pseudocode: /// if (dsoInitialized == executeWhenInitialized) { /// dsoInitialized = !executeWhenInitialized; /// auto record = {1, dsoSlot, minfoBeg, minfoEnd, minfoUsedPointer}; /// _d_dso_registry(cast(CompilerDSOData*)&record); /// } static void build_dso_ctor_dtor_body( llvm::Function *targetFunc, llvm::Value *dsoInitialized, llvm::Value *dsoSlot, llvm::Value *minfoBeg, llvm::Value *minfoEnd, llvm::Value *minfoUsedPointer, bool executeWhenInitialized) { llvm::Function *const dsoRegistry = getRuntimeFunction(Loc(), gIR->module, "_d_dso_registry"); llvm::Type *const recordPtrTy = dsoRegistry->getFunctionType()->getContainedType(1); llvm::BasicBlock *const entryBB = llvm::BasicBlock::Create(gIR->context(), "", targetFunc); llvm::BasicBlock *const initBB = llvm::BasicBlock::Create(gIR->context(), "init", targetFunc); llvm::BasicBlock *const endBB = llvm::BasicBlock::Create(gIR->context(), "end", targetFunc); { IRBuilder<> b(entryBB); llvm::Value *condEval = b.CreateICmp(executeWhenInitialized ? llvm::ICmpInst::ICMP_NE : llvm::ICmpInst::ICMP_EQ, b.CreateLoad(dsoInitialized), b.getInt8(0)); b.CreateCondBr(condEval, initBB, endBB); } { IRBuilder<> b(initBB); b.CreateStore(b.getInt8(!executeWhenInitialized), dsoInitialized); llvm::Constant *version = DtoConstSize_t(1); llvm::Type *memberTypes[] = {version->getType(), dsoSlot->getType(), minfoBeg->getType(), minfoEnd->getType(), minfoUsedPointer->getType()}; llvm::StructType *stype = llvm::StructType::get(gIR->context(), memberTypes, false); llvm::Value *record = b.CreateAlloca(stype); #if LDC_LLVM_VER >= 307 b.CreateStore(version, b.CreateStructGEP(stype, record, 0)); // version b.CreateStore(dsoSlot, b.CreateStructGEP(stype, record, 1)); // slot b.CreateStore(minfoBeg, b.CreateStructGEP(stype, record, 2)); b.CreateStore(minfoEnd, b.CreateStructGEP(stype, record, 3)); b.CreateStore(minfoUsedPointer, b.CreateStructGEP(stype, record, 4)); #else b.CreateStore(version, b.CreateStructGEP(record, 0)); // version b.CreateStore(dsoSlot, b.CreateStructGEP(record, 1)); // slot b.CreateStore(minfoBeg, b.CreateStructGEP(record, 2)); b.CreateStore(minfoEnd, b.CreateStructGEP(record, 3)); b.CreateStore(minfoUsedPointer, b.CreateStructGEP(record, 4)); #endif b.CreateCall(dsoRegistry, b.CreateBitCast(record, recordPtrTy)); b.CreateBr(endBB); } { IRBuilder<> b(endBB); b.CreateRetVoid(); } } static void build_module_ref(std::string moduleMangle, llvm::Constant *thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; auto thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); } static void build_dso_registry_calls(std::string moduleMangle, llvm::Constant *thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); // Order is important here: We must create the symbols in the // bracketing sections right before/after the ModuleInfo reference // so that they end up in the correct order in the object file. auto minfoBeg = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_beg"); minfoBeg->setSection(".minfo_beg"); minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; auto thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); auto minfoEnd = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_end"); minfoEnd->setSection(".minfo_end"); minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility); // Build the ctor to invoke _d_dso_registry. // This is the DSO slot for use by the druntime implementation. auto dsoSlot = new llvm::GlobalVariable(gIR->module, getVoidPtrType(), false, llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(getVoidPtrType()), "ldc.dso_slot"); dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility); // Okay, so the theory is easy: We want to have one global constructor and // destructor per object (i.e. executable/shared library) that calls // _d_dso_registry with the respective DSO record. However, there are a // couple of issues that make this harder than necessary: // // 1) The natural way to implement the "one-per-image" part would be to // emit a weak reference to a weak function into a .ctors. // section (llvm.global_ctors doesn't support the necessary // functionality, so we'd use our knowledge of the linker script to work // around that). But as of LLVM 3.4, emitting a symbol both as weak and // into a custom section is not supported by the MC layer. Thus, we have // to use a normal ctor/dtor and manually ensure that we only perform // the call once. This is done by introducing ldc.dso_initialized. // // 2) To make sure the .minfo section isn't removed by the linker when // using --gc-sections, we need to keep a reference to it around in // _every_ object file (as --gc-sections works per object file). The // natural place for this is the ctor, where we just load a reference // on the stack after the DSO record (to ensure LLVM doesn't optimize // it out). However, this way, we need to have at least one ctor // instance per object file be pulled into the final executable. We // do this here by making the module mangle string part of its name, // even thoguht this is slightly wasteful on -singleobj builds. // // It might be a better idea to simply use a custom linker script (using // INSERT AFTER… so as to still keep the default one) to avoid all these // problems. This would mean that it is no longer safe to link D objects // directly using e.g. "g++ dcode.o cppcode.o", though. auto dsoInitialized = new llvm::GlobalVariable( gIR->module, llvm::Type::getInt8Ty(gIR->context()), false, llvm::GlobalValue::LinkOnceODRLinkage, llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0), "ldc.dso_initialized"); dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility); // There is no reason for this cast to void*, other than that removing it // seems to trigger a bug in the llvm::Linker (at least on LLVM 3.4) // causing it to not merge the %object.ModuleInfo types properly. This // manifests itself in a type mismatch assertion being triggered on the // minfoUsedPointer store in the ctor as soon as the optimizer runs. llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType()); std::string ctorName = "ldc.dso_ctor."; ctorName += moduleMangle; llvm::Function *dsoCtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, ctorName, &gIR->module); dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoCtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, false); llvm::appendToGlobalCtors(gIR->module, dsoCtor, 65535); std::string dtorName = "ldc.dso_dtor."; dtorName += moduleMangle; llvm::Function *dsoDtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, dtorName, &gIR->module); dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoDtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, true); llvm::appendToGlobalDtors(gIR->module, dsoDtor, 65535); } static void build_llvm_used_array(IRState *p) { if (p->usedArray.empty()) { return; } std::vector usedVoidPtrs; usedVoidPtrs.reserve(p->usedArray.size()); for (auto constant : p->usedArray) { usedVoidPtrs.push_back(DtoBitCast(constant, getVoidPtrType())); } llvm::ArrayType *arrayType = llvm::ArrayType::get(getVoidPtrType(), usedVoidPtrs.size()); auto llvmUsed = new llvm::GlobalVariable( p->module, arrayType, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(arrayType, usedVoidPtrs), "llvm.used"); llvmUsed->setSection("llvm.metadata"); } // Add module-private variables and functions for coverage analysis. static void addCoverageAnalysis(Module *m) { IF_LOG { Logger::println("Adding coverage analysis for module %s (%d lines)", m->srcfile->toChars(), m->numlines); Logger::indent(); } // size_t[# source lines / # bits in sizeTy] _d_cover_valid LLValue *d_cover_valid_slice = nullptr; { unsigned Dsizet_bits = gDataLayout->getTypeSizeInBits(DtoSize_t()); size_t array_size = (m->numlines + (Dsizet_bits - 1)) / Dsizet_bits; // ceil // Work around a bug in the interface of druntime's _d_cover_register2 // https://issues.dlang.org/show_bug.cgi?id=14417 // For safety, make the array large enough such that the slice passed to // _d_cover_register2 is completely valid. array_size = m->numlines; IF_LOG Logger::println( "Build private variable: size_t[%llu] _d_cover_valid", static_cast(array_size)); llvm::ArrayType *type = llvm::ArrayType::get(DtoSize_t(), array_size); llvm::ConstantAggregateZero *zeroinitializer = llvm::ConstantAggregateZero::get(type); m->d_cover_valid = new llvm::GlobalVariable( gIR->module, type, true, LLGlobalValue::InternalLinkage, zeroinitializer, "_d_cover_valid"); LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)}; d_cover_valid_slice = DtoConstSlice(DtoConstSize_t(type->getArrayNumElements()), llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 type, #endif m->d_cover_valid, idxs, true)); // Assert that initializer array elements have enough bits assert(sizeof(m->d_cover_valid_init[0]) * 8 >= gDataLayout->getTypeSizeInBits(DtoSize_t())); m->d_cover_valid_init.setDim(array_size); m->d_cover_valid_init.zero(); } // uint[# source lines] _d_cover_data LLValue *d_cover_data_slice = nullptr; { IF_LOG Logger::println("Build private variable: uint[%d] _d_cover_data", m->numlines); LLArrayType *type = LLArrayType::get(LLType::getInt32Ty(gIR->context()), m->numlines); llvm::ConstantAggregateZero *zeroinitializer = llvm::ConstantAggregateZero::get(type); m->d_cover_data = new llvm::GlobalVariable( gIR->module, type, false, LLGlobalValue::InternalLinkage, zeroinitializer, "_d_cover_data"); LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)}; d_cover_data_slice = DtoConstSlice(DtoConstSize_t(type->getArrayNumElements()), llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 type, #endif m->d_cover_data, idxs, true)); } // Create "static constructor" that calls _d_cover_register2(string filename, // size_t[] valid, uint[] data, ubyte minPercent) // Build ctor name LLFunction *ctor = nullptr; std::string ctorname = "_D"; ctorname += mangle(m); ctorname += "12_coverageanalysisCtor1FZv"; { IF_LOG Logger::println("Build Coverage Analysis constructor: %s", ctorname.c_str()); LLFunctionType *ctorTy = LLFunctionType::get( LLType::getVoidTy(gIR->context()), std::vector(), false); ctor = LLFunction::Create(ctorTy, LLGlobalValue::InternalLinkage, ctorname, &gIR->module); ctor->setCallingConv(gABI->callingConv(ctor->getFunctionType(), LINKd)); // Set function attributes. See functions.cpp:DtoDefineFunction() if (global.params.targetTriple->getArch() == llvm::Triple::x86_64) { ctor->addFnAttr(LLAttribute::UWTable); } llvm::BasicBlock *bb = llvm::BasicBlock::Create(gIR->context(), "", ctor); IRBuilder<> builder(bb); // Set up call to _d_cover_register2 llvm::Function *fn = getRuntimeFunction(Loc(), gIR->module, "_d_cover_register2"); LLValue *args[] = {DtoConstString(m->srcfile->name->toChars()), d_cover_valid_slice, d_cover_data_slice, DtoConstUbyte(global.params.covPercent)}; // Check if argument types are correct for (unsigned i = 0; i < 4; ++i) { assert(args[i]->getType() == fn->getFunctionType()->getParamType(i)); } builder.CreateCall(fn, args); builder.CreateRetVoid(); } // Add the ctor to the module's static ctors list. TODO: This is quite the // hack. { IF_LOG Logger::println("Add %s to module's shared static constructor list", ctorname.c_str()); FuncDeclaration *fd = FuncDeclaration::genCfunc(nullptr, Type::tvoid, ctorname.c_str()); fd->linkage = LINKd; IrFunction *irfunc = getIrFunc(fd, true); irfunc->func = ctor; getIrModule(m)->sharedCtors.push_back(fd); } IF_LOG Logger::undent(); } // Initialize _d_cover_valid for coverage analysis static void addCoverageAnalysisInitializer(Module *m) { IF_LOG Logger::println("Adding coverage analysis _d_cover_valid initializer"); size_t array_size = m->d_cover_valid_init.size(); llvm::ArrayType *type = llvm::ArrayType::get(DtoSize_t(), array_size); std::vector arrayInits(array_size); for (size_t i = 0; i < array_size; i++) { arrayInits[i] = DtoConstSize_t(m->d_cover_valid_init[i]); } m->d_cover_valid->setInitializer(llvm::ConstantArray::get(type, arrayInits)); } static void genModuleInfo(Module *m, bool emitFullModuleInfo); void codegenModule(IRState *irs, Module *m, bool emitFullModuleInfo) { assert(!irs->dmodule && "irs->module not null, codegen already in progress?!"); irs->dmodule = m; assert(!gIR && "gIR not null, codegen already in progress?!"); gIR = irs; initRuntime(); // Skip pseudo-modules for coverage analysis std::string name = m->toChars(); if (global.params.cov && name != "__entrypoint" && name != "__main") { addCoverageAnalysis(m); } // process module members for (unsigned k = 0; k < m->members->dim; k++) { Dsymbol *dsym = (*m->members)[k]; assert(dsym); Declaration_codegen(dsym); } if (global.errors) { fatal(); } // Skip emission of all the additional module metadata if requested by the // user. if (!m->noModuleInfo) { // generate ModuleInfo genModuleInfo(m, emitFullModuleInfo); build_llvm_used_array(irs); } if (m->d_cover_valid) { addCoverageAnalysisInitializer(m); } gIR = nullptr; irs->dmodule = nullptr; } // Put out instance of ModuleInfo for this Module static void genModuleInfo(Module *m, bool emitFullModuleInfo) { // resolve ModuleInfo if (!Module::moduleinfo) { m->error("object.d is missing the ModuleInfo struct"); fatal(); } // check for patch else { // The base struct should consist only of _flags/_index. if (Module::moduleinfo->structsize != 4 + 4) { m->error("Unexpected size of struct object.ModuleInfo; " "druntime version does not match compiler (see -v)"); fatal(); } } // use the RTTIBuilder RTTIBuilder b(Module::moduleinfo); // some types llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); LLType *classinfoTy = Type::typeinfoclass->type->ctype->getLLType(); // importedModules[] std::vector importInits; LLConstant *importedModules = nullptr; llvm::ArrayType *importedModulesTy = nullptr; for (size_t i = 0; i < m->aimports.dim; i++) { Module *mod = static_cast(m->aimports.data[i]); if (!mod->needModuleInfo() || mod == m) { continue; } importInits.push_back( DtoBitCast(getIrModule(mod)->moduleInfoSymbol(), moduleInfoPtrTy)); } // has import array? if (!importInits.empty()) { importedModulesTy = llvm::ArrayType::get(moduleInfoPtrTy, importInits.size()); importedModules = LLConstantArray::get(importedModulesTy, importInits); } // localClasses[] LLConstant *localClasses = nullptr; llvm::ArrayType *localClassesTy = nullptr; ClassDeclarations aclasses; // printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < m->members->dim; i++) { (*m->members)[i]->addLocalClass(&aclasses); } // fill inits std::vector classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration *cd = aclasses[i]; DtoResolveClass(cd); if (cd->isInterfaceDeclaration()) { IF_LOG Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } else if (cd->sizeok != SIZEOKdone) { IF_LOG Logger::println( "skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); continue; } IF_LOG Logger::println("class: %s", cd->toPrettyChars()); LLConstant *c = DtoBitCast(getIrAggr(cd)->getClassInfoSymbol(), classinfoTy); classInits.push_back(c); } // has class array? if (!classInits.empty()) { localClassesTy = llvm::ArrayType::get(classinfoTy, classInits.size()); localClasses = LLConstantArray::get(localClassesTy, classInits); } // These must match the values in druntime/src/object_.d #define MIstandalone 4 #define MItlsctor 8 #define MItlsdtor 0x10 #define MIctor 0x20 #define MIdtor 0x40 #define MIxgetMembers 0x80 #define MIictor 0x100 #define MIunitTest 0x200 #define MIimportedModules 0x400 #define MIlocalClasses 0x800 #define MInew 0x80000000 // it's the "new" layout llvm::Function *fsharedctor = build_module_shared_ctor(m); llvm::Function *fshareddtor = build_module_shared_dtor(m); llvm::Function *funittest = build_module_unittest(m); llvm::Function *fctor = build_module_ctor(m); llvm::Function *fdtor = build_module_dtor(m); unsigned flags = MInew; if (fctor) { flags |= MItlsctor; } if (fdtor) { flags |= MItlsdtor; } if (fsharedctor) { flags |= MIctor; } if (fshareddtor) { flags |= MIdtor; } #if 0 if (fgetmembers) flags |= MIxgetMembers; if (fictor) flags |= MIictor; #endif if (funittest) { flags |= MIunitTest; } if (importedModules) { flags |= MIimportedModules; } if (localClasses) { flags |= MIlocalClasses; } if (!m->needmoduleinfo) { flags |= MIstandalone; } b.push_uint(flags); // flags b.push_uint(0); // index if (fctor) { b.push(fctor); } if (fdtor) { b.push(fdtor); } if (fsharedctor) { b.push(fsharedctor); } if (fshareddtor) { b.push(fshareddtor); } #if 0 if (fgetmembers) b.push(fgetmembers); if (fictor) b.push(fictor); #endif if (funittest) { b.push(funittest); } if (importedModules) { b.push_size(importInits.size()); b.push(importedModules); } if (localClasses) { b.push_size(classInits.size()); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = m->toPrettyChars(); const size_t len = strlen(name) + 1; llvm::IntegerType *it = llvm::IntegerType::getInt8Ty(gIR->context()); llvm::ArrayType *at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); objc_Module_genmoduleinfo_classes(); // create and set initializer LLGlobalVariable *moduleInfoSym = getIrModule(m)->moduleInfoSymbol(); b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym); setLinkage({LLGlobalValue::ExternalLinkage, false}, moduleInfoSym); if ((global.params.targetTriple.isOSLinux() && global.params.targetTriple.getEnvironment() != llvm::Triple::Android) || global.params.targetTriple.isOSFreeBSD() || #if LDC_LLVM_VER > 305 global.params.targetTriple->isOSNetBSD() || global.params.targetTriple->isOSOpenBSD() || global.params.targetTriple->isOSDragonFly() #else global.params.targetTriple->getOS() == llvm::Triple::NetBSD || global.params.targetTriple->getOS() == llvm::Triple::OpenBSD || global.params.targetTriple->getOS() == llvm::Triple::DragonFly #endif ) { if (emitFullModuleInfo) { build_dso_registry_calls(mangle(m), moduleInfoSym); } else { build_module_ref(mangle(m), moduleInfoSym); } } else { // build the modulereference and ctor for registering it LLFunction *mictor = build_module_reference_and_ctor(mangle(m), moduleInfoSym); AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); } }