Home | History | Annotate | Download | only in CodeGen
      1 //===-- ParallelCG.cpp ----------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines functions that can be used for parallel code generation.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/CodeGen/ParallelCG.h"
     15 #include "llvm/Bitcode/ReaderWriter.h"
     16 #include "llvm/IR/LLVMContext.h"
     17 #include "llvm/IR/LegacyPassManager.h"
     18 #include "llvm/IR/Module.h"
     19 #include "llvm/Support/ErrorOr.h"
     20 #include "llvm/Support/MemoryBuffer.h"
     21 #include "llvm/Support/TargetRegistry.h"
     22 #include "llvm/Support/ThreadPool.h"
     23 #include "llvm/Target/TargetMachine.h"
     24 #include "llvm/Transforms/Utils/SplitModule.h"
     25 
     26 using namespace llvm;
     27 
     28 static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
     29                     function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
     30                     TargetMachine::CodeGenFileType FileType) {
     31   std::unique_ptr<TargetMachine> TM = TMFactory();
     32   legacy::PassManager CodeGenPasses;
     33   if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType))
     34     report_fatal_error("Failed to setup codegen");
     35   CodeGenPasses.run(*M);
     36 }
     37 
     38 std::unique_ptr<Module> llvm::splitCodeGen(
     39     std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
     40     ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
     41     const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
     42     TargetMachine::CodeGenFileType FileType, bool PreserveLocals) {
     43   assert(BCOSs.empty() || BCOSs.size() == OSs.size());
     44 
     45   if (OSs.size() == 1) {
     46     if (!BCOSs.empty())
     47       WriteBitcodeToFile(M.get(), *BCOSs[0]);
     48     codegen(M.get(), *OSs[0], TMFactory, FileType);
     49     return M;
     50   }
     51 
     52   // Create ThreadPool in nested scope so that threads will be joined
     53   // on destruction.
     54   {
     55     ThreadPool CodegenThreadPool(OSs.size());
     56     int ThreadCount = 0;
     57 
     58     SplitModule(
     59         std::move(M), OSs.size(),
     60         [&](std::unique_ptr<Module> MPart) {
     61           // We want to clone the module in a new context to multi-thread the
     62           // codegen. We do it by serializing partition modules to bitcode
     63           // (while still on the main thread, in order to avoid data races) and
     64           // spinning up new threads which deserialize the partitions into
     65           // separate contexts.
     66           // FIXME: Provide a more direct way to do this in LLVM.
     67           SmallString<0> BC;
     68           raw_svector_ostream BCOS(BC);
     69           WriteBitcodeToFile(MPart.get(), BCOS);
     70 
     71           if (!BCOSs.empty()) {
     72             BCOSs[ThreadCount]->write(BC.begin(), BC.size());
     73             BCOSs[ThreadCount]->flush();
     74           }
     75 
     76           llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
     77           // Enqueue the task
     78           CodegenThreadPool.async(
     79               [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
     80                 LLVMContext Ctx;
     81                 ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
     82                     MemoryBufferRef(StringRef(BC.data(), BC.size()),
     83                                     "<split-module>"),
     84                     Ctx);
     85                 if (!MOrErr)
     86                   report_fatal_error("Failed to read bitcode");
     87                 std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
     88 
     89                 codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
     90               },
     91               // Pass BC using std::move to ensure that it get moved rather than
     92               // copied into the thread's context.
     93               std::move(BC));
     94         },
     95         PreserveLocals);
     96   }
     97 
     98   return {};
     99 }
    100