[lld] r301709 - Revert r301678: Remove LinkerScript::flush.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 28 15:40:59 PDT 2017


Author: ruiu
Date: Fri Apr 28 17:40:58 2017
New Revision: 301709

URL: http://llvm.org/viewvc/llvm-project?rev=301709&view=rev
Log:
Revert r301678: Remove LinkerScript::flush.

This reverts commit r301678 since that change significantly slowed
down the linker. Before this patch, LLD could link clang in 8 seconds,
but with this patch it took 40 seconds.

Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=301709&r1=301708&r2=301709&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Fri Apr 28 17:40:58 2017
@@ -475,15 +475,10 @@ void LinkerScript::addOrphanSections(Out
             return Cmd->Name == Name;
           return false;
         });
-    if (I == Opt.Commands.end()) {
+    if (I == Opt.Commands.end())
       Factory.addInputSec(S, Name);
-    } else {
-      auto *Cmd = cast<OutputSectionCommand>(*I);
-      Factory.addInputSec(S, Name, Cmd->Sec);
-      auto *ISD = make<InputSectionDescription>("");
-      ISD->Sections.push_back(S);
-      Cmd->Commands.push_back(ISD);
-    }
+    else
+      Factory.addInputSec(S, Name, cast<OutputSectionCommand>(*I)->Sec);
   }
 }
 
@@ -492,6 +487,8 @@ static bool isTbss(OutputSection *Sec) {
 }
 
 void LinkerScript::output(InputSection *S) {
+  if (!AlreadyOutputIS.insert(S).second)
+    return;
   bool IsTbss = isTbss(CurOutSec);
 
   uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
@@ -523,9 +520,19 @@ void LinkerScript::output(InputSection *
     Dot = Pos;
 }
 
+void LinkerScript::flush() {
+  assert(CurOutSec);
+  if (!AlreadyOutputOS.insert(CurOutSec).second)
+    return;
+  for (InputSection *I : CurOutSec->Sections)
+    output(I);
+}
+
 void LinkerScript::switchTo(OutputSection *Sec) {
   if (CurOutSec == Sec)
     return;
+  if (AlreadyOutputOS.count(Sec))
+    return;
 
   CurOutSec = Sec;
 
@@ -576,7 +583,7 @@ void LinkerScript::process(BaseCommand &
 
     if (!Sec->Live)
       continue;
-    assert(CurOutSec == Sec->OutSec);
+    assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec));
     output(cast<InputSection>(Sec));
   }
 }
@@ -635,8 +642,19 @@ void LinkerScript::assignOffsets(OutputS
     Dot = CurMemRegion->Offset;
   switchTo(Sec);
 
-  for (BaseCommand *C : Cmd->Commands)
-    process(*C);
+  // flush() may add orphan sections, so the order of flush() and
+  // symbol assignments is important. We want to call flush() first so
+  // that symbols pointing the end of the current section points to
+  // the location after orphan sections.
+  auto Mid =
+      std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+                   [](BaseCommand *Cmd) { return !isa<SymbolAssignment>(Cmd); })
+          .base();
+  for (auto I = Cmd->Commands.begin(); I != Mid; ++I)
+    process(**I);
+  flush();
+  for (auto I = Mid, E = Cmd->Commands.end(); I != E; ++I)
+    process(**I);
 }
 
 void LinkerScript::removeEmptyCommands() {
@@ -806,24 +824,15 @@ void LinkerScript::placeOrphanSections()
       ++CmdIndex;
     }
 
-    // If there is no command corresponding to this output section,
-    // create one and put a InputSectionDescription in it so that both
-    // representations agree on which input sections to use.
     auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) {
       auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
       return Cmd && Cmd->Name == Name;
     });
     if (Pos == E) {
       auto *Cmd = make<OutputSectionCommand>(Name);
+      Cmd->Sec = Sec;
       Opt.Commands.insert(CmdIter, Cmd);
       ++CmdIndex;
-
-      Cmd->Sec = Sec;
-      auto *ISD = make<InputSectionDescription>("");
-      for (InputSection *IS : Sec->Sections)
-        ISD->Sections.push_back(IS);
-      Cmd->Commands.push_back(ISD);
-
       continue;
     }
 
@@ -841,49 +850,6 @@ void LinkerScript::processNonSectionComm
   }
 }
 
-// Do a last effort at synchronizing the linker script "AST" and the section
-// list. This is needed to account for last minute changes, like adding a
-// .ARM.exidx terminator and sorting SHF_LINK_ORDER sections.
-//
-// FIXME: We should instead create the "AST" earlier and the above changes would
-// be done directly in the "AST".
-//
-// This can only handle new sections being added and sections being reordered.
-void LinkerScript::synchronize() {
-  for (BaseCommand *Base : Opt.Commands) {
-    auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
-    if (!Cmd)
-      continue;
-    ArrayRef<InputSection *> Sections = Cmd->Sec->Sections;
-    std::vector<InputSectionBase **> ScriptSections;
-    for (BaseCommand *Base : Cmd->Commands) {
-      auto *ISD = dyn_cast<InputSectionDescription>(Base);
-      if (!ISD)
-        continue;
-      for (InputSectionBase *&IS : ISD->Sections)
-        if (IS->Live)
-          ScriptSections.push_back(&IS);
-    }
-    std::vector<InputSectionBase *> Missing;
-    for (InputSection *IS : Sections)
-      if (std::find_if(ScriptSections.begin(), ScriptSections.end(),
-                       [=](InputSectionBase **Base) { return *Base == IS; }) ==
-          ScriptSections.end())
-        Missing.push_back(IS);
-    if (!Missing.empty()) {
-      auto ISD = make<InputSectionDescription>("");
-      ISD->Sections = Missing;
-      Cmd->Commands.push_back(ISD);
-      for (InputSectionBase *&IS : ISD->Sections)
-        if (IS->Live)
-          ScriptSections.push_back(&IS);
-    }
-    assert(ScriptSections.size() == Sections.size());
-    for (int I = 0, N = Sections.size(); I < N; ++I)
-      *ScriptSections[I] = Sections[I];
-  }
-}
-
 void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
   // Assign addresses as instructed by linker script SECTIONS sub-commands.
   Dot = 0;

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=301709&r1=301708&r2=301709&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Fri Apr 28 17:40:58 2017
@@ -228,6 +228,7 @@ protected:
   MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
 
   void switchTo(OutputSection *Sec);
+  void flush();
   void output(InputSection *Sec);
   void process(BaseCommand &Base);
 
@@ -241,6 +242,9 @@ protected:
   OutputSection *CurOutSec = nullptr;
   MemoryRegion *CurMemRegion = nullptr;
 
+  llvm::DenseSet<OutputSection *> AlreadyOutputOS;
+  llvm::DenseSet<InputSectionBase *> AlreadyOutputIS;
+
 public:
   bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
   uint64_t getDot() { return Dot; }
@@ -267,7 +271,6 @@ public:
   void assignOffsets(OutputSectionCommand *Cmd);
   void placeOrphanSections();
   void processNonSectionCommands();
-  void synchronize();
   void assignAddresses(std::vector<PhdrEntry> &Phdrs);
   int getSectionIndex(StringRef Name);
 

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=301709&r1=301708&r2=301709&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Apr 28 17:40:58 2017
@@ -254,7 +254,6 @@ template <class ELFT> void Writer<ELFT>:
       fixSectionAlignments();
       Script->fabricateDefaultCommands(Config->MaxPageSize);
     }
-    Script->synchronize();
     Script->assignAddresses(Phdrs);
 
     // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
@@ -1081,7 +1080,6 @@ static void removeUnusedSyntheticSection
 
     SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(),
                                          SS->OutSec->Sections.end(), SS));
-    SS->Live = false;
     // If there are no other sections in the output section, remove it from the
     // output.
     if (SS->OutSec->Sections.empty())




More information about the llvm-commits mailing list