1c269ed51SPeter Collingbourne //===-- ParallelCG.cpp ----------------------------------------------------===// 2c269ed51SPeter Collingbourne // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c269ed51SPeter Collingbourne // 7c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 8c269ed51SPeter Collingbourne // 9c269ed51SPeter Collingbourne // This file defines functions that can be used for parallel code generation. 10c269ed51SPeter Collingbourne // 11c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 12c269ed51SPeter Collingbourne 13c269ed51SPeter Collingbourne #include "llvm/CodeGen/ParallelCG.h" 14ad17679aSTeresa Johnson #include "llvm/Bitcode/BitcodeReader.h" 15ad17679aSTeresa Johnson #include "llvm/Bitcode/BitcodeWriter.h" 16c269ed51SPeter Collingbourne #include "llvm/IR/LLVMContext.h" 17c269ed51SPeter Collingbourne #include "llvm/IR/LegacyPassManager.h" 18c269ed51SPeter Collingbourne #include "llvm/IR/Module.h" 19c269ed51SPeter Collingbourne #include "llvm/Support/ErrorOr.h" 20c269ed51SPeter Collingbourne #include "llvm/Support/MemoryBuffer.h" 21d84c7decSTeresa Johnson #include "llvm/Support/ThreadPool.h" 22c269ed51SPeter Collingbourne #include "llvm/Target/TargetMachine.h" 23c269ed51SPeter Collingbourne #include "llvm/Transforms/Utils/SplitModule.h" 24c269ed51SPeter Collingbourne 25c269ed51SPeter Collingbourne using namespace llvm; 26c269ed51SPeter Collingbourne 271afc1de4SBenjamin Kramer static void codegen(Module *M, llvm::raw_pwrite_stream &OS, 281afc1de4SBenjamin Kramer function_ref<std::unique_ptr<TargetMachine>()> TMFactory, 294d450906STobias Edler von Koch TargetMachine::CodeGenFileType FileType) { 307950b129SDavide Italiano std::unique_ptr<TargetMachine> TM = TMFactory(); 31c269ed51SPeter Collingbourne legacy::PassManager CodeGenPasses; 329a45114bSPeter Collingbourne if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType)) 33c269ed51SPeter Collingbourne report_fatal_error("Failed to setup codegen"); 34c269ed51SPeter Collingbourne CodeGenPasses.run(*M); 35c269ed51SPeter Collingbourne } 36c269ed51SPeter Collingbourne 377950b129SDavide Italiano std::unique_ptr<Module> llvm::splitCodeGen( 387950b129SDavide Italiano std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs, 397950b129SDavide Italiano ArrayRef<llvm::raw_pwrite_stream *> BCOSs, 407950b129SDavide Italiano const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, 417950b129SDavide Italiano TargetMachine::CodeGenFileType FileType, bool PreserveLocals) { 42268826a2SEvgeniy Stepanov assert(BCOSs.empty() || BCOSs.size() == OSs.size()); 43268826a2SEvgeniy Stepanov 44c269ed51SPeter Collingbourne if (OSs.size() == 1) { 45268826a2SEvgeniy Stepanov if (!BCOSs.empty()) 466a86e25dSRafael Espindola WriteBitcodeToFile(*M, *BCOSs[0]); 477950b129SDavide Italiano codegen(M.get(), *OSs[0], TMFactory, FileType); 48c269ed51SPeter Collingbourne return M; 49c269ed51SPeter Collingbourne } 50c269ed51SPeter Collingbourne 51d84c7decSTeresa Johnson // Create ThreadPool in nested scope so that threads will be joined 52d84c7decSTeresa Johnson // on destruction. 53d84c7decSTeresa Johnson { 54d84c7decSTeresa Johnson ThreadPool CodegenThreadPool(OSs.size()); 55d84c7decSTeresa Johnson int ThreadCount = 0; 56d84c7decSTeresa Johnson 57d84c7decSTeresa Johnson SplitModule( 58d84c7decSTeresa Johnson std::move(M), OSs.size(), 59d84c7decSTeresa Johnson [&](std::unique_ptr<Module> MPart) { 60d84c7decSTeresa Johnson // We want to clone the module in a new context to multi-thread the 61d84c7decSTeresa Johnson // codegen. We do it by serializing partition modules to bitcode 62d84c7decSTeresa Johnson // (while still on the main thread, in order to avoid data races) and 63d84c7decSTeresa Johnson // spinning up new threads which deserialize the partitions into 64d84c7decSTeresa Johnson // separate contexts. 65c269ed51SPeter Collingbourne // FIXME: Provide a more direct way to do this in LLVM. 66caa11696SDavide Italiano SmallString<0> BC; 67c269ed51SPeter Collingbourne raw_svector_ostream BCOS(BC); 686a86e25dSRafael Espindola WriteBitcodeToFile(*MPart, BCOS); 69c269ed51SPeter Collingbourne 70268826a2SEvgeniy Stepanov if (!BCOSs.empty()) { 71268826a2SEvgeniy Stepanov BCOSs[ThreadCount]->write(BC.begin(), BC.size()); 72268826a2SEvgeniy Stepanov BCOSs[ThreadCount]->flush(); 73268826a2SEvgeniy Stepanov } 74268826a2SEvgeniy Stepanov 75d84c7decSTeresa Johnson llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++]; 76d84c7decSTeresa Johnson // Enqueue the task 77d84c7decSTeresa Johnson CodegenThreadPool.async( 78caa11696SDavide Italiano [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) { 79c269ed51SPeter Collingbourne LLVMContext Ctx; 80d9445c49SPeter Collingbourne Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile( 81d84c7decSTeresa Johnson MemoryBufferRef(StringRef(BC.data(), BC.size()), 82c269ed51SPeter Collingbourne "<split-module>"), 83c269ed51SPeter Collingbourne Ctx); 84c269ed51SPeter Collingbourne if (!MOrErr) 85c269ed51SPeter Collingbourne report_fatal_error("Failed to read bitcode"); 86c269ed51SPeter Collingbourne std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); 87c269ed51SPeter Collingbourne 887950b129SDavide Italiano codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType); 89c269ed51SPeter Collingbourne }, 90c269ed51SPeter Collingbourne // Pass BC using std::move to ensure that it get moved rather than 91c269ed51SPeter Collingbourne // copied into the thread's context. 92c269ed51SPeter Collingbourne std::move(BC)); 93d84c7decSTeresa Johnson }, 94d84c7decSTeresa Johnson PreserveLocals); 95d84c7decSTeresa Johnson } 96c269ed51SPeter Collingbourne 97c269ed51SPeter Collingbourne return {}; 98c269ed51SPeter Collingbourne } 99