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 
28c269ed51SPeter Collingbourne static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
29c269ed51SPeter Collingbourne                     const Target *TheTarget, StringRef CPU, StringRef Features,
30c269ed51SPeter Collingbourne                     const TargetOptions &Options, Reloc::Model RM,
314d450906STobias Edler von Koch                     CodeModel::Model CM, CodeGenOpt::Level OL,
324d450906STobias Edler von Koch                     TargetMachine::CodeGenFileType FileType) {
33c269ed51SPeter Collingbourne   std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
34c269ed51SPeter Collingbourne       M->getTargetTriple(), CPU, Features, Options, RM, CM, OL));
35c269ed51SPeter Collingbourne 
36c269ed51SPeter Collingbourne   legacy::PassManager CodeGenPasses;
374d450906STobias Edler von Koch   if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType))
38c269ed51SPeter Collingbourne     report_fatal_error("Failed to setup codegen");
39c269ed51SPeter Collingbourne   CodeGenPasses.run(*M);
40c269ed51SPeter Collingbourne }
41c269ed51SPeter Collingbourne 
42*268826a2SEvgeniy Stepanov std::unique_ptr<Module> llvm::splitCodeGen(
43*268826a2SEvgeniy Stepanov     std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
44*268826a2SEvgeniy Stepanov     ArrayRef<llvm::raw_pwrite_stream *> BCOSs, StringRef CPU,
45*268826a2SEvgeniy Stepanov     StringRef Features, const TargetOptions &Options, Reloc::Model RM,
46*268826a2SEvgeniy Stepanov     CodeModel::Model CM, CodeGenOpt::Level OL,
47*268826a2SEvgeniy Stepanov     TargetMachine::CodeGenFileType FileType, bool PreserveLocals) {
48c269ed51SPeter Collingbourne   StringRef TripleStr = M->getTargetTriple();
49c269ed51SPeter Collingbourne   std::string ErrMsg;
50c269ed51SPeter Collingbourne   const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
51c269ed51SPeter Collingbourne   if (!TheTarget)
52c269ed51SPeter Collingbourne     report_fatal_error(Twine("Target not found: ") + ErrMsg);
53c269ed51SPeter Collingbourne 
54*268826a2SEvgeniy Stepanov   assert(BCOSs.empty() || BCOSs.size() == OSs.size());
55*268826a2SEvgeniy Stepanov 
56c269ed51SPeter Collingbourne   if (OSs.size() == 1) {
57*268826a2SEvgeniy Stepanov     if (!BCOSs.empty())
58*268826a2SEvgeniy Stepanov       WriteBitcodeToFile(M.get(), *BCOSs[0]);
59*268826a2SEvgeniy Stepanov     codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM, OL,
60*268826a2SEvgeniy Stepanov             FileType);
61c269ed51SPeter Collingbourne     return M;
62c269ed51SPeter Collingbourne   }
63c269ed51SPeter Collingbourne 
64d84c7decSTeresa Johnson   // Create ThreadPool in nested scope so that threads will be joined
65d84c7decSTeresa Johnson   // on destruction.
66d84c7decSTeresa Johnson   {
67d84c7decSTeresa Johnson     ThreadPool CodegenThreadPool(OSs.size());
68d84c7decSTeresa Johnson     int ThreadCount = 0;
69d84c7decSTeresa Johnson 
70d84c7decSTeresa Johnson     SplitModule(
71d84c7decSTeresa Johnson         std::move(M), OSs.size(),
72d84c7decSTeresa Johnson         [&](std::unique_ptr<Module> MPart) {
73d84c7decSTeresa Johnson           // We want to clone the module in a new context to multi-thread the
74d84c7decSTeresa Johnson           // codegen. We do it by serializing partition modules to bitcode
75d84c7decSTeresa Johnson           // (while still on the main thread, in order to avoid data races) and
76d84c7decSTeresa Johnson           // spinning up new threads which deserialize the partitions into
77d84c7decSTeresa Johnson           // separate contexts.
78c269ed51SPeter Collingbourne           // FIXME: Provide a more direct way to do this in LLVM.
79c269ed51SPeter Collingbourne           SmallVector<char, 0> BC;
80c269ed51SPeter Collingbourne           raw_svector_ostream BCOS(BC);
81c269ed51SPeter Collingbourne           WriteBitcodeToFile(MPart.get(), BCOS);
82c269ed51SPeter Collingbourne 
83*268826a2SEvgeniy Stepanov           if (!BCOSs.empty()) {
84*268826a2SEvgeniy Stepanov             BCOSs[ThreadCount]->write(BC.begin(), BC.size());
85*268826a2SEvgeniy Stepanov             BCOSs[ThreadCount]->flush();
86*268826a2SEvgeniy Stepanov           }
87*268826a2SEvgeniy Stepanov 
88d84c7decSTeresa Johnson           llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
89d84c7decSTeresa Johnson           // Enqueue the task
90d84c7decSTeresa Johnson           CodegenThreadPool.async(
914d450906STobias Edler von Koch               [TheTarget, CPU, Features, Options, RM, CM, OL, FileType,
92c269ed51SPeter Collingbourne                ThreadOS](const SmallVector<char, 0> &BC) {
93c269ed51SPeter Collingbourne                 LLVMContext Ctx;
94d84c7decSTeresa Johnson                 ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
95d84c7decSTeresa Johnson                     MemoryBufferRef(StringRef(BC.data(), BC.size()),
96c269ed51SPeter Collingbourne                                     "<split-module>"),
97c269ed51SPeter Collingbourne                     Ctx);
98c269ed51SPeter Collingbourne                 if (!MOrErr)
99c269ed51SPeter Collingbourne                   report_fatal_error("Failed to read bitcode");
100c269ed51SPeter Collingbourne                 std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
101c269ed51SPeter Collingbourne 
102c269ed51SPeter Collingbourne                 codegen(MPartInCtx.get(), *ThreadOS, TheTarget, CPU, Features,
1034d450906STobias Edler von Koch                         Options, RM, CM, OL, FileType);
104c269ed51SPeter Collingbourne               },
105c269ed51SPeter Collingbourne               // Pass BC using std::move to ensure that it get moved rather than
106c269ed51SPeter Collingbourne               // copied into the thread's context.
107c269ed51SPeter Collingbourne               std::move(BC));
108d84c7decSTeresa Johnson         },
109d84c7decSTeresa Johnson         PreserveLocals);
110d84c7decSTeresa Johnson   }
111c269ed51SPeter Collingbourne 
112c269ed51SPeter Collingbourne   return {};
113c269ed51SPeter Collingbourne }
114