From 0a1d37b2e85cc428a49e120ea5ac67003d0ab620 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 1 Sep 2015 20:40:22 +0000 Subject: [PATCH] gold-plugin: Implement parallel LTO code generation using llvm::splitCodeGen. Parallelism can be enabled using a new plugin option, jobs=N, where N is the number of code generation threads. Differential Revision: http://reviews.llvm.org/D12308 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246584 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tools/gold/X86/parallel.ll | 22 +++++++++ tools/gold/gold-plugin.cpp | 81 +++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 test/tools/gold/X86/parallel.ll diff --git a/test/tools/gold/X86/parallel.ll b/test/tools/gold/X86/parallel.ll new file mode 100644 index 00000000000..8e1d9b675d4 --- /dev/null +++ b/test/tools/gold/X86/parallel.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as -o %t.bc %s +; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -u foo -u bar -plugin-opt jobs=2 -plugin-opt save-temps -o %t %t.bc +; RUN: llvm-nm %t.o0 | FileCheck --check-prefix=CHECK0 %s +; RUN: llvm-nm %t.o1 | FileCheck --check-prefix=CHECK1 %s + +target triple = "x86_64-unknown-linux-gnu" + +; CHECK0-NOT: bar +; CHECK0: T foo +; CHECK0-NOT: bar +define void @foo() { + call void @bar() + ret void +} + +; CHECK1-NOT: foo +; CHECK1: T bar +; CHECK1-NOT: foo +define void @bar() { + call void @foo() + ret void +} diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index a63cbbd6087..a917ecfa502 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -20,6 +20,7 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/ParallelCG.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DiagnosticInfo.h" @@ -92,6 +93,7 @@ namespace options { static bool generate_api_file = false; static OutputType TheOutputType = OT_NORMAL; static unsigned OptLevel = 2; + static unsigned Parallelism = 1; static std::string obj_path; static std::string extra_library_path; static std::string triple; @@ -127,8 +129,11 @@ namespace options { TheOutputType = OT_DISABLE; } else if (opt.size() == 2 && opt[0] == 'O') { if (opt[1] < '0' || opt[1] > '3') - report_fatal_error("Optimization level must be between 0 and 3"); + message(LDPL_FATAL, "Optimization level must be between 0 and 3"); OptLevel = opt[1] - '0'; + } else if (opt.startswith("jobs=")) { + if (StringRef(opt_ + 5).getAsInteger(10, Parallelism)) + message(LDPL_FATAL, "Invalid parallelism level: %s", opt_ + 5); } else { // Save this option to pass to the code generator. // ParseCommandLineOptions() expects argv[0] to be program name. Lazily @@ -742,8 +747,8 @@ static void saveBCFile(StringRef Path, Module &M) { WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); } -static void codegen(Module &M) { - const std::string &TripleStr = M.getTargetTriple(); +static void codegen(std::unique_ptr M) { + const std::string &TripleStr = M->getTargetTriple(); Triple TheTriple(TripleStr); std::string ErrMsg; @@ -779,12 +784,10 @@ static void codegen(Module &M) { TripleStr, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel)); - runLTOPasses(M, *TM); + runLTOPasses(*M, *TM); if (options::TheOutputType == options::OT_SAVE_TEMPS) - saveBCFile(output_name + ".opt.bc", M); - - legacy::PassManager CodeGenPasses; + saveBCFile(output_name + ".opt.bc", *M); SmallString<128> Filename; if (!options::obj_path.empty()) @@ -792,37 +795,47 @@ static void codegen(Module &M) { else if (options::TheOutputType == options::OT_SAVE_TEMPS) Filename = output_name + ".o"; - int FD; + std::vector> Filenames(options::Parallelism); bool TempOutFile = Filename.empty(); - if (TempOutFile) { - std::error_code EC = - sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); - if (EC) - message(LDPL_FATAL, "Could not create temporary file: %s", - EC.message().c_str()); - } else { - std::error_code EC = - sys::fs::openFileForWrite(Filename.c_str(), FD, sys::fs::F_None); - if (EC) - message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str()); - } - { - raw_fd_ostream OS(FD, true); + // Open a file descriptor for each backend thread. This is done in a block + // so that the output file descriptors are closed before gold opens them. + std::list OSs; + std::vector OSPtrs(options::Parallelism); + for (unsigned I = 0; I != options::Parallelism; ++I) { + int FD; + if (TempOutFile) { + std::error_code EC = + sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filenames[I]); + if (EC) + message(LDPL_FATAL, "Could not create temporary file: %s", + EC.message().c_str()); + } else { + Filenames[I] = Filename; + if (options::Parallelism != 1) + Filenames[I] += utostr(I); + std::error_code EC = + sys::fs::openFileForWrite(Filenames[I], FD, sys::fs::F_None); + if (EC) + message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str()); + } + OSs.emplace_back(FD, true); + OSPtrs[I] = &OSs.back(); + } - if (TM->addPassesToEmitFile(CodeGenPasses, OS, - TargetMachine::CGFT_ObjectFile)) - message(LDPL_FATAL, "Failed to setup codegen"); - CodeGenPasses.run(M); + // Run backend threads. + splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(), + Options, RelocationModel, CodeModel::Default, CGOptLevel); } - if (add_input_file(Filename.c_str()) != LDPS_OK) - message(LDPL_FATAL, - "Unable to add .o file to the link. File left behind in: %s", - Filename.c_str()); - - if (TempOutFile) - Cleanup.push_back(Filename.c_str()); + for (auto &Filename : Filenames) { + if (add_input_file(Filename.c_str()) != LDPS_OK) + message(LDPL_FATAL, + "Unable to add .o file to the link. File left behind in: %s", + Filename.c_str()); + if (TempOutFile) + Cleanup.push_back(Filename.c_str()); + } } /// gold informs us that all symbols have been read. At this point, we use @@ -889,7 +902,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { return LDPS_OK; } - codegen(*L.getModule()); + codegen(std::move(Combined)); if (!options::extra_library_path.empty() && set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK) -- 2.34.1