1c269ed51SPeter Collingbourne //===-- ParallelCG.cpp ----------------------------------------------------===// 2c269ed51SPeter Collingbourne // 3c269ed51SPeter Collingbourne // The LLVM Compiler Infrastructure 4c269ed51SPeter Collingbourne // 5c269ed51SPeter Collingbourne // This file is distributed under the University of Illinois Open Source 6c269ed51SPeter Collingbourne // License. See LICENSE.TXT for details. 7c269ed51SPeter Collingbourne // 8c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 9c269ed51SPeter Collingbourne // 10c269ed51SPeter Collingbourne // This file defines functions that can be used for parallel code generation. 11c269ed51SPeter Collingbourne // 12c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 13c269ed51SPeter Collingbourne 14c269ed51SPeter Collingbourne #include "llvm/CodeGen/ParallelCG.h" 15c269ed51SPeter Collingbourne #include "llvm/Bitcode/ReaderWriter.h" 16c269ed51SPeter Collingbourne #include "llvm/IR/LLVMContext.h" 17c269ed51SPeter Collingbourne #include "llvm/IR/LegacyPassManager.h" 18c269ed51SPeter Collingbourne #include "llvm/IR/Module.h" 19c269ed51SPeter Collingbourne #include "llvm/Support/ErrorOr.h" 20c269ed51SPeter Collingbourne #include "llvm/Support/MemoryBuffer.h" 21c269ed51SPeter Collingbourne #include "llvm/Support/TargetRegistry.h" 22d84c7decSTeresa Johnson #include "llvm/Support/ThreadPool.h" 23c269ed51SPeter Collingbourne #include "llvm/Target/TargetMachine.h" 24c269ed51SPeter Collingbourne #include "llvm/Transforms/Utils/SplitModule.h" 25c269ed51SPeter Collingbourne 26c269ed51SPeter Collingbourne using namespace llvm; 27c269ed51SPeter Collingbourne 28*7950b129SDavide Italiano static void 29*7950b129SDavide Italiano codegen(Module *M, llvm::raw_pwrite_stream &OS, 30*7950b129SDavide Italiano std::function<std::unique_ptr<TargetMachine>()> TMFactory, 314d450906STobias Edler von Koch TargetMachine::CodeGenFileType FileType) { 32*7950b129SDavide Italiano std::unique_ptr<TargetMachine> TM = TMFactory(); 33c269ed51SPeter Collingbourne legacy::PassManager CodeGenPasses; 344d450906STobias Edler von Koch if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType)) 35c269ed51SPeter Collingbourne report_fatal_error("Failed to setup codegen"); 36c269ed51SPeter Collingbourne CodeGenPasses.run(*M); 37c269ed51SPeter Collingbourne } 38c269ed51SPeter Collingbourne 39*7950b129SDavide Italiano std::unique_ptr<Module> 40*7950b129SDavide Italiano llvm::splitCodeGen(std::unique_ptr<Module> M, ArrayRef<raw_pwrite_stream *> OSs, 41268826a2SEvgeniy Stepanov ArrayRef<llvm::raw_pwrite_stream *> BCOSs, StringRef CPU, 42*7950b129SDavide Italiano StringRef Features, const TargetOptions &Options, 43*7950b129SDavide Italiano Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, 44*7950b129SDavide Italiano TargetMachine::CodeGenFileType FileType, 45*7950b129SDavide Italiano bool PreserveLocals) { 46*7950b129SDavide Italiano std::string TripleStr = M->getTargetTriple(); 47c269ed51SPeter Collingbourne std::string ErrMsg; 48*7950b129SDavide Italiano 49c269ed51SPeter Collingbourne const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); 50c269ed51SPeter Collingbourne if (!TheTarget) 51c269ed51SPeter Collingbourne report_fatal_error(Twine("Target not found: ") + ErrMsg); 52*7950b129SDavide Italiano return splitCodeGen(std::move(M), OSs, BCOSs, [&]() { 53*7950b129SDavide Italiano return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( 54*7950b129SDavide Italiano TripleStr, CPU, Features, Options, RM, CM, OL)); 55*7950b129SDavide Italiano }, FileType, PreserveLocals); 56*7950b129SDavide Italiano } 57c269ed51SPeter Collingbourne 58*7950b129SDavide Italiano std::unique_ptr<Module> llvm::splitCodeGen( 59*7950b129SDavide Italiano std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs, 60*7950b129SDavide Italiano ArrayRef<llvm::raw_pwrite_stream *> BCOSs, 61*7950b129SDavide Italiano const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, 62*7950b129SDavide Italiano TargetMachine::CodeGenFileType FileType, bool PreserveLocals) { 63268826a2SEvgeniy Stepanov assert(BCOSs.empty() || BCOSs.size() == OSs.size()); 64268826a2SEvgeniy Stepanov 65c269ed51SPeter Collingbourne if (OSs.size() == 1) { 66268826a2SEvgeniy Stepanov if (!BCOSs.empty()) 67268826a2SEvgeniy Stepanov WriteBitcodeToFile(M.get(), *BCOSs[0]); 68*7950b129SDavide Italiano codegen(M.get(), *OSs[0], TMFactory, FileType); 69c269ed51SPeter Collingbourne return M; 70c269ed51SPeter Collingbourne } 71c269ed51SPeter Collingbourne 72d84c7decSTeresa Johnson // Create ThreadPool in nested scope so that threads will be joined 73d84c7decSTeresa Johnson // on destruction. 74d84c7decSTeresa Johnson { 75d84c7decSTeresa Johnson ThreadPool CodegenThreadPool(OSs.size()); 76d84c7decSTeresa Johnson int ThreadCount = 0; 77d84c7decSTeresa Johnson 78d84c7decSTeresa Johnson SplitModule( 79d84c7decSTeresa Johnson std::move(M), OSs.size(), 80d84c7decSTeresa Johnson [&](std::unique_ptr<Module> MPart) { 81d84c7decSTeresa Johnson // We want to clone the module in a new context to multi-thread the 82d84c7decSTeresa Johnson // codegen. We do it by serializing partition modules to bitcode 83d84c7decSTeresa Johnson // (while still on the main thread, in order to avoid data races) and 84d84c7decSTeresa Johnson // spinning up new threads which deserialize the partitions into 85d84c7decSTeresa Johnson // separate contexts. 86c269ed51SPeter Collingbourne // FIXME: Provide a more direct way to do this in LLVM. 87c269ed51SPeter Collingbourne SmallVector<char, 0> BC; 88c269ed51SPeter Collingbourne raw_svector_ostream BCOS(BC); 89c269ed51SPeter Collingbourne WriteBitcodeToFile(MPart.get(), BCOS); 90c269ed51SPeter Collingbourne 91268826a2SEvgeniy Stepanov if (!BCOSs.empty()) { 92268826a2SEvgeniy Stepanov BCOSs[ThreadCount]->write(BC.begin(), BC.size()); 93268826a2SEvgeniy Stepanov BCOSs[ThreadCount]->flush(); 94268826a2SEvgeniy Stepanov } 95268826a2SEvgeniy Stepanov 96d84c7decSTeresa Johnson llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++]; 97d84c7decSTeresa Johnson // Enqueue the task 98d84c7decSTeresa Johnson CodegenThreadPool.async( 99*7950b129SDavide Italiano [TMFactory, FileType, ThreadOS](const SmallVector<char, 0> &BC) { 100c269ed51SPeter Collingbourne LLVMContext Ctx; 101d84c7decSTeresa Johnson ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile( 102d84c7decSTeresa Johnson MemoryBufferRef(StringRef(BC.data(), BC.size()), 103c269ed51SPeter Collingbourne "<split-module>"), 104c269ed51SPeter Collingbourne Ctx); 105c269ed51SPeter Collingbourne if (!MOrErr) 106c269ed51SPeter Collingbourne report_fatal_error("Failed to read bitcode"); 107c269ed51SPeter Collingbourne std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); 108c269ed51SPeter Collingbourne 109*7950b129SDavide Italiano codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType); 110c269ed51SPeter Collingbourne }, 111c269ed51SPeter Collingbourne // Pass BC using std::move to ensure that it get moved rather than 112c269ed51SPeter Collingbourne // copied into the thread's context. 113c269ed51SPeter Collingbourne std::move(BC)); 114d84c7decSTeresa Johnson }, 115d84c7decSTeresa Johnson PreserveLocals); 116d84c7decSTeresa Johnson } 117c269ed51SPeter Collingbourne 118c269ed51SPeter Collingbourne return {}; 119c269ed51SPeter Collingbourne } 120