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