[PATCH] D12260: CodeGen: Introduce LinkedCodeGen and teach LTOCodeGenerator to use it.
Duncan P. N. Exon Smith via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 18:57:54 PDT 2015
> On 2015-Aug-25, at 16:14, Peter Collingbourne <peter at pcc.me.uk> wrote:
>
> pcc updated this revision to Diff 33150.
> pcc added a comment.
>
> - Fix Windows build
>
>
> https://urldefense.proofpoint.com/v2/url?u=http-3A__reviews.llvm.org_D12260&d=BQIFaQ&c=eEvniauFctOgLOKGJOplqw&r=vftFLnHiqThJHdL0qZWd_Vo12qdMVOZDFnNVBhP9GKA&m=LR4XRsm2u4QpVLq4liZi9UycCYW146OrosG6MnIC3Ek&s=SjFYB-ttVWcxbGFt0wO_dA0k8YQq_9XVKLcPQzHVuVY&e=
>
> Files:
> cmake/modules/HandleLLVMOptions.cmake
> include/llvm/CodeGen/Parallel.h
> include/llvm/LTO/LTOCodeGenerator.h
> lib/CodeGen/CMakeLists.txt
> lib/CodeGen/Parallel.cpp
> lib/LTO/LTOCodeGenerator.cpp
> test/LTO/X86/parallel.ll
> tools/llvm-lto/llvm-lto.cpp
>
> <D12260.33150.patch>
> Index: tools/llvm-lto/llvm-lto.cpp
> ===================================================================
> --- tools/llvm-lto/llvm-lto.cpp
> +++ tools/llvm-lto/llvm-lto.cpp
> @@ -240,24 +244,38 @@
>
> if (!OutputFilename.empty()) {
> std::string ErrorInfo;
> - std::unique_ptr<MemoryBuffer> Code = CodeGen.compile(
> - DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo);
> - if (!Code) {
> - errs() << argv[0]
> - << ": error compiling the code: " << ErrorInfo << "\n";
> + if (!CodeGen.optimize(DisableInline, DisableGVNLoadPRE,
> + DisableLTOVectorization, ErrorInfo)) {
> + errs() << argv[0] << ": error optimizing the code: " << ErrorInfo << "\n";
> return 1;
> }
>
> - std::error_code EC;
> - raw_fd_ostream FileStream(OutputFilename, EC, sys::fs::F_None);
> - if (EC) {
> - errs() << argv[0] << ": error opening the file '" << OutputFilename
> - << "': " << EC.message() << "\n";
> - return 1;
> + std::list<raw_fd_ostream> OSs;
> + std::vector<raw_pwrite_stream *> OSPtrs;
> + for (unsigned I = 0; I != Parallelism; ++I) {
> + std::string PartFilename = OutputFilename;
> + if (Parallelism != 1)
> + PartFilename += utostr(I);
I don't love these filenames. I know it's just for the testing tool,
but maybe `.o.N` instead of `.oN`?
> + std::error_code EC;
> + OSs.emplace_back(PartFilename, EC, sys::fs::F_None);
> + if (EC) {
> + errs() << argv[0] << ": error opening the file '" << PartFilename
> + << "': " << EC.message() << "\n";
> + return 1;
> + }
> + OSPtrs.push_back(&OSs.back());
> }
>
> - FileStream.write(Code->getBufferStart(), Code->getBufferSize());
> + if (!CodeGen.compileOptimized(OSPtrs, ErrorInfo)) {
> + errs() << argv[0] << ": error compiling the code: " << ErrorInfo << "\n";
> + return 1;
> + }
> } else {
> + if (Parallelism != 1) {
> + errs() << argv[0] << ": -j must be specified together with -o\n";
> + return 1;
> + }
> +
> std::string ErrorInfo;
> const char *OutputName = nullptr;
> if (!CodeGen.compile_to_file(&OutputName, DisableInline,
> Index: lib/CodeGen/Parallel.cpp
> ===================================================================
> --- /dev/null
> +++ lib/CodeGen/Parallel.cpp
Should this be ParallelCodeGen.cpp or ParallelCG.cpp? I don't have a
strong opinion myself, but I feel like that vaguely follows the file
naming conventions better (we tend to name files a little redundantly).
> @@ -0,0 +1,89 @@
> +//===-- Parallel.cpp ------------------------------------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines functions that can be used for parallel code generation.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/CodeGen/Parallel.h"
> +#include "llvm/Bitcode/ReaderWriter.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/LegacyPassManager.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/Support/ErrorOr.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/TargetRegistry.h"
> +#include "llvm/Target/TargetMachine.h"
> +#include "llvm/Transforms/Utils/SplitModule.h"
> +
> +#ifdef _MSC_VER
> +// concrt.h depends on eh.h for __uncaught_exception declaration
> +// even if we disable exceptions.
> +#include <eh.h>
> +#endif
Can/should this go in an llvm/Support header (that also includes
`<thread>`) somewhere?
(Do we already have this somewhere else? If so, maybe move it to a
Support header in a separate commit, and then just reuse it.)
> +
> +#include <thread>
> +
> +using namespace llvm;
> +
> +static void codegen(Module *M, llvm::raw_pwrite_stream &OS,
> + const Target *TheTarget, StringRef CPU, StringRef Features,
> + const TargetOptions &Options, Reloc::Model RM,
> + CodeModel::Model CM, CodeGenOpt::Level OL) {
> + std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
> + M->getTargetTriple(), CPU, Features, Options, RM, CM, OL));
> +
> + legacy::PassManager CodeGenPasses;
> + if (TM->addPassesToEmitFile(CodeGenPasses, OS,
> + TargetMachine::CGFT_ObjectFile))
> + report_fatal_error("Failed to setup codegen");
> + CodeGenPasses.run(*M);
> +}
> +
> +std::unique_ptr<Module> llvm::LinkedCodeGen(
> + std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
> + StringRef CPU, StringRef Features, const TargetOptions &Options,
> + Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL) {
> + StringRef TripleStr = M->getTargetTriple();
> + std::string ErrMsg;
> + const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
> + if (!TheTarget)
> + report_fatal_error(Twine("Target not found: ") + ErrMsg);
> +
> + if (OSs.size() == 1) {
> + codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM,
> + OL);
> + return M;
> + }
> +
> + std::vector<std::thread> Threads;
> + SplitModule(std::move(M), OSs.size(), [&](std::unique_ptr<Module> MPart) {
> + std::string BC;
> + raw_string_ostream OS(BC);
Does `raw_svector_ostream` work here?
> + WriteBitcodeToFile(MPart.get(), OS);
> + OS.flush();
> +
> + Threads.emplace_back([=](llvm::raw_pwrite_stream *OS, StringRef BC) {
> + LLVMContext Ctx;
> + ErrorOr<std::unique_ptr<Module>> MOrErr =
> + parseBitcodeFile(MemoryBufferRef(BC, "<split-module>"), Ctx);
> + if (!MOrErr)
> + report_fatal_error("Failed to read bitcode");
> + std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
> +
> + codegen(MPartInCtx.get(), *OS, TheTarget, CPU, Features, Options, RM, CM,
> + OL);
> + }, OSs[Threads.size()], std::move(BC));
> + });
> +
> + for (std::thread &T : Threads)
> + T.join();
> +
> + return {};
> +}
> Index: include/llvm/CodeGen/Parallel.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/CodeGen/Parallel.h
> @@ -0,0 +1,41 @@
> +//===-- llvm/CodeGen/Parallel.h - Parallel code generation ------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This header declares functions that can be used for parallel code generation.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CODEGEN_PARALLEL_H
> +#define LLVM_CODEGEN_PARALLEL_H
> +
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/Support/CodeGen.h"
> +
> +namespace llvm {
> +
> +class Module;
> +class TargetOptions;
> +class raw_pwrite_stream;
> +
> +/// Split M into OSs.size() partitions, and generate code for each. Writes
> +/// OSs.size() object files to the output streams in OSs. The resulting object
> +/// files if linked together are intended to be equivalent to the single object
> +/// file that would have been code generated from M.
> +///
> +/// \returns M if OSs.size() == 1, otherwise returns std::unique_ptr<Module>().
> +std::unique_ptr<Module>
> +LinkedCodeGen(std::unique_ptr<Module> M, ArrayRef<raw_pwrite_stream *> OSs,
This name doesn't really make sense to me. Also, we use lowerCamelCase() for
functions these days. `splitCodeGen()` maybe? (You might do better.)
> + StringRef CPU, StringRef Features, const TargetOptions &Options,
> + Reloc::Model RM = Reloc::Default,
> + CodeModel::Model CM = CodeModel::Default,
> + CodeGenOpt::Level OL = CodeGenOpt::Default);
> +
> +} // namespace llvm
> +
> +#endif
More information about the llvm-commits
mailing list