<div dir="ltr">Yup, that's an idea I want to try to implement.</div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Sep 4, 2015 at 5:33 PM, Sean Silva <span dir="ltr"><<a href="mailto:chisophugis@gmail.com" target="_blank">chisophugis@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Fri, Sep 4, 2015 at 2:35 PM, Rui Ueyama via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ruiu<br>
Date: Fri Sep  4 16:35:54 2015<br>
New Revision: 246878<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=246878&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=246878&view=rev</a><br>
Log:<br>
COFF: Implement a better algorithm for ICF.<br>
<br>
Identical COMDAT Folding is a feature to merge COMDAT sections<br>
by contents. Two sections are considered the same if their contents,<br>
relocations, attributes, etc, are all the same.<br>
<br>
An interesting fact is that MSVC linker takes "iterations" parameter<br>
for ICF because the algorithm they are using is iterative. Merging<br>
two sections could make more sections to be mergeable because<br>
different relocations could now point to the same section. ICF is<br>
repeated until we get a convergence (until no section can be merged).<br>
This algorithm is not fast. Usually it needs three iterations until a<br>
convergence is obtained.<br>
<br>
In the new algorithm implemented in this patch, we consider sections<br>
and relocations as a directed acyclic graph, and we try to merge<br>
sections whose outdegree is zero. Sections with outdegree zero are then<br>
removed from the graph, which makes  other sections to have outdegree<br>
zero. We repeat that until all sections are processed. In this<br>
algorithm, we don't iterate over the same sections many times.<br>
<br>
There's an apparent issue in the algorithm -- the section graph is<br>
not guaranteed to be acyclic. It's actually pretty often cyclic.<br>
So this algorithm cannot eliminate all possible duplicates.<br>
That's OK for now because the previous algorithm was not able to<br>
eliminate cycles too. I'll address the issue in a follow-up patch.<br></blockquote><div><br></div></div></div><div>If you collapse SCC's, then the graph is guaranteed to be acyclic. Then you only need to solve how to compare SCC's.</div><span class="HOEnZb"><font color="#888888"><div><br></div><div>-- Sean Silva</div></font></span><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Modified:<br>
    lld/trunk/COFF/Chunks.h<br>
    lld/trunk/COFF/ICF.cpp<br>
<br>
Modified: lld/trunk/COFF/Chunks.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=246878&r1=246877&r2=246878&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=246878&r1=246877&r2=246878&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Chunks.h (original)<br>
+++ lld/trunk/COFF/Chunks.h Fri Sep  4 16:35:54 2015<br>
@@ -182,6 +182,8 @@ public:<br>
   // with other chunk by ICF, it points to another chunk,<br>
   // and this chunk is considrered as dead.<br>
   SectionChunk *Ptr;<br>
+  int Outdegree = 0;<br>
+  std::vector<SectionChunk *> Ins;<br>
<br>
   // The CRC of the contents as described in the COFF spec 4.5.5.<br>
   // Auxiliary Format 5: Section Definitions. Used for ICF.<br>
<br>
Modified: lld/trunk/COFF/ICF.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/ICF.cpp?rev=246878&r1=246877&r2=246878&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/ICF.cpp?rev=246878&r1=246877&r2=246878&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/ICF.cpp (original)<br>
+++ lld/trunk/COFF/ICF.cpp Fri Sep  4 16:35:54 2015<br>
@@ -90,31 +90,53 @@ bool SectionChunk::equals(const SectionC<br>
   return std::equal(Relocs.begin(), Relocs.end(), X->Relocs.begin(), Eq);<br>
 }<br>
<br>
+static void link(SectionChunk *From, SectionChunk *To) {<br>
+  ++From->Outdegree;<br>
+  To->Ins.push_back(From);<br>
+}<br>
+<br>
 // Merge identical COMDAT sections.<br>
-// Two sections are considered as identical when their section headers,<br>
+// Two sections are considered the same if their section headers,<br>
 // contents and relocations are all the same.<br>
 void doICF(const std::vector<Chunk *> &Chunks) {<br>
-  std::unordered_set<SectionChunk *, Hasher, Equals> Set;<br>
-  bool Redo;<br>
-  do {<br>
-    Set.clear();<br>
-    Redo = false;<br>
-    for (Chunk *C : Chunks) {<br>
-      auto *SC = dyn_cast<SectionChunk>(C);<br>
-      if (!SC || !SC->isCOMDAT() || !SC->isLive())<br>
-        continue;<br>
+  std::vector<SectionChunk *> SChunks;<br>
+  for (Chunk *C : Chunks)<br>
+    if (auto *SC = dyn_cast<SectionChunk>(C))<br>
+      if (SC->isCOMDAT() && SC->isLive())<br>
+        SChunks.push_back(SC);<br>
+<br>
+  // Initialize SectionChunks' outdegrees and in-chunk lists.<br>
+  for (SectionChunk *SC : SChunks) {<br>
+    for (SectionChunk *C : SC->children())<br>
+      link(SC, C);<br>
+    for (SymbolBody *B : SC->symbols())<br>
+      if (auto *D = dyn_cast<DefinedRegular>(B))<br>
+        link(SC, D->getChunk());<br>
+  }<br>
+<br>
+  // By merging two sections, more sections can become mergeable<br>
+  // because two originally different relocations can now point to<br>
+  // the same section. We process sections whose outdegree is zero<br>
+  // first to deal with that.<br>
+  for (;;) {<br>
+    std::unordered_set<SectionChunk *, Hasher, Equals> Set;<br>
+    auto Pred = [](SectionChunk *SC) { return SC->Outdegree > 0; };<br>
+    auto Bound = std::partition(SChunks.begin(), SChunks.end(), Pred);<br>
+    if (Bound == SChunks.end())<br>
+      return;<br>
+    for (auto It = Bound, E = SChunks.end(); It != E; ++It) {<br>
+      SectionChunk *SC = *It;<br>
       auto P = Set.insert(SC);<br>
       bool Inserted = P.second;<br>
       if (Inserted)<br>
         continue;<br>
       SectionChunk *Existing = *P.first;<br>
       SC->replaceWith(Existing);<br>
-      // By merging sections, two relocations that originally pointed to<br>
-      // different locations can now point to the same location.<br>
-      // So, repeat the process until a convegence is obtained.<br>
-      Redo = true;<br>
+      for (SectionChunk *In : SC->Ins)<br>
+        --In->Outdegree;<br>
     }<br>
-  } while (Redo);<br>
+    SChunks.erase(Bound, SChunks.end());<br>
+  }<br>
 }<br>
<br>
 } // namespace coff<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">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>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div>