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