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