[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