ThreadSafeModule cloneToNewContext(ThreadSafeModule &TSM, GVPredicate ShouldCloneDef, GVModifier UpdateClonedDefSource) { assert(TSM && "Can not clone null module"); if (!ShouldCloneDef) ShouldCloneDef = [](const GlobalValue &) { return true; }; auto Lock = TSM.getContextLock(); SmallVector<char, 1> ClonedModuleBuffer; { std::set<GlobalValue *> ClonedDefsInSrc; ValueToValueMapTy VMap; auto Tmp = CloneModule(*TSM.getModule(), VMap, [&](const GlobalValue *GV) { if (ShouldCloneDef(*GV)) { ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV)); return true; } return false; }); if (UpdateClonedDefSource) for (auto *GV : ClonedDefsInSrc) UpdateClonedDefSource(*GV); BitcodeWriter BCWriter(ClonedModuleBuffer); BCWriter.writeModule(*Tmp); BCWriter.writeSymtab(); BCWriter.writeStrtab(); } MemoryBufferRef ClonedModuleBufferRef( StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()), "cloned module buffer"); ThreadSafeContext NewTSCtx(llvm::make_unique<LLVMContext>()); auto ClonedModule = cantFail(parseBitcodeFile(ClonedModuleBufferRef, *NewTSCtx.getContext())); ClonedModule->setModuleIdentifier(TSM.getModule()->getName()); return ThreadSafeModule(std::move(ClonedModule), std::move(NewTSCtx)); }
void DebugIR::createDebugInfo(Module &M, OwningPtr<Module> &DisplayM) { if (M.getFunctionList().size() == 0) // no functions -- no debug info needed return; OwningPtr<ValueToValueMapTy> VMap; if (WriteSourceToDisk && (HideDebugIntrinsics || HideDebugMetadata)) { VMap.reset(new ValueToValueMapTy); DisplayM.reset(CloneModule(&M, *VMap)); if (HideDebugIntrinsics) DebugIntrinsicsRemover::process(*DisplayM); if (HideDebugMetadata) DebugMetadataRemover::process(*DisplayM); } DIUpdater R(M, Filename, Directory, DisplayM.get(), VMap.get()); }
// clones the contents of the module `m` to the shadow_output collector // in the old JIT, this is equivalent to also adding it to the execution engine static void jl_add_to_shadow(Module *m) { #if defined(USE_MCJIT) || defined(USE_ORCJIT) #ifndef KEEP_BODIES if (!imaging_mode) return; #endif ValueToValueMapTy VMap; std::unique_ptr<Module> clone(CloneModule(m, VMap)); for (Module::iterator I = clone->begin(), E = clone->end(); I != E; ++I) { Function *F = &*I; if (!F->isDeclaration()) { F->setLinkage(Function::InternalLinkage); addComdat(F); } } #else // on the old jit, the shadow_module is the same as the execution engine_module std::unique_ptr<Module> clone(m); #endif jl_merge_module(shadow_output, std::move(clone)); }
// takes the running content that has collected in the shadow module and dump it to disk // this builds the object file portion of the sysimage files for fast startup static void jl_dump_shadow(char *fname, int jit_model, const char *sysimg_data, size_t sysimg_len, bool dump_as_bc) { #ifdef LLVM36 std::error_code err; StringRef fname_ref = StringRef(fname); raw_fd_ostream OS(fname_ref, err, sys::fs::F_None); #elif defined(LLVM35) std::string err; raw_fd_ostream OS(fname, err, sys::fs::F_None); #else std::string err; raw_fd_ostream OS(fname, err); #endif #ifdef LLVM37 // 3.7 simplified formatted output; just use the raw stream alone raw_fd_ostream& FOS(OS); #else formatted_raw_ostream FOS(OS); #endif // We don't want to use MCJIT's target machine because // it uses the large code model and we may potentially // want less optimizations there. Triple TheTriple = Triple(jl_TargetMachine->getTargetTriple()); #if defined(_OS_WINDOWS_) && defined(FORCE_ELF) #ifdef LLVM35 TheTriple.setObjectFormat(Triple::COFF); #else TheTriple.setEnvironment(Triple::UnknownEnvironment); #endif #elif defined(_OS_DARWIN_) && defined(FORCE_ELF) #ifdef LLVM35 TheTriple.setObjectFormat(Triple::MachO); #else TheTriple.setEnvironment(Triple::MachO); #endif #endif #ifdef LLVM35 std::unique_ptr<TargetMachine> #else OwningPtr<TargetMachine> #endif TM(jl_TargetMachine->getTarget().createTargetMachine( TheTriple.getTriple(), jl_TargetMachine->getTargetCPU(), jl_TargetMachine->getTargetFeatureString(), jl_TargetMachine->Options, #if defined(_OS_LINUX_) || defined(_OS_FREEBSD_) Reloc::PIC_, #else jit_model ? Reloc::PIC_ : Reloc::Default, #endif jit_model ? CodeModel::JITDefault : CodeModel::Default, CodeGenOpt::Aggressive // -O3 TODO: respect command -O0 flag? )); #ifdef LLVM38 legacy::PassManager PM; #else PassManager PM; #endif #ifndef LLVM37 PM.add(new TargetLibraryInfo(Triple(TM->getTargetTriple()))); #else PM.add(new TargetLibraryInfoWrapperPass(Triple(TM->getTargetTriple()))); #endif // set up optimization passes #ifdef LLVM37 // No DataLayout pass needed anymore. #elif defined(LLVM36) PM.add(new DataLayoutPass()); #elif defined(LLVM35) PM.add(new DataLayoutPass(*jl_ExecutionEngine->getDataLayout())); #else PM.add(new DataLayout(*jl_ExecutionEngine->getDataLayout())); #endif addOptimizationPasses(&PM); if (!dump_as_bc) { if (TM->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile, false)) { jl_error("Could not generate obj file for this target"); } } // now copy the module, since PM.run may modify it ValueToValueMapTy VMap; #ifdef LLVM38 Module *clone = CloneModule(shadow_output, VMap).release(); #else Module *clone = CloneModule(shadow_output, VMap); #endif #ifdef LLVM37 // Reset the target triple to make sure it matches the new target machine clone->setTargetTriple(TM->getTargetTriple().str()); #ifdef LLVM38 clone->setDataLayout(TM->createDataLayout()); #else clone->setDataLayout(TM->getDataLayout()->getStringRepresentation()); #endif #endif // add metadata information jl_gen_llvm_globaldata(clone, VMap, sysimg_data, sysimg_len); // do the actual work PM.run(*clone); if (dump_as_bc) WriteBitcodeToFile(clone, FOS); delete clone; }