<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Nevermind, it seems that it needs to be std::list instead of std::vector. raw_svector_ostream has no copy constructor, but std::vector needs it when the vector is grown, so std::vector<raw_svector_ostream> doesn't compile.</div><div class="gmail_quote"><br></div><div class="gmail_quote">On Fri, Apr 15, 2016 at 4:46 PM, Davide Italiano <span dir="ltr"><<a href="mailto:davide@freebsd.org" target="_blank">davide@freebsd.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Fri, Apr 15, 2016 at 3:51 PM, Rui Ueyama <<a href="mailto:ruiu@google.com">ruiu@google.com</a>> wrote:<br>
> On Fri, Apr 15, 2016 at 3:38 PM, Davide Italiano via llvm-commits<br>
> <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br>
>><br>
>> Author: davide<br>
>> Date: Fri Apr 15 17:38:10 2016<br>
>> New Revision: 266484<br>
>><br>
>> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=266484&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=266484&view=rev</a><br>
>> Log:<br>
>> [LTO] Implement parallel Codegen for LTO using splitCodeGen.<br>
>><br>
>> Parallelism level can be chosen using the new --lto-jobs=K option<br>
>> where K is the number of threads used for CodeGen. It currently<br>
>> defaults to 1.<br>
>><br>
>> Added:<br>
>>     lld/trunk/test/ELF/lto/parallel.ll<br>
>> Modified:<br>
>>     lld/trunk/ELF/Config.h<br>
>>     lld/trunk/ELF/Driver.cpp<br>
>>     lld/trunk/ELF/LTO.cpp<br>
>>     lld/trunk/ELF/LTO.h<br>
>>     lld/trunk/ELF/Options.td<br>
>>     lld/trunk/ELF/SymbolTable.cpp<br>
>>     lld/trunk/test/ELF/basic.s<br>
>><br>
>> Modified: lld/trunk/ELF/Config.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/Config.h (original)<br>
>> +++ lld/trunk/ELF/Config.h Fri Apr 15 17:38:10 2016<br>
>> @@ -94,6 +94,7 @@ struct Configuration {<br>
>>    ELFKind EKind = ELFNoneKind;<br>
>>    uint16_t EMachine = llvm::ELF::EM_NONE;<br>
>>    uint64_t EntryAddr = -1;<br>
>> +  unsigned LtoJobs;<br>
>>    unsigned LtoO;<br>
>>    unsigned Optimize;<br>
>>  };<br>
>><br>
>> Modified: lld/trunk/ELF/Driver.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/Driver.cpp (original)<br>
>> +++ lld/trunk/ELF/Driver.cpp Fri Apr 15 17:38:10 2016<br>
>> @@ -321,6 +321,9 @@ void LinkerDriver::readConfigs(opt::Inpu<br>
>>    Config->LtoO = getInteger(Args, OPT_lto_O, 2);<br>
>>    if (Config->LtoO > 3)<br>
>>      error("invalid optimization level for LTO: " + getString(Args,<br>
>> OPT_lto_O));<br>
>> +  Config->LtoJobs = getInteger(Args, OPT_lto_jobs, 1);<br>
>> +  if (Config->LtoJobs == 0)<br>
>> +    error("number of threads must be > 0");<br>
>><br>
>>    Config->ZExecStack = hasZOption(Args, "execstack");<br>
>>    Config->ZNodelete = hasZOption(Args, "nodelete");<br>
>><br>
>> Modified: lld/trunk/ELF/LTO.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.cpp?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.cpp?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/LTO.cpp (original)<br>
>> +++ lld/trunk/ELF/LTO.cpp Fri Apr 15 17:38:10 2016<br>
>> @@ -16,6 +16,7 @@<br>
>>  #include "llvm/Analysis/TargetTransformInfo.h"<br>
>>  #include "llvm/Bitcode/ReaderWriter.h"<br>
>>  #include "llvm/CodeGen/CommandFlags.h"<br>
>> +#include "llvm/CodeGen/ParallelCG.h"<br>
>>  #include "llvm/IR/LegacyPassManager.h"<br>
>>  #include "llvm/Linker/IRMover.h"<br>
>>  #include "llvm/Support/StringSaver.h"<br>
>> @@ -33,10 +34,13 @@ using namespace lld;<br>
>>  using namespace lld::elf;<br>
>><br>
>>  // This is for use when debugging LTO.<br>
>> -static void saveLtoObjectFile(StringRef Buffer) {<br>
>> +static void saveLtoObjectFile(StringRef Buffer, unsigned I, bool Many) {<br>
>> +  SmallString<128> Filename = Config->OutputFile;<br>
>> +  if (Many)<br>
>> +    Filename += utostr(I);<br>
>> +  Filename += ".lto.o";<br>
>>    std::error_code EC;<br>
>> -  raw_fd_ostream OS(Config->OutputFile.str() + ".lto.o", EC,<br>
>> -                    sys::fs::OpenFlags::F_None);<br>
>> +  raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::F_None);<br>
>>    check(EC);<br>
>>    OS << Buffer;<br>
>>  }<br>
>> @@ -136,9 +140,36 @@ static void internalize(GlobalValue &GV)<br>
>>    GV.setLinkage(GlobalValue::InternalLinkage);<br>
>>  }<br>
>><br>
>> +std::vector<std::unique_ptr<InputFile>><br>
>> BitcodeCompiler::runSplitCodegen() {<br>
>> +  unsigned NumThreads = Config->LtoJobs;<br>
>> +  OwningData.resize(NumThreads);<br>
>> +<br>
>> +  std::list<raw_svector_ostream> OSs;<br>
>> +  std::vector<raw_pwrite_stream *> OSPtrs;<br>
><br>
><br>
> Is there any reason you used std::list instead of std::vector? I think<br>
> std::vector is generally preferred unless you really want to have a linked<br>
> list.<br>
><br>
<br>
</div></div>I just blatantly modeled this after the gold plugin does.<br>
If we want to change it, we might want to change it everywhere.<br>
<div class="HOEnZb"><div class="h5"><br>
>><br>
>> +  for (SmallString<0> &Obj : OwningData) {<br>
>> +    OSs.emplace_back(Obj);<br>
>> +    OSPtrs.push_back(&OSs.back());<br>
>> +  }<br>
>> +<br>
>> +  splitCodeGen(std::move(Combined), OSPtrs, {},<br>
>> +               [this]() { return getTargetMachine(); });<br>
>> +<br>
>> +  std::vector<std::unique_ptr<InputFile>> ObjFiles;<br>
>> +  for (SmallString<0> &Obj : OwningData)<br>
>> +    ObjFiles.push_back(createObjectFile(<br>
>> +        MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object")));<br>
>> +<br>
>> +  if (Config->SaveTemps)<br>
>> +    for (unsigned I = 0; I < NumThreads; ++I)<br>
>> +      saveLtoObjectFile(OwningData[I], I, NumThreads > 1);<br>
>> +<br>
>> +  return ObjFiles;<br>
>> +}<br>
>> +<br>
>>  // Merge all the bitcode files we have seen, codegen the result<br>
>>  // and return the resulting ObjectFile.<br>
>> -std::unique_ptr<InputFile> BitcodeCompiler::compile() {<br>
>> +std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::compile() {<br>
>> +  TheTriple = Combined->getTargetTriple();<br>
>>    for (const auto &Name : InternalizedSyms) {<br>
>>      GlobalValue *GV = Combined->getNamedValue(Name.first());<br>
>>      assert(GV);<br>
>> @@ -151,26 +182,16 @@ std::unique_ptr<InputFile> BitcodeCompil<br>
>>    std::unique_ptr<TargetMachine> TM(getTargetMachine());<br>
>>    runLTOPasses(*Combined, *TM);<br>
>><br>
>> -  raw_svector_ostream OS(OwningData);<br>
>> -  legacy::PassManager CodeGenPasses;<br>
>> -  if (TM->addPassesToEmitFile(CodeGenPasses, OS,<br>
>> -                              TargetMachine::CGFT_ObjectFile))<br>
>> -    fatal("failed to setup codegen");<br>
>> -  CodeGenPasses.run(*Combined);<br>
>> -  MB = MemoryBuffer::getMemBuffer(OwningData,<br>
>> -                                  "LLD-INTERNAL-combined-lto-object",<br>
>> false);<br>
>> -  if (Config->SaveTemps)<br>
>> -    saveLtoObjectFile(MB->getBuffer());<br>
>> -  return createObjectFile(*MB);<br>
>> +  return runSplitCodegen();<br>
>>  }<br>
>><br>
>> -TargetMachine *BitcodeCompiler::getTargetMachine() {<br>
>> -  StringRef TripleStr = Combined->getTargetTriple();<br>
>> +std::unique_ptr<TargetMachine> BitcodeCompiler::getTargetMachine() {<br>
>>    std::string Msg;<br>
>> -  const Target *T = TargetRegistry::lookupTarget(TripleStr, Msg);<br>
>> +  const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg);<br>
>>    if (!T)<br>
>>      fatal("target not found: " + Msg);<br>
>>    TargetOptions Options = InitTargetOptionsFromCodeGenFlags();<br>
>>    Reloc::Model R = Config->Pic ? Reloc::PIC_ : Reloc::Static;<br>
>> -  return T->createTargetMachine(TripleStr, "", "", Options, R);<br>
>> +  return std::unique_ptr<TargetMachine>(<br>
>> +      T->createTargetMachine(TheTriple, "", "", Options, R));<br>
>>  }<br>
>><br>
>> Modified: lld/trunk/ELF/LTO.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.h?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.h?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/LTO.h (original)<br>
>> +++ lld/trunk/ELF/LTO.h Fri Apr 15 17:38:10 2016<br>
>> @@ -37,20 +37,22 @@ class InputFile;<br>
>>  class BitcodeCompiler {<br>
>>  public:<br>
>>    void add(BitcodeFile &F);<br>
>> -  std::unique_ptr<InputFile> compile();<br>
>> +  std::vector<std::unique_ptr<InputFile>> compile();<br>
>><br>
>>    BitcodeCompiler()<br>
>>        : Combined(new llvm::Module("ld-temp.o", Context)),<br>
>> Mover(*Combined) {}<br>
>><br>
>>  private:<br>
>> -  llvm::TargetMachine *getTargetMachine();<br>
>> +  std::vector<std::unique_ptr<InputFile>> runSplitCodegen();<br>
>> +  std::unique_ptr<llvm::TargetMachine> getTargetMachine();<br>
>><br>
>>    llvm::LLVMContext Context;<br>
>>    std::unique_ptr<llvm::Module> Combined;<br>
>>    llvm::IRMover Mover;<br>
>> -  SmallString<0> OwningData;<br>
>> +  std::vector<SmallString<0>> OwningData;<br>
>>    std::unique_ptr<MemoryBuffer> MB;<br>
>>    llvm::StringSet<> InternalizedSyms;<br>
>> +  std::string TheTriple;<br>
>>  };<br>
>>  }<br>
>>  }<br>
>><br>
>> Modified: lld/trunk/ELF/Options.td<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/Options.td (original)<br>
>> +++ lld/trunk/ELF/Options.td Fri Apr 15 17:38:10 2016<br>
>> @@ -237,7 +237,9 @@ def G : Separate<["-"], "G">;<br>
>>  // Aliases for ignored options<br>
>>  def alias_version_script_version_script : Joined<["--"],<br>
>> "version-script=">, Alias<version_script>;<br>
>><br>
>> -// Debugging/developer options<br>
>> +// LTO-related options.<br>
>> +def lto_jobs : Joined<["--"], "lto-jobs=">,<br>
>> +  HelpText<"Number of threads to run codegen">;<br>
>>  def disable_verify : Flag<["-"], "disable-verify">;<br>
>>  def mllvm : Separate<["-"], "mllvm">;<br>
>>  def save_temps : Flag<["-"], "save-temps">;<br>
>><br>
>> Modified: lld/trunk/ELF/SymbolTable.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/ELF/SymbolTable.cpp (original)<br>
>> +++ lld/trunk/ELF/SymbolTable.cpp Fri Apr 15 17:38:10 2016<br>
>> @@ -122,24 +122,27 @@ template <class ELFT> void SymbolTable<E<br>
>>    Lto.reset(new BitcodeCompiler);<br>
>>    for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles)<br>
>>      Lto->add(*F);<br>
>> -  std::unique_ptr<InputFile> IF = Lto->compile();<br>
>> -  ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());<br>
>> +  std::vector<std::unique_ptr<InputFile>> IFs = Lto->compile();<br>
>><br>
>>    // Replace bitcode symbols.<br>
>> -  llvm::DenseSet<StringRef> DummyGroups;<br>
>> -  Obj->parse(DummyGroups);<br>
>> -  for (SymbolBody *Body : Obj->getNonLocalSymbols()) {<br>
>> -    Symbol *Sym = insert(Body);<br>
>> -    Sym->Body->setUsedInRegularObj();<br>
>> -    if (Sym->Body->isShared())<br>
>> -      Sym->Body->MustBeInDynSym = true;<br>
>> -    if (Sym->Body->MustBeInDynSym)<br>
>> -      Body->MustBeInDynSym = true;<br>
>> -    if (!Sym->Body->isUndefined() && Body->isUndefined())<br>
>> -      continue;<br>
>> -    Sym->Body = Body;<br>
>> +  for (auto &IF : IFs) {<br>
>> +    ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());<br>
>> +<br>
>> +    llvm::DenseSet<StringRef> DummyGroups;<br>
>> +    Obj->parse(DummyGroups);<br>
>> +    for (SymbolBody *Body : Obj->getNonLocalSymbols()) {<br>
>> +      Symbol *Sym = insert(Body);<br>
>> +      Sym->Body->setUsedInRegularObj();<br>
>> +      if (Sym->Body->isShared())<br>
>> +        Sym->Body->MustBeInDynSym = true;<br>
>> +      if (Sym->Body->MustBeInDynSym)<br>
>> +        Body->MustBeInDynSym = true;<br>
>> +      if (!Sym->Body->isUndefined() && Body->isUndefined())<br>
>> +        continue;<br>
>> +      Sym->Body = Body;<br>
>> +    }<br>
>> +    ObjectFiles.emplace_back(Obj);<br>
>>    }<br>
>> -  ObjectFiles.emplace_back(Obj);<br>
>>  }<br>
>><br>
>>  // Add an undefined symbol.<br>
>><br>
>> Modified: lld/trunk/test/ELF/basic.s<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/basic.s?rev=266484&r1=266483&r2=266484&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/basic.s?rev=266484&r1=266483&r2=266484&view=diff</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/test/ELF/basic.s (original)<br>
>> +++ lld/trunk/test/ELF/basic.s Fri Apr 15 17:38:10 2016<br>
>> @@ -214,3 +214,6 @@ _start:<br>
>><br>
>>  # RUN: not ld.lld %t -o %t -m wrong_emul 2>&1 | FileCheck<br>
>> --check-prefix=UNKNOWN_EMUL %s<br>
>>  # UNKNOWN_EMUL: unknown emulation: wrong_emul<br>
>> +<br>
>> +# RUN: not ld.lld %t --lto-jobs=0 2>&1 | FileCheck<br>
>> --check-prefix=NOTHREADS %s<br>
>> +# NOTHREADS: number of threads must be > 0<br>
>><br>
>> Added: lld/trunk/test/ELF/lto/parallel.ll<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/parallel.ll?rev=266484&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/parallel.ll?rev=266484&view=auto</a><br>
>><br>
>> ==============================================================================<br>
>> --- lld/trunk/test/ELF/lto/parallel.ll (added)<br>
>> +++ lld/trunk/test/ELF/lto/parallel.ll Fri Apr 15 17:38:10 2016<br>
>> @@ -0,0 +1,22 @@<br>
>> +; RUN: llvm-as -o %t.bc %s<br>
>> +; RUN: ld.lld -m elf_x86_64 --lto-jobs=2 -save-temps -o %t %t.bc -shared<br>
>> +; RUN: llvm-nm %t0.lto.o | FileCheck --check-prefix=CHECK0 %s<br>
>> +; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s<br>
>> +<br>
>> +target triple = "x86_64-unknown-linux-gnu"<br>
>> +<br>
>> +; CHECK0-NOT: bar<br>
>> +; CHECK0: T foo<br>
>> +; CHECK0-NOT: bar<br>
>> +define void @foo() {<br>
>> +  call void @bar()<br>
>> +  ret void<br>
>> +}<br>
>> +<br>
>> +; CHECK1-NOT: foo<br>
>> +; CHECK1: T bar<br>
>> +; CHECK1-NOT: foo<br>
>> +define void @bar() {<br>
>> +  call void @foo()<br>
>> +  ret void<br>
>> +}<br>
>><br>
>><br>
>> _______________________________________________<br>
>> llvm-commits mailing list<br>
>> <a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
>> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
><br>
><br>
<br>
<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
Davide<br>
<br>
"There are no solved problems; there are only problems that are more<br>
or less solved" -- Henri Poincare<br>
</font></span></blockquote></div><br></div></div>