llvm::GlobalVariable* JitCodeSpecializer::_clone_global_variable(SpecializationContext& context, const llvm::GlobalVariable& global_variable) const { // If the global variable already exists in the module, there is no point in cloning it again if (auto global = context.module->getGlobalVariable(global_variable.getName())) { return global; } // Create a new global variable with the same type, attributes, and properties const auto cloned_global = llvm::dyn_cast<llvm::GlobalVariable>( context.module->getOrInsertGlobal(global_variable.getName(), global_variable.getValueType())); cloned_global->setLinkage(global_variable.getLinkage()); cloned_global->setThreadLocalMode(global_variable.getThreadLocalMode()); cloned_global->copyAttributesFrom(&global_variable); if (!global_variable.isDeclaration()) { if (global_variable.hasInitializer()) { // Instruct LLVM to perform the cloning of the actual value (i.e., initializer) of the variable cloned_global->setInitializer(llvm::MapValue(global_variable.getInitializer(), context.llvm_value_map)); } // Clone LLVM metadata for the global variable llvm::SmallVector<std::pair<uint32_t, llvm::MDNode*>, 1> metadata_nodes; global_variable.getAllMetadata(metadata_nodes); for (const auto& metadata_node : metadata_nodes) { cloned_global->addMetadata(metadata_node.first, *MapMetadata(metadata_node.second, context.llvm_value_map, llvm::RF_MoveDistinctMDs)); } } return cloned_global; }
static void InitADFeatures(llvm::Module *M, const char *name, llvm::FunctionType *EPTy) { auto FC = M->getOrInsertFunction(name, EPTy); auto F = llvm::dyn_cast<llvm::Function>(FC); F->setLinkage(llvm::GlobalValue::ExternalLinkage); F->addFnAttr(llvm::Attribute::Naked); }
static void InitExternalData(NativeModulePtr natMod, llvm::Module *M) { for (auto dr : natMod->getExtDataRefs()) { auto dsize = dr->getDataSize(); auto symname = dr->getSymbolName(); auto extType = llvm::ArrayType::get(llvm::Type::getInt8Ty(M->getContext()), dsize); auto gv = llvm::dyn_cast<llvm::GlobalValue>( M->getOrInsertGlobal(symname, extType)); TASSERT(gv != nullptr, "Could not make global value!"); if (dr->isWeak()) { gv->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } else { gv->setLinkage(llvm::GlobalValue::ExternalLinkage); } llvm::Triple triple(M->getTargetTriple()); if (llvm::Triple::Win32 == triple.getOS()) { gv->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); } } }
Generator::Generator(llvm::Module *module, llvm::DIScope *debug_scope_) : mod(module), debug_scope(debug_scope_) { std::map<std::string, llvm::IRBuilder<> **> tors = { { "__ctor", &ctor }, { "__dtor", &dtor } }; for (auto &tor : tors) { auto func = llvm::cast<llvm::Function>(module->getOrInsertFunction( tor.first, llvm::FunctionType::get( llvm::Type::getVoidTy(module->getContext()), false))); func->setLinkage(llvm::GlobalValue::InternalLinkage); *tor.second = new llvm::IRBuilder<>( llvm::BasicBlock::Create(module->getContext(), "entry", func)); } }
void RTTIBuilder::push_void_array(llvm::Constant *CI, Type *valtype, Dsymbol *mangle_sym) { std::string initname(mangle(mangle_sym)); initname.append(".rtti.voidarr.data"); const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()); auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI, initname); setLinkage(lwc, G); G->setAlignment(DtoAlignment(valtype)); push_void_array(getTypeAllocSize(CI->getType()), G); }
void RTTIBuilder::push_array(llvm::Constant *CI, uint64_t dim, Type *valtype, Dsymbol *mangle_sym) { std::string tmpStr(valtype->arrayOf()->toChars()); tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), '['), tmpStr.end()); tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), ']'), tmpStr.end()); tmpStr.append("arr"); std::string initname(mangle_sym ? mangle(mangle_sym) : ".ldc"); initname.append(".rtti."); initname.append(tmpStr); initname.append(".data"); const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()); auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI, initname); setLinkage(lwc, G); G->setAlignment(DtoAlignment(valtype)); push_array(dim, DtoBitCast(G, DtoType(valtype->pointerTo()))); }
static void InitLiftedFunctions(NativeModulePtr natMod, llvm::Module *M) { for (auto &f : natMod->get_funcs()) { NativeFunctionPtr native_func = f.second; auto fname = native_func->get_name(); auto F = M->getFunction(fname); if (!F) { F = llvm::dyn_cast<llvm::Function>( M->getOrInsertFunction(fname, LiftedFunctionType())); TASSERT(F != nullptr, "Could not insert function into module"); ArchSetCallingConv(M, F); // make local functions 'static' F->setLinkage(llvm::GlobalValue::InternalLinkage); std::cout << "Inserted function: " << fname << std::endl; } else { std::cout << "Already inserted function: " << fname << ", skipping." << std::endl; } } }
void RTTIBuilder::finalize(LLType *type, LLValue *value) { llvm::ArrayRef<LLConstant *> inits = llvm::makeArrayRef(this->inits); LLStructType *st = isaStruct(type); assert(st); // set struct body if (st->isOpaque()) { const int n = inits.size(); std::vector<LLType *> types; types.reserve(n); for (int i = 0; i < n; ++i) { types.push_back(inits[i]->getType()); } st->setBody(types); } // create the inititalizer LLConstant *tiInit = LLConstantStruct::get(st, inits); // set the initializer llvm::GlobalVariable *gvar = llvm::cast<llvm::GlobalVariable>(value); gvar->setInitializer(tiInit); setLinkage({TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()}, gvar); }
// Iterate over the list of external functions and insert them as // global functions. static void InitExternalCode(NativeModulePtr natMod, llvm::Module *M) { for (auto e : natMod->getExtCalls()) { auto conv = e->getCallingConvention(); auto argCount = e->getNumArgs(); auto symName = e->getSymbolName(); auto funcSign = e->getFunctionSignature(); // Create the function if it is not already there. auto &C = M->getContext(); auto F = M->getFunction(symName); if (F) { continue; } if (ExternalCodeRef::McsemaCall == conv) { // normal mcsema function prototypes F = llvm::dyn_cast<llvm::Function>(M->getOrInsertFunction( ArchNameMcSemaCall(symName), LiftedFunctionType())); ArchSetCallingConv(M, F); F->setLinkage(llvm::GlobalValue::ExternalLinkage); continue; } std::vector<llvm::Type *> arguments; llvm::Type *returnType = nullptr; // Create arguments. const auto Arch = SystemArch(M); const auto OS = SystemOS(M); for (auto i = 0; i < argCount; i++) { if (_X86_64_ == Arch) { if (llvm::Triple::Win32 == OS) { if (funcSign.c_str()[i] == 'F') { arguments.push_back(llvm::Type::getDoubleTy(C)); } else { arguments.push_back(llvm::Type::getInt64Ty(C)); } } else if (llvm::Triple::Linux == OS) { arguments.push_back(llvm::Type::getInt64Ty(C)); } else { TASSERT(false, "Unknown OS Type!"); } } else { arguments.push_back(llvm::Type::getInt32Ty(C)); } } //create function type switch (e->getReturnType()) { case ExternalCodeRef::NoReturn: case ExternalCodeRef::VoidTy: returnType = llvm::Type::getVoidTy(C); break; case ExternalCodeRef::Unknown: case ExternalCodeRef::IntTy: if (natMod->is64Bit()) { returnType = llvm::Type::getInt64Ty(C); } else { returnType = llvm::Type::getInt32Ty(C); } break; default: throw TErr( __LINE__, __FILE__, "Encountered an unknown return type while translating function"); } auto FTy = llvm::FunctionType::get(returnType, arguments, false); if (e->isWeak()) { F = llvm::Function::Create(FTy, llvm::GlobalValue::ExternalWeakLinkage, symName, M); } else { F = llvm::Function::Create(FTy, llvm::GlobalValue::ExternalLinkage, symName, M); } if (e->getReturnType() == ExternalCodeRef::NoReturn) { F->setDoesNotReturn(); } //set calling convention if (natMod->is64Bit()) { ArchSetCallingConv(M, F); } else { F->setCallingConv(getLLVMCC(conv)); } } }
void setLinkage(Dsymbol *sym, llvm::GlobalObject *obj) { setLinkage(DtoLinkage(sym), obj); }
llvm::GlobalVariable *genModuleInfo(Module *m) { // check declaration in object.d const auto moduleInfoType = getModuleInfoType(); const auto moduleInfoDecl = Module::moduleinfo; // The "new-style" ModuleInfo records are variable-length, with the presence // of the various fields indicated by a certain flag bit. The base struct // should consist only of the _flags/_index fields (the latter of which is // unused). if (moduleInfoDecl->structsize != 4 + 4) { m->error("Unexpected size of struct `object.ModuleInfo`; " "druntime version does not match compiler (see -v)"); fatal(); } // First, figure out which fields are present and set the flags accordingly. unsigned flags = MInew; const auto fctor = buildModuleCtor(m); if (fctor) { flags |= MItlsctor; } const auto fdtor = buildModuleDtor(m); if (fdtor) { flags |= MItlsdtor; } const auto fsharedctor = buildModuleSharedCtor(m); if (fsharedctor) { flags |= MIctor; } const auto fshareddtor = buildModuleSharedDtor(m); if (fshareddtor) { flags |= MIdtor; } #if 0 if (fgetmembers) flags |= MIxgetMembers; #endif const auto fictor = getIrModule(m)->coverageCtor; if (fictor) flags |= MIictor; const auto funittest = buildModuleUnittest(m); if (funittest) { flags |= MIunitTest; } size_t importedModulesCount; const auto importedModules = buildImportedModules(m, importedModulesCount); if (importedModules) { flags |= MIimportedModules; } size_t localClassesCount; const auto localClasses = buildLocalClasses(m, localClassesCount); if (localClasses) { flags |= MIlocalClasses; } if (!m->needmoduleinfo) { flags |= MIstandalone; } // Now, start building the initialiser for the ModuleInfo instance. RTTIBuilder b(moduleInfoType); b.push_uint(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); #endif if (fictor) { b.push(fictor); } if (funittest) { b.push(funittest); } if (importedModules) { b.push_size(importedModulesCount); b.push(importedModules); } if (localClasses) { b.push_size(localClassesCount); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = m->toPrettyChars(); const size_t len = strlen(name) + 1; const auto it = llvm::IntegerType::getInt8Ty(gIR->context()); const auto at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); // Create a global symbol with the above initialiser. LLGlobalVariable *moduleInfoSym = getIrModule(m)->moduleInfoSymbol(); b.finalize(moduleInfoSym); setLinkage({LLGlobalValue::ExternalLinkage, supportsCOMDAT()}, moduleInfoSym); return moduleInfoSym; }