diff --git a/gen/module.cpp b/gen/module.cpp index 84fc662a..16278dd1 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -42,6 +42,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Analysis/Verifier.h" #include "llvm/LinkAllPasses.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #if LDC_LLVM_VER >= 303 #include "llvm/IR/Module.h" #include "llvm/IR/DataLayout.h" @@ -326,6 +327,173 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo) return ctor; } +/// Builds the body for the ldc.dso_ctor and ldc.dso_dtor functions. +/// +/// Pseudocode: +/// if (dsoInitialized == executeWhenInitialized) { +/// dsoInitiaized = !executeWhenInitialized; +/// auto record = CompilerDSOData(1, dsoSlot, minfoBeg, minfoEnd); +/// _d_dso_registry(&record); +/// } +static void build_dso_ctor_dtor_body( + llvm::Function* targetFunc, + llvm::GlobalVariable* dsoInitiaized, + llvm::GlobalVariable* dsoSlot, + llvm::GlobalVariable* minfoBeg, + llvm::GlobalVariable* minfoEnd, + bool executeWhenInitialized +) { + llvm::Function* const dsoRegistry = LLVM_D_GetRuntimeFunction( + gIR->module, "_d_dso_registry"); + llvm::Type* const recordPtrTy = dsoRegistry->getFunctionType()->getContainedType(1); + llvm::Type* const recordTy = recordPtrTy->getContainedType(0); + + 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* initialized = b.CreateLoad(dsoInitiaized); + if (executeWhenInitialized) + b.CreateCondBr(initialized, initBB, endBB); + else + b.CreateCondBr(initialized, endBB, initBB); + } + { + IRBuilder<> b(initBB); + b.CreateStore(b.getInt1(!executeWhenInitialized), dsoInitiaized); + + llvm::Value* record = b.CreateAlloca(recordTy); + b.CreateStore(DtoConstSize_t(1), 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.CreateCall(dsoRegistry, record); + b.CreateBr(endBB); + } + { + IRBuilder<> b(endBB); + b.CreateRetVoid(); + } +} + +static void build_dso_registry_calls(llvm::Constant* thisModuleInfo) +{ + // Build the ModuleInfo reference and bracketing symbols. + llvm::Type* const moduleInfoPtrTy = + getPtrToType(DtoType(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. + llvm::GlobalVariable* minfoBeg = new llvm::GlobalVariable( + *gIR->module, + moduleInfoPtrTy, + true, + llvm::GlobalValue::LinkOnceODRLinkage, + getNullPtr(moduleInfoPtrTy), + "_minfo_beg" + ); + minfoBeg->setSection(".minfo_beg"); + minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility); + + std::string thismrefname = "_D"; + thismrefname += gIR->dmodule->mangle(); + thismrefname += "11__moduleRefZ"; + llvm::GlobalVariable* thismref = new llvm::GlobalVariable( + *gIR->module, + moduleInfoPtrTy, + true, + llvm::GlobalValue::LinkOnceODRLinkage, + DtoBitCast(thisModuleInfo, moduleInfoPtrTy), + thismrefname + ); + thismref->setSection(".minfo"); + gIR->usedArray.push_back(thismref); + + llvm::GlobalVariable* minfoEnd = new llvm::GlobalVariable( + *gIR->module, + moduleInfoPtrTy, + true, + llvm::GlobalValue::LinkOnceODRLinkage, + getNullPtr(moduleInfoPtrTy), + "_minfo_end" + ); + minfoEnd->setSection(".minfo_end"); + minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility); + + // Build the ctor to invoke _d_dso_registry. + llvm::GlobalVariable* dsoSlot = new llvm::GlobalVariable( + *gIR->module, + getVoidPtrType(), + false, + llvm::GlobalValue::LinkOnceODRLinkage, + getNullPtr(getVoidPtrType()), + "ldc.dso_slot" + ); + dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility); + llvm::GlobalVariable* dsoInitiaized = new llvm::GlobalVariable( + *gIR->module, + llvm::Type::getInt1Ty(gIR->context()), + false, + llvm::GlobalValue::LinkOnceODRLinkage, + llvm::ConstantInt::getFalse(gIR->context()), + "ldc.dso_initialized" + ); + dsoInitiaized->setVisibility(llvm::GlobalValue::HiddenVisibility); + + llvm::Function* dsoCtor = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), + llvm::GlobalValue::LinkOnceODRLinkage, + "ldc.dso_ctor", + gIR->module + ); + dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility); + build_dso_ctor_dtor_body(dsoCtor, dsoInitiaized, dsoSlot, minfoBeg, minfoEnd, false); + llvm::appendToGlobalCtors(*gIR->module, dsoCtor, 65535); + + llvm::Function* dsoDtor = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), + llvm::GlobalValue::LinkOnceODRLinkage, + "ldc.dso_dtor", + gIR->module + ); + dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility); + build_dso_ctor_dtor_body(dsoDtor, dsoInitiaized, dsoSlot, minfoBeg, minfoEnd, 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 (std::vector::iterator it = p->usedArray.begin(), + end = p->usedArray.end(); it != end; ++it) + { + usedVoidPtrs.push_back(DtoBitCast(*it, getVoidPtrType())); + } + + llvm::ArrayType *arrayType = llvm::ArrayType::get( + getVoidPtrType(), usedVoidPtrs.size()); + llvm::GlobalVariable* llvmUsed = new llvm::GlobalVariable( + *p->module, + arrayType, + false, + llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(arrayType, usedVoidPtrs), + "llvm.used" + ); + llvmUsed->setSection("llvm.metadata"); +} + llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context) { bool logenabled = Logger::enabled(); @@ -410,6 +578,8 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context) // generate ModuleInfo genmoduleinfo(); + build_llvm_used_array(&ir); + #if LDC_LLVM_VER >= 303 // Add the linker options metadata flag. ir.module->addModuleFlag(llvm::Module::AppendUnique, "Linker Options", @@ -632,8 +802,11 @@ void Module::genmoduleinfo() b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym); moduleInfoSym->setLinkage(llvm::GlobalValue::ExternalLinkage); - // build the modulereference and ctor for registering it - LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSym); - - AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); + if (global.params.isLinux) { + build_dso_registry_calls(moduleInfoSym); + } else { + // build the modulereference and ctor for registering it + LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSym); + AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); + } } diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 96480b24..20de9871 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -191,6 +191,7 @@ static void LLVM_D_BuildRuntimeModule() LLType* classInfoTy = DtoType(Type::typeinfoclass->type); LLType* typeInfoTy = DtoType(Type::dtypeinfo->type); LLType* aaTypeInfoTy = DtoType(Type::typeinfoassociativearray->type); + LLType* moduleInfoPtrTy = getPtrToType(DtoType(Module::moduleinfo->type)); LLType* aaTy = rt_ptr(LLStructType::get(gIR->context())); @@ -306,7 +307,7 @@ static void LLVM_D_BuildRuntimeModule() llvm::StringRef fname("_d_array_bounds"); llvm::StringRef fname2("_d_switch_error"); LLType *types[] = { - getPtrToType(DtoType(Module::moduleinfo->type)), + moduleInfoPtrTy, intTy }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); @@ -777,7 +778,7 @@ static void LLVM_D_BuildRuntimeModule() ->setAttributes(Attr_1_NoCapture); } - // int _aaEqual(TypeInfo_AssociativeArray ti, AA e1, AA e2) + // int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2) { llvm::StringRef fname("_aaEqual"); LLType *types[] = { typeInfoTy, aaTy, aaTy }; @@ -941,4 +942,23 @@ static void LLVM_D_BuildRuntimeModule() LLFunctionType* fty = llvm::FunctionType::get(voidTy, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } + + // void _d_dso_registry(CompilerDSOData* data) + if (global.params.isLinux) { + llvm::StringRef fname("_d_dso_registry"); + + llvm::StructType* dsoDataTy = llvm::StructType::get( + sizeTy, // version + getPtrToType(voidPtrTy), // slot + getPtrToType(moduleInfoPtrTy), // _minfo_beg + getPtrToType(moduleInfoPtrTy), // _minfo_end + NULL + ); + + llvm::Type* params[] = { + getPtrToType(dsoDataTy) + }; + llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, params, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } } diff --git a/runtime/druntime b/runtime/druntime index 43854621..e70b83b2 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 438546212cf6d1b82d5e6174056aa689f4caeb3c +Subproject commit e70b83b27122cc7f1b43ab404e27993fa43bdb29