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"
22c269ed51SPeter Collingbourne #include "llvm/Support/thread.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,
47*d19d4d30SSergei Larin                    TargetMachine::CodeGenFileType FileType,
48*d19d4d30SSergei 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 
61592ee15eSPeter Collingbourne   std::vector<thread> Threads;
62c269ed51SPeter Collingbourne   SplitModule(std::move(M), OSs.size(), [&](std::unique_ptr<Module> MPart) {
63c269ed51SPeter Collingbourne     // We want to clone the module in a new context to multi-thread the codegen.
64c269ed51SPeter Collingbourne     // We do it by serializing partition modules to bitcode (while still on the
65c269ed51SPeter Collingbourne     // main thread, in order to avoid data races) and spinning up new threads
66c269ed51SPeter Collingbourne     // which deserialize the partitions into separate contexts.
67c269ed51SPeter Collingbourne     // FIXME: Provide a more direct way to do this in LLVM.
68c269ed51SPeter Collingbourne     SmallVector<char, 0> BC;
69c269ed51SPeter Collingbourne     raw_svector_ostream BCOS(BC);
70c269ed51SPeter Collingbourne     WriteBitcodeToFile(MPart.get(), BCOS);
71c269ed51SPeter Collingbourne 
72c269ed51SPeter Collingbourne     llvm::raw_pwrite_stream *ThreadOS = OSs[Threads.size()];
73c269ed51SPeter Collingbourne     Threads.emplace_back(
744d450906STobias Edler von Koch         [TheTarget, CPU, Features, Options, RM, CM, OL, FileType,
75c269ed51SPeter Collingbourne          ThreadOS](const SmallVector<char, 0> &BC) {
76c269ed51SPeter Collingbourne           LLVMContext Ctx;
77c269ed51SPeter Collingbourne           ErrorOr<std::unique_ptr<Module>> MOrErr =
78c269ed51SPeter Collingbourne               parseBitcodeFile(MemoryBufferRef(StringRef(BC.data(), BC.size()),
79c269ed51SPeter Collingbourne                                                "<split-module>"),
80c269ed51SPeter Collingbourne                                Ctx);
81c269ed51SPeter Collingbourne           if (!MOrErr)
82c269ed51SPeter Collingbourne             report_fatal_error("Failed to read bitcode");
83c269ed51SPeter Collingbourne           std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
84c269ed51SPeter Collingbourne 
85c269ed51SPeter Collingbourne           codegen(MPartInCtx.get(), *ThreadOS, TheTarget, CPU, Features,
864d450906STobias Edler von Koch                   Options, RM, CM, OL, FileType);
87c269ed51SPeter Collingbourne         },
88c269ed51SPeter Collingbourne         // Pass BC using std::move to ensure that it get moved rather than
89c269ed51SPeter Collingbourne         // copied into the thread's context.
90c269ed51SPeter Collingbourne         std::move(BC));
91*d19d4d30SSergei Larin   }, PreserveLocals);
92c269ed51SPeter Collingbourne 
93592ee15eSPeter Collingbourne   for (thread &T : Threads)
94c269ed51SPeter Collingbourne     T.join();
95c269ed51SPeter Collingbourne 
96c269ed51SPeter Collingbourne   return {};
97c269ed51SPeter Collingbourne }
98