1c269ed51SPeter Collingbourne //===-- ParallelCG.cpp ----------------------------------------------------===// 2c269ed51SPeter Collingbourne // 3c269ed51SPeter Collingbourne // The LLVM Compiler Infrastructure 4c269ed51SPeter Collingbourne // 5c269ed51SPeter Collingbourne // This file is distributed under the University of Illinois Open Source 6c269ed51SPeter Collingbourne // License. See LICENSE.TXT for details. 7c269ed51SPeter Collingbourne // 8c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 9c269ed51SPeter Collingbourne // 10c269ed51SPeter Collingbourne // This file defines functions that can be used for parallel code generation. 11c269ed51SPeter Collingbourne // 12c269ed51SPeter Collingbourne //===----------------------------------------------------------------------===// 13c269ed51SPeter Collingbourne 14c269ed51SPeter Collingbourne #include "llvm/CodeGen/ParallelCG.h" 15c269ed51SPeter Collingbourne #include "llvm/Bitcode/ReaderWriter.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" 21c269ed51SPeter Collingbourne #include "llvm/Support/TargetRegistry.h" 22c269ed51SPeter Collingbourne #include "llvm/Support/thread.h" 23c269ed51SPeter Collingbourne #include "llvm/Target/TargetMachine.h" 24c269ed51SPeter Collingbourne #include "llvm/Transforms/Utils/SplitModule.h" 25c269ed51SPeter Collingbourne 26c269ed51SPeter Collingbourne using namespace llvm; 27c269ed51SPeter Collingbourne 28c269ed51SPeter Collingbourne static void codegen(Module *M, llvm::raw_pwrite_stream &OS, 29c269ed51SPeter Collingbourne const Target *TheTarget, StringRef CPU, StringRef Features, 30c269ed51SPeter Collingbourne const TargetOptions &Options, Reloc::Model RM, 314d450906STobias Edler von Koch CodeModel::Model CM, CodeGenOpt::Level OL, 324d450906STobias Edler von Koch TargetMachine::CodeGenFileType FileType) { 33c269ed51SPeter Collingbourne std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( 34c269ed51SPeter Collingbourne M->getTargetTriple(), CPU, Features, Options, RM, CM, OL)); 35c269ed51SPeter Collingbourne 36c269ed51SPeter Collingbourne legacy::PassManager CodeGenPasses; 374d450906STobias Edler von Koch if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType)) 38c269ed51SPeter Collingbourne report_fatal_error("Failed to setup codegen"); 39c269ed51SPeter Collingbourne CodeGenPasses.run(*M); 40c269ed51SPeter Collingbourne } 41c269ed51SPeter Collingbourne 42c269ed51SPeter Collingbourne std::unique_ptr<Module> 43c269ed51SPeter Collingbourne llvm::splitCodeGen(std::unique_ptr<Module> M, 44c269ed51SPeter Collingbourne ArrayRef<llvm::raw_pwrite_stream *> OSs, StringRef CPU, 45c269ed51SPeter Collingbourne StringRef Features, const TargetOptions &Options, 464d450906STobias Edler von Koch Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, 47*d19d4d30SSergei Larin TargetMachine::CodeGenFileType FileType, 48*d19d4d30SSergei Larin bool PreserveLocals) { 49c269ed51SPeter Collingbourne StringRef TripleStr = M->getTargetTriple(); 50c269ed51SPeter Collingbourne std::string ErrMsg; 51c269ed51SPeter Collingbourne const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); 52c269ed51SPeter Collingbourne if (!TheTarget) 53c269ed51SPeter Collingbourne report_fatal_error(Twine("Target not found: ") + ErrMsg); 54c269ed51SPeter Collingbourne 55c269ed51SPeter Collingbourne if (OSs.size() == 1) { 56c269ed51SPeter Collingbourne codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM, 574d450906STobias Edler von Koch OL, FileType); 58c269ed51SPeter Collingbourne return M; 59c269ed51SPeter Collingbourne } 60c269ed51SPeter Collingbourne 61592ee15eSPeter Collingbourne std::vector<thread> Threads; 62c269ed51SPeter Collingbourne SplitModule(std::move(M), OSs.size(), [&](std::unique_ptr<Module> MPart) { 63c269ed51SPeter Collingbourne // We want to clone the module in a new context to multi-thread the codegen. 64c269ed51SPeter Collingbourne // We do it by serializing partition modules to bitcode (while still on the 65c269ed51SPeter Collingbourne // main thread, in order to avoid data races) and spinning up new threads 66c269ed51SPeter Collingbourne // which deserialize the partitions into separate contexts. 67c269ed51SPeter Collingbourne // FIXME: Provide a more direct way to do this in LLVM. 68c269ed51SPeter Collingbourne SmallVector<char, 0> BC; 69c269ed51SPeter Collingbourne raw_svector_ostream BCOS(BC); 70c269ed51SPeter Collingbourne WriteBitcodeToFile(MPart.get(), BCOS); 71c269ed51SPeter Collingbourne 72c269ed51SPeter Collingbourne llvm::raw_pwrite_stream *ThreadOS = OSs[Threads.size()]; 73c269ed51SPeter Collingbourne Threads.emplace_back( 744d450906STobias Edler von Koch [TheTarget, CPU, Features, Options, RM, CM, OL, FileType, 75c269ed51SPeter Collingbourne ThreadOS](const SmallVector<char, 0> &BC) { 76c269ed51SPeter Collingbourne LLVMContext Ctx; 77c269ed51SPeter Collingbourne ErrorOr<std::unique_ptr<Module>> MOrErr = 78c269ed51SPeter Collingbourne parseBitcodeFile(MemoryBufferRef(StringRef(BC.data(), BC.size()), 79c269ed51SPeter Collingbourne "<split-module>"), 80c269ed51SPeter Collingbourne Ctx); 81c269ed51SPeter Collingbourne if (!MOrErr) 82c269ed51SPeter Collingbourne report_fatal_error("Failed to read bitcode"); 83c269ed51SPeter Collingbourne std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); 84c269ed51SPeter Collingbourne 85c269ed51SPeter Collingbourne codegen(MPartInCtx.get(), *ThreadOS, TheTarget, CPU, Features, 864d450906STobias Edler von Koch Options, RM, CM, OL, FileType); 87c269ed51SPeter Collingbourne }, 88c269ed51SPeter Collingbourne // Pass BC using std::move to ensure that it get moved rather than 89c269ed51SPeter Collingbourne // copied into the thread's context. 90c269ed51SPeter Collingbourne std::move(BC)); 91*d19d4d30SSergei Larin }, PreserveLocals); 92c269ed51SPeter Collingbourne 93592ee15eSPeter Collingbourne for (thread &T : Threads) 94c269ed51SPeter Collingbourne T.join(); 95c269ed51SPeter Collingbourne 96c269ed51SPeter Collingbourne return {}; 97c269ed51SPeter Collingbourne } 98