1292915Sdim//===-- ParallelCG.cpp ----------------------------------------------------===//
2292915Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292915Sdim//
7292915Sdim//===----------------------------------------------------------------------===//
8292915Sdim//
9292915Sdim// This file defines functions that can be used for parallel code generation.
10292915Sdim//
11292915Sdim//===----------------------------------------------------------------------===//
12292915Sdim
13292915Sdim#include "llvm/CodeGen/ParallelCG.h"
14314564Sdim#include "llvm/Bitcode/BitcodeReader.h"
15314564Sdim#include "llvm/Bitcode/BitcodeWriter.h"
16292915Sdim#include "llvm/IR/LLVMContext.h"
17292915Sdim#include "llvm/IR/LegacyPassManager.h"
18292915Sdim#include "llvm/IR/Module.h"
19292915Sdim#include "llvm/Support/ErrorOr.h"
20292915Sdim#include "llvm/Support/MemoryBuffer.h"
21309124Sdim#include "llvm/Support/ThreadPool.h"
22292915Sdim#include "llvm/Target/TargetMachine.h"
23292915Sdim#include "llvm/Transforms/Utils/SplitModule.h"
24292915Sdim
25292915Sdimusing namespace llvm;
26292915Sdim
27292915Sdimstatic void codegen(Module *M, llvm::raw_pwrite_stream &OS,
28309124Sdim                    function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
29360784Sdim                    CodeGenFileType FileType) {
30309124Sdim  std::unique_ptr<TargetMachine> TM = TMFactory();
31292915Sdim  legacy::PassManager CodeGenPasses;
32341825Sdim  if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType))
33292915Sdim    report_fatal_error("Failed to setup codegen");
34292915Sdim  CodeGenPasses.run(*M);
35292915Sdim}
36292915Sdim
37309124Sdimstd::unique_ptr<Module> llvm::splitCodeGen(
38309124Sdim    std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
39309124Sdim    ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
40309124Sdim    const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
41360784Sdim    CodeGenFileType FileType, bool PreserveLocals) {
42309124Sdim  assert(BCOSs.empty() || BCOSs.size() == OSs.size());
43292915Sdim
44292915Sdim  if (OSs.size() == 1) {
45309124Sdim    if (!BCOSs.empty())
46341825Sdim      WriteBitcodeToFile(*M, *BCOSs[0]);
47309124Sdim    codegen(M.get(), *OSs[0], TMFactory, FileType);
48292915Sdim    return M;
49292915Sdim  }
50292915Sdim
51309124Sdim  // Create ThreadPool in nested scope so that threads will be joined
52309124Sdim  // on destruction.
53309124Sdim  {
54309124Sdim    ThreadPool CodegenThreadPool(OSs.size());
55309124Sdim    int ThreadCount = 0;
56292915Sdim
57309124Sdim    SplitModule(
58309124Sdim        std::move(M), OSs.size(),
59309124Sdim        [&](std::unique_ptr<Module> MPart) {
60309124Sdim          // We want to clone the module in a new context to multi-thread the
61309124Sdim          // codegen. We do it by serializing partition modules to bitcode
62309124Sdim          // (while still on the main thread, in order to avoid data races) and
63309124Sdim          // spinning up new threads which deserialize the partitions into
64309124Sdim          // separate contexts.
65309124Sdim          // FIXME: Provide a more direct way to do this in LLVM.
66309124Sdim          SmallString<0> BC;
67309124Sdim          raw_svector_ostream BCOS(BC);
68341825Sdim          WriteBitcodeToFile(*MPart, BCOS);
69292915Sdim
70309124Sdim          if (!BCOSs.empty()) {
71309124Sdim            BCOSs[ThreadCount]->write(BC.begin(), BC.size());
72309124Sdim            BCOSs[ThreadCount]->flush();
73309124Sdim          }
74309124Sdim
75309124Sdim          llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
76309124Sdim          // Enqueue the task
77309124Sdim          CodegenThreadPool.async(
78309124Sdim              [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
79309124Sdim                LLVMContext Ctx;
80314564Sdim                Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
81309124Sdim                    MemoryBufferRef(StringRef(BC.data(), BC.size()),
82309124Sdim                                    "<split-module>"),
83309124Sdim                    Ctx);
84309124Sdim                if (!MOrErr)
85309124Sdim                  report_fatal_error("Failed to read bitcode");
86309124Sdim                std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
87309124Sdim
88309124Sdim                codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
89309124Sdim              },
90309124Sdim              // Pass BC using std::move to ensure that it get moved rather than
91309124Sdim              // copied into the thread's context.
92309124Sdim              std::move(BC));
93292915Sdim        },
94309124Sdim        PreserveLocals);
95309124Sdim  }
96292915Sdim
97292915Sdim  return {};
98292915Sdim}
99