ParallelCG.cpp 3.7 KB

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