ParallelCG.cpp 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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/ErrorOr.h"
  19. #include "llvm/Support/MemoryBuffer.h"
  20. #include "llvm/Support/ThreadPool.h"
  21. #include "llvm/Target/TargetMachine.h"
  22. #include "llvm/Transforms/Utils/SplitModule.h"
  23. using namespace llvm;
  24. static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
  25. function_ref<std::unique_ptr<TargetMachine>()> TMFactory,
  26. TargetMachine::CodeGenFileType FileType) {
  27. std::unique_ptr<TargetMachine> TM = TMFactory();
  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. std::unique_ptr<Module> llvm::splitCodeGen(
  34. std::unique_ptr<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. TargetMachine::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.get(), *OSs[0], TMFactory, FileType);
  43. return M;
  44. }
  45. // Create ThreadPool in nested scope so that threads will be joined
  46. // on destruction.
  47. {
  48. ThreadPool CodegenThreadPool(OSs.size());
  49. int ThreadCount = 0;
  50. SplitModule(
  51. std::move(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. return {};
  87. }