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 26 using namespace llvm; 27 28 static void 29 codegen(Module *M, llvm::raw_pwrite_stream &OS, 30 const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, 31 TargetMachine::CodeGenFileType FileType) { 32 std::unique_ptr<TargetMachine> TM = TMFactory(); 33 legacy::PassManager CodeGenPasses; 34 if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType)) 35 report_fatal_error("Failed to setup codegen"); 36 CodeGenPasses.run(*M); 37 } 38 39 std::unique_ptr<Module> 40 llvm::splitCodeGen(std::unique_ptr<Module> M, ArrayRef<raw_pwrite_stream *> OSs, 41 ArrayRef<llvm::raw_pwrite_stream *> BCOSs, StringRef CPU, 42 StringRef Features, const TargetOptions &Options, 43 Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, 44 TargetMachine::CodeGenFileType FileType, 45 bool PreserveLocals) { 46 StringRef TripleStr = M->getTargetTriple(); 47 std::string ErrMsg; 48 49 const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); 50 if (!TheTarget) 51 report_fatal_error(Twine("Target not found: ") + ErrMsg); 52 return splitCodeGen(std::move(M), OSs, BCOSs, [&]() { 53 return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( 54 TripleStr, CPU, Features, Options, RM, CM, OL)); 55 }, FileType, PreserveLocals); 56 } 57 58 std::unique_ptr<Module> llvm::splitCodeGen( 59 std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs, 60 ArrayRef<llvm::raw_pwrite_stream *> BCOSs, 61 const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, 62 TargetMachine::CodeGenFileType FileType, bool PreserveLocals) { 63 assert(BCOSs.empty() || BCOSs.size() == OSs.size()); 64 65 if (OSs.size() == 1) { 66 if (!BCOSs.empty()) 67 WriteBitcodeToFile(M.get(), *BCOSs[0]); 68 codegen(M.get(), *OSs[0], TMFactory, FileType); 69 return M; 70 } 71 72 // Create ThreadPool in nested scope so that threads will be joined 73 // on destruction. 74 { 75 ThreadPool CodegenThreadPool(OSs.size()); 76 int ThreadCount = 0; 77 78 SplitModule( 79 std::move(M), OSs.size(), 80 [&](std::unique_ptr<Module> MPart) { 81 // We want to clone the module in a new context to multi-thread the 82 // codegen. We do it by serializing partition modules to bitcode 83 // (while still on the main thread, in order to avoid data races) and 84 // spinning up new threads which deserialize the partitions into 85 // separate contexts. 86 // FIXME: Provide a more direct way to do this in LLVM. 87 SmallVector<char, 0> BC; 88 raw_svector_ostream BCOS(BC); 89 WriteBitcodeToFile(MPart.get(), BCOS); 90 91 if (!BCOSs.empty()) { 92 BCOSs[ThreadCount]->write(BC.begin(), BC.size()); 93 BCOSs[ThreadCount]->flush(); 94 } 95 96 llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++]; 97 // Enqueue the task 98 CodegenThreadPool.async( 99 [&TMFactory, FileType, ThreadOS](const SmallVector<char, 0> &BC) { 100 LLVMContext Ctx; 101 ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile( 102 MemoryBufferRef(StringRef(BC.data(), BC.size()), 103 "<split-module>"), 104 Ctx); 105 if (!MOrErr) 106 report_fatal_error("Failed to read bitcode"); 107 std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); 108 109 codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType); 110 }, 111 // Pass BC using std::move to ensure that it get moved rather than 112 // copied into the thread's context. 113 std::move(BC)); 114 }, 115 PreserveLocals); 116 } 117 118 return {}; 119 } 120