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