ParallelCG.cpp revision 292915
1292915Sdim//===-- ParallelCG.cpp ----------------------------------------------------===// 2292915Sdim// 3292915Sdim// The LLVM Compiler Infrastructure 4292915Sdim// 5292915Sdim// This file is distributed under the University of Illinois Open Source 6292915Sdim// License. See LICENSE.TXT for details. 7292915Sdim// 8292915Sdim//===----------------------------------------------------------------------===// 9292915Sdim// 10292915Sdim// This file defines functions that can be used for parallel code generation. 11292915Sdim// 12292915Sdim//===----------------------------------------------------------------------===// 13292915Sdim 14292915Sdim#include "llvm/CodeGen/ParallelCG.h" 15292915Sdim#include "llvm/Bitcode/ReaderWriter.h" 16292915Sdim#include "llvm/IR/LLVMContext.h" 17292915Sdim#include "llvm/IR/LegacyPassManager.h" 18292915Sdim#include "llvm/IR/Module.h" 19292915Sdim#include "llvm/Support/ErrorOr.h" 20292915Sdim#include "llvm/Support/MemoryBuffer.h" 21292915Sdim#include "llvm/Support/TargetRegistry.h" 22292915Sdim#include "llvm/Support/thread.h" 23292915Sdim#include "llvm/Target/TargetMachine.h" 24292915Sdim#include "llvm/Transforms/Utils/SplitModule.h" 25292915Sdim 26292915Sdimusing namespace llvm; 27292915Sdim 28292915Sdimstatic void codegen(Module *M, llvm::raw_pwrite_stream &OS, 29292915Sdim const Target *TheTarget, StringRef CPU, StringRef Features, 30292915Sdim const TargetOptions &Options, Reloc::Model RM, 31292915Sdim CodeModel::Model CM, CodeGenOpt::Level OL, 32292915Sdim TargetMachine::CodeGenFileType FileType) { 33292915Sdim std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( 34292915Sdim M->getTargetTriple(), CPU, Features, Options, RM, CM, OL)); 35292915Sdim 36292915Sdim legacy::PassManager CodeGenPasses; 37292915Sdim if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType)) 38292915Sdim report_fatal_error("Failed to setup codegen"); 39292915Sdim CodeGenPasses.run(*M); 40292915Sdim} 41292915Sdim 42292915Sdimstd::unique_ptr<Module> 43292915Sdimllvm::splitCodeGen(std::unique_ptr<Module> M, 44292915Sdim ArrayRef<llvm::raw_pwrite_stream *> OSs, StringRef CPU, 45292915Sdim StringRef Features, const TargetOptions &Options, 46292915Sdim Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, 47292915Sdim TargetMachine::CodeGenFileType FileType) { 48292915Sdim StringRef TripleStr = M->getTargetTriple(); 49292915Sdim std::string ErrMsg; 50292915Sdim const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); 51292915Sdim if (!TheTarget) 52292915Sdim report_fatal_error(Twine("Target not found: ") + ErrMsg); 53292915Sdim 54292915Sdim if (OSs.size() == 1) { 55292915Sdim codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM, 56292915Sdim OL, FileType); 57292915Sdim return M; 58292915Sdim } 59292915Sdim 60292915Sdim std::vector<thread> Threads; 61292915Sdim SplitModule(std::move(M), OSs.size(), [&](std::unique_ptr<Module> MPart) { 62292915Sdim // We want to clone the module in a new context to multi-thread the codegen. 63292915Sdim // We do it by serializing partition modules to bitcode (while still on the 64292915Sdim // main thread, in order to avoid data races) and spinning up new threads 65292915Sdim // which deserialize the partitions into separate contexts. 66292915Sdim // FIXME: Provide a more direct way to do this in LLVM. 67292915Sdim SmallVector<char, 0> BC; 68292915Sdim raw_svector_ostream BCOS(BC); 69292915Sdim WriteBitcodeToFile(MPart.get(), BCOS); 70292915Sdim 71292915Sdim llvm::raw_pwrite_stream *ThreadOS = OSs[Threads.size()]; 72292915Sdim Threads.emplace_back( 73292915Sdim [TheTarget, CPU, Features, Options, RM, CM, OL, FileType, 74292915Sdim ThreadOS](const SmallVector<char, 0> &BC) { 75292915Sdim LLVMContext Ctx; 76292915Sdim ErrorOr<std::unique_ptr<Module>> MOrErr = 77292915Sdim parseBitcodeFile(MemoryBufferRef(StringRef(BC.data(), BC.size()), 78292915Sdim "<split-module>"), 79292915Sdim Ctx); 80292915Sdim if (!MOrErr) 81292915Sdim report_fatal_error("Failed to read bitcode"); 82292915Sdim std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); 83292915Sdim 84292915Sdim codegen(MPartInCtx.get(), *ThreadOS, TheTarget, CPU, Features, 85292915Sdim Options, RM, CM, OL, FileType); 86292915Sdim }, 87292915Sdim // Pass BC using std::move to ensure that it get moved rather than 88292915Sdim // copied into the thread's context. 89292915Sdim std::move(BC)); 90292915Sdim }); 91292915Sdim 92292915Sdim for (thread &T : Threads) 93292915Sdim T.join(); 94292915Sdim 95292915Sdim return {}; 96292915Sdim} 97