diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/ParallelCG.cpp')
| -rw-r--r-- | contrib/llvm/lib/CodeGen/ParallelCG.cpp | 99 | 
1 files changed, 99 insertions, 0 deletions
| diff --git a/contrib/llvm/lib/CodeGen/ParallelCG.cpp b/contrib/llvm/lib/CodeGen/ParallelCG.cpp new file mode 100644 index 000000000000..bc3f2a6e9b5a --- /dev/null +++ b/contrib/llvm/lib/CodeGen/ParallelCG.cpp @@ -0,0 +1,99 @@ +//===-- ParallelCG.cpp ----------------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines functions that can be used for parallel code generation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/ParallelCG.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ThreadPool.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/SplitModule.h" + +using namespace llvm; + +static void codegen(Module *M, llvm::raw_pwrite_stream &OS, +                    function_ref<std::unique_ptr<TargetMachine>()> TMFactory, +                    TargetMachine::CodeGenFileType FileType) { +  std::unique_ptr<TargetMachine> TM = TMFactory(); +  legacy::PassManager CodeGenPasses; +  if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType)) +    report_fatal_error("Failed to setup codegen"); +  CodeGenPasses.run(*M); +} + +std::unique_ptr<Module> llvm::splitCodeGen( +    std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs, +    ArrayRef<llvm::raw_pwrite_stream *> BCOSs, +    const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, +    TargetMachine::CodeGenFileType FileType, bool PreserveLocals) { +  assert(BCOSs.empty() || BCOSs.size() == OSs.size()); + +  if (OSs.size() == 1) { +    if (!BCOSs.empty()) +      WriteBitcodeToFile(*M, *BCOSs[0]); +    codegen(M.get(), *OSs[0], TMFactory, FileType); +    return M; +  } + +  // Create ThreadPool in nested scope so that threads will be joined +  // on destruction. +  { +    ThreadPool CodegenThreadPool(OSs.size()); +    int ThreadCount = 0; + +    SplitModule( +        std::move(M), OSs.size(), +        [&](std::unique_ptr<Module> MPart) { +          // We want to clone the module in a new context to multi-thread the +          // codegen. We do it by serializing partition modules to bitcode +          // (while still on the main thread, in order to avoid data races) and +          // spinning up new threads which deserialize the partitions into +          // separate contexts. +          // FIXME: Provide a more direct way to do this in LLVM. +          SmallString<0> BC; +          raw_svector_ostream BCOS(BC); +          WriteBitcodeToFile(*MPart, BCOS); + +          if (!BCOSs.empty()) { +            BCOSs[ThreadCount]->write(BC.begin(), BC.size()); +            BCOSs[ThreadCount]->flush(); +          } + +          llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++]; +          // Enqueue the task +          CodegenThreadPool.async( +              [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) { +                LLVMContext Ctx; +                Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile( +                    MemoryBufferRef(StringRef(BC.data(), BC.size()), +                                    "<split-module>"), +                    Ctx); +                if (!MOrErr) +                  report_fatal_error("Failed to read bitcode"); +                std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); + +                codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType); +              }, +              // Pass BC using std::move to ensure that it get moved rather than +              // copied into the thread's context. +              std::move(BC)); +        }, +        PreserveLocals); +  } + +  return {}; +} | 
