1*0b57cec5SDimitry Andric //===-- ParallelCG.cpp ----------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file defines functions that can be used for parallel code generation.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric #include "llvm/CodeGen/ParallelCG.h"
14*0b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeReader.h"
15*0b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriter.h"
16*0b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
17*0b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
18*0b57cec5SDimitry Andric #include "llvm/IR/Module.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBufferRef.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/ThreadPool.h"
21*0b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
22*0b57cec5SDimitry Andric #include "llvm/Transforms/Utils/SplitModule.h"
23*0b57cec5SDimitry Andric
24*0b57cec5SDimitry Andric using namespace llvm;
25*0b57cec5SDimitry Andric
codegen(Module * M,llvm::raw_pwrite_stream & OS,function_ref<std::unique_ptr<TargetMachine> ()> TMFactory,CodeGenFileType FileType)26*0b57cec5SDimitry Andric static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
27*0b57cec5SDimitry Andric function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
28*0b57cec5SDimitry Andric CodeGenFileType FileType) {
29*0b57cec5SDimitry Andric std::unique_ptr<TargetMachine> TM = TMFactory();
30*0b57cec5SDimitry Andric assert(TM && "Failed to create target machine!");
31*0b57cec5SDimitry Andric
32*0b57cec5SDimitry Andric legacy::PassManager CodeGenPasses;
33*0b57cec5SDimitry Andric if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType))
34*0b57cec5SDimitry Andric report_fatal_error("Failed to setup codegen");
35*0b57cec5SDimitry Andric CodeGenPasses.run(*M);
36*0b57cec5SDimitry Andric }
37*0b57cec5SDimitry Andric
splitCodeGen(Module & M,ArrayRef<llvm::raw_pwrite_stream * > OSs,ArrayRef<llvm::raw_pwrite_stream * > BCOSs,const std::function<std::unique_ptr<TargetMachine> ()> & TMFactory,CodeGenFileType FileType,bool PreserveLocals)38*0b57cec5SDimitry Andric void llvm::splitCodeGen(
39*0b57cec5SDimitry Andric Module &M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
40*0b57cec5SDimitry Andric ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
41*0b57cec5SDimitry Andric const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
42*0b57cec5SDimitry Andric CodeGenFileType FileType, bool PreserveLocals) {
43*0b57cec5SDimitry Andric assert(BCOSs.empty() || BCOSs.size() == OSs.size());
44*0b57cec5SDimitry Andric
45*0b57cec5SDimitry Andric if (OSs.size() == 1) {
46*0b57cec5SDimitry Andric if (!BCOSs.empty())
47*0b57cec5SDimitry Andric WriteBitcodeToFile(M, *BCOSs[0]);
48*0b57cec5SDimitry Andric codegen(&M, *OSs[0], TMFactory, FileType);
49*0b57cec5SDimitry Andric return;
50*0b57cec5SDimitry Andric }
51*0b57cec5SDimitry Andric
52*0b57cec5SDimitry Andric // Create ThreadPool in nested scope so that threads will be joined
53*0b57cec5SDimitry Andric // on destruction.
54*0b57cec5SDimitry Andric {
55*0b57cec5SDimitry Andric ThreadPool CodegenThreadPool(hardware_concurrency(OSs.size()));
56*0b57cec5SDimitry Andric int ThreadCount = 0;
57*0b57cec5SDimitry Andric
58*0b57cec5SDimitry Andric SplitModule(
59*0b57cec5SDimitry Andric M, OSs.size(),
60*0b57cec5SDimitry Andric [&](std::unique_ptr<Module> MPart) {
61*0b57cec5SDimitry Andric // We want to clone the module in a new context to multi-thread the
62*0b57cec5SDimitry Andric // codegen. We do it by serializing partition modules to bitcode
63*0b57cec5SDimitry Andric // (while still on the main thread, in order to avoid data races) and
64*0b57cec5SDimitry Andric // spinning up new threads which deserialize the partitions into
65*0b57cec5SDimitry Andric // separate contexts.
66*0b57cec5SDimitry Andric // FIXME: Provide a more direct way to do this in LLVM.
67*0b57cec5SDimitry Andric SmallString<0> BC;
68*0b57cec5SDimitry Andric raw_svector_ostream BCOS(BC);
69*0b57cec5SDimitry Andric WriteBitcodeToFile(*MPart, BCOS);
70*0b57cec5SDimitry Andric
71*0b57cec5SDimitry Andric if (!BCOSs.empty()) {
72*0b57cec5SDimitry Andric BCOSs[ThreadCount]->write(BC.begin(), BC.size());
73*0b57cec5SDimitry Andric BCOSs[ThreadCount]->flush();
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric
76*0b57cec5SDimitry Andric llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
77*0b57cec5SDimitry Andric // Enqueue the task
78*0b57cec5SDimitry Andric CodegenThreadPool.async(
79*0b57cec5SDimitry Andric [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
80*0b57cec5SDimitry Andric LLVMContext Ctx;
81*0b57cec5SDimitry Andric Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
82*0b57cec5SDimitry Andric MemoryBufferRef(StringRef(BC.data(), BC.size()),
83*0b57cec5SDimitry Andric "<split-module>"),
84*0b57cec5SDimitry Andric Ctx);
85*0b57cec5SDimitry Andric if (!MOrErr)
86*0b57cec5SDimitry Andric report_fatal_error("Failed to read bitcode");
87*0b57cec5SDimitry Andric std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
88*0b57cec5SDimitry Andric
89*0b57cec5SDimitry Andric codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
90*0b57cec5SDimitry Andric },
91*0b57cec5SDimitry Andric // Pass BC using std::move to ensure that it get moved rather than
92*0b57cec5SDimitry Andric // copied into the thread's context.
93*0b57cec5SDimitry Andric std::move(BC));
94*0b57cec5SDimitry Andric },
95*0b57cec5SDimitry Andric PreserveLocals);
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric }
98*0b57cec5SDimitry Andric