ParallelCG.cpp revision 353358
1194955Strasz//===-- ParallelCG.cpp ----------------------------------------------------===//
2194955Strasz//
3194955Strasz// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4194955Strasz// See https://llvm.org/LICENSE.txt for license information.
5194955Strasz// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6194955Strasz//
7194955Strasz//===----------------------------------------------------------------------===//
8194955Strasz//
9194955Strasz// This file defines functions that can be used for parallel code generation.
10194955Strasz//
11194955Strasz//===----------------------------------------------------------------------===//
12194955Strasz
13194955Strasz#include "llvm/CodeGen/ParallelCG.h"
14194955Strasz#include "llvm/Bitcode/BitcodeReader.h"
15194955Strasz#include "llvm/Bitcode/BitcodeWriter.h"
16194955Strasz#include "llvm/IR/LLVMContext.h"
17194955Strasz#include "llvm/IR/LegacyPassManager.h"
18194955Strasz#include "llvm/IR/Module.h"
19194955Strasz#include "llvm/Support/ErrorOr.h"
20194955Strasz#include "llvm/Support/MemoryBuffer.h"
21194955Strasz#include "llvm/Support/ThreadPool.h"
22194955Strasz#include "llvm/Target/TargetMachine.h"
23194955Strasz#include "llvm/Transforms/Utils/SplitModule.h"
24194955Strasz
25194955Straszusing namespace llvm;
26194955Strasz
27194955Straszstatic void codegen(Module *M, llvm::raw_pwrite_stream &OS,
28194955Strasz                    function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
29194955Strasz                    TargetMachine::CodeGenFileType FileType) {
30194955Strasz  std::unique_ptr<TargetMachine> TM = TMFactory();
31194955Strasz  legacy::PassManager CodeGenPasses;
32194955Strasz  if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType))
33194955Strasz    report_fatal_error("Failed to setup codegen");
34194955Strasz  CodeGenPasses.run(*M);
35194955Strasz}
36194955Strasz
37194955Straszstd::unique_ptr<Module> llvm::splitCodeGen(
38194955Strasz    std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
39194955Strasz    ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
40194955Strasz    const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
41194955Strasz    TargetMachine::CodeGenFileType FileType, bool PreserveLocals) {
42194955Strasz  assert(BCOSs.empty() || BCOSs.size() == OSs.size());
43194955Strasz
44194955Strasz  if (OSs.size() == 1) {
45194955Strasz    if (!BCOSs.empty())
46194955Strasz      WriteBitcodeToFile(*M, *BCOSs[0]);
47194955Strasz    codegen(M.get(), *OSs[0], TMFactory, FileType);
48194955Strasz    return M;
49194955Strasz  }
50194955Strasz
51194955Strasz  // Create ThreadPool in nested scope so that threads will be joined
52194955Strasz  // on destruction.
53194955Strasz  {
54194955Strasz    ThreadPool CodegenThreadPool(OSs.size());
55194955Strasz    int ThreadCount = 0;
56194955Strasz
57194955Strasz    SplitModule(
58194955Strasz        std::move(M), OSs.size(),
59194955Strasz        [&](std::unique_ptr<Module> MPart) {
60194955Strasz          // We want to clone the module in a new context to multi-thread the
61194955Strasz          // codegen. We do it by serializing partition modules to bitcode
62194955Strasz          // (while still on the main thread, in order to avoid data races) and
63194955Strasz          // spinning up new threads which deserialize the partitions into
64194955Strasz          // separate contexts.
65194955Strasz          // FIXME: Provide a more direct way to do this in LLVM.
66194955Strasz          SmallString<0> BC;
67194955Strasz          raw_svector_ostream BCOS(BC);
68194955Strasz          WriteBitcodeToFile(*MPart, BCOS);
69194955Strasz
70194955Strasz          if (!BCOSs.empty()) {
71194955Strasz            BCOSs[ThreadCount]->write(BC.begin(), BC.size());
72194955Strasz            BCOSs[ThreadCount]->flush();
73194955Strasz          }
74287547Sdelphij
75194955Strasz          llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
76194955Strasz          // Enqueue the task
77194955Strasz          CodegenThreadPool.async(
78194955Strasz              [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
79194955Strasz                LLVMContext Ctx;
80194955Strasz                Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
81194955Strasz                    MemoryBufferRef(StringRef(BC.data(), BC.size()),
82194955Strasz                                    "<split-module>"),
83194955Strasz                    Ctx);
84194955Strasz                if (!MOrErr)
85194955Strasz                  report_fatal_error("Failed to read bitcode");
86194955Strasz                std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
87194955Strasz
88194955Strasz                codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
89194955Strasz              },
90194955Strasz              // Pass BC using std::move to ensure that it get moved rather than
91194955Strasz              // copied into the thread's context.
92194955Strasz              std::move(BC));
93194955Strasz        },
94194955Strasz        PreserveLocals);
95194955Strasz  }
96194955Strasz
97194955Strasz  return {};
98194955Strasz}
99194955Strasz