Index: test/tools/gold/X86/parallel.ll =================================================================== --- /dev/null +++ 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 +} Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ 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 @@ 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; @@ -103,10 +105,9 @@ // use only and will not be passed. static std::vector extra; - static void process_plugin_option(const char *opt_) - { + static bool process_plugin_option(const char *opt_) { if (opt_ == nullptr) - return; + return true; llvm::StringRef opt = opt_; if (opt == "generate-api-file") { @@ -126,9 +127,16 @@ } else if (opt == "disable-output") { 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"); + if (opt[1] < '0' || opt[1] > '3') { + message(LDPL_ERROR, "Optimization level must be between 0 and 3"); + return false; + } OptLevel = opt[1] - '0'; + } else if (opt.startswith("jobs=")) { + if (StringRef(opt_ + 5).getAsInteger(10, Parallelism)) { + message(LDPL_ERROR, "Invalid parallelism level: %s", opt_ + 5); + return false; + } } else { // Save this option to pass to the code generator. // ParseCommandLineOptions() expects argv[0] to be program name. Lazily @@ -138,6 +146,8 @@ extra.push_back(opt_); } + + return true; } } @@ -184,7 +194,8 @@ } break; case LDPT_OPTION: - options::process_plugin_option(tv->tv_u.tv_string); + if (!options::process_plugin_option(tv->tv_u.tv_string)) + return LDPS_ERR; break; case LDPT_REGISTER_CLAIM_FILE_HOOK: { ld_plugin_register_claim_file callback; @@ -742,8 +753,8 @@ 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 +790,10 @@ 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 +801,47 @@ 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 +908,7 @@ 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)