summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/ParallelCG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/ParallelCG.cpp')
-rw-r--r--llvm/lib/CodeGen/ParallelCG.cpp98
1 files changed, 98 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/ParallelCG.cpp b/llvm/lib/CodeGen/ParallelCG.cpp
new file mode 100644
index 000000000000..e4c73658cb4f
--- /dev/null
+++ b/llvm/lib/CodeGen/ParallelCG.cpp
@@ -0,0 +1,98 @@
+//===-- ParallelCG.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions that can be used for parallel code generation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/ParallelCG.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/Utils/SplitModule.h"
+
+using namespace llvm;
+
+static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
+ function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
+ TargetMachine::CodeGenFileType FileType) {
+ std::unique_ptr<TargetMachine> TM = TMFactory();
+ legacy::PassManager CodeGenPasses;
+ if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType))
+ report_fatal_error("Failed to setup codegen");
+ CodeGenPasses.run(*M);
+}
+
+std::unique_ptr<Module> llvm::splitCodeGen(
+ std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
+ ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
+ const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
+ TargetMachine::CodeGenFileType FileType, bool PreserveLocals) {
+ assert(BCOSs.empty() || BCOSs.size() == OSs.size());
+
+ if (OSs.size() == 1) {
+ if (!BCOSs.empty())
+ WriteBitcodeToFile(*M, *BCOSs[0]);
+ codegen(M.get(), *OSs[0], TMFactory, FileType);
+ return M;
+ }
+
+ // Create ThreadPool in nested scope so that threads will be joined
+ // on destruction.
+ {
+ ThreadPool CodegenThreadPool(OSs.size());
+ int ThreadCount = 0;
+
+ SplitModule(
+ std::move(M), OSs.size(),
+ [&](std::unique_ptr<Module> MPart) {
+ // We want to clone the module in a new context to multi-thread the
+ // codegen. We do it by serializing partition modules to bitcode
+ // (while still on the main thread, in order to avoid data races) and
+ // spinning up new threads which deserialize the partitions into
+ // separate contexts.
+ // FIXME: Provide a more direct way to do this in LLVM.
+ SmallString<0> BC;
+ raw_svector_ostream BCOS(BC);
+ WriteBitcodeToFile(*MPart, BCOS);
+
+ if (!BCOSs.empty()) {
+ BCOSs[ThreadCount]->write(BC.begin(), BC.size());
+ BCOSs[ThreadCount]->flush();
+ }
+
+ llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
+ // Enqueue the task
+ CodegenThreadPool.async(
+ [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
+ LLVMContext Ctx;
+ Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
+ MemoryBufferRef(StringRef(BC.data(), BC.size()),
+ "<split-module>"),
+ Ctx);
+ if (!MOrErr)
+ report_fatal_error("Failed to read bitcode");
+ std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
+
+ codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
+ },
+ // Pass BC using std::move to ensure that it get moved rather than
+ // copied into the thread's context.
+ std::move(BC));
+ },
+ PreserveLocals);
+ }
+
+ return {};
+}