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. CodeGenFileType FileType) {
  27. std::unique_ptr<TargetMachine> TM = TMFactory();
  28. assert(TM && "Failed to create target machine!");
  29. legacy::PassManager CodeGenPasses;
  30. if (TM->addPassesToEmitFile(CodeGenPasses, OS, nullptr, FileType))
  31. report_fatal_error("Failed to setup codegen");
  32. CodeGenPasses.run(*M);
  33. }
  34. void llvm::splitCodeGen(
  35. Module &M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
  36. ArrayRef<llvm::raw_pwrite_stream *> BCOSs,
  37. const std::function<std::unique_ptr<TargetMachine>()> &TMFactory,
  38. CodeGenFileType FileType, bool PreserveLocals) {
  39. assert(BCOSs.empty() || BCOSs.size() == OSs.size());
  40. if (OSs.size() == 1) {
  41. if (!BCOSs.empty())
  42. WriteBitcodeToFile(M, *BCOSs[0]);
  43. codegen(&M, *OSs[0], TMFactory, FileType);
  44. return;
  45. }
  46. // Create ThreadPool in nested scope so that threads will be joined
  47. // on destruction.
  48. {
  49. ThreadPool CodegenThreadPool(hardware_concurrency(OSs.size()));
  50. int ThreadCount = 0;
  51. SplitModule(
  52. M, OSs.size(),
  53. [&](std::unique_ptr<Module> MPart) {
  54. // We want to clone the module in a new context to multi-thread the
  55. // codegen. We do it by serializing partition modules to bitcode
  56. // (while still on the main thread, in order to avoid data races) and
  57. // spinning up new threads which deserialize the partitions into
  58. // separate contexts.
  59. // FIXME: Provide a more direct way to do this in LLVM.
  60. SmallString<0> BC;
  61. raw_svector_ostream BCOS(BC);
  62. WriteBitcodeToFile(*MPart, BCOS);
  63. if (!BCOSs.empty()) {
  64. BCOSs[ThreadCount]->write(BC.begin(), BC.size());
  65. BCOSs[ThreadCount]->flush();
  66. }
  67. llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
  68. // Enqueue the task
  69. CodegenThreadPool.async(
  70. [TMFactory, FileType, ThreadOS](const SmallString<0> &BC) {
  71. LLVMContext Ctx;
  72. Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
  73. MemoryBufferRef(StringRef(BC.data(), BC.size()),
  74. "<split-module>"),
  75. Ctx);
  76. if (!MOrErr)
  77. report_fatal_error("Failed to read bitcode");
  78. std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
  79. codegen(MPartInCtx.get(), *ThreadOS, TMFactory, FileType);
  80. },
  81. // Pass BC using std::move to ensure that it get moved rather than
  82. // copied into the thread's context.
  83. std::move(BC));
  84. },
  85. PreserveLocals);
  86. }
  87. }