//===- ICF.cpp ------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // ICF is short for Identical Code Folding. This is a size optimization to // identify and merge two or more read-only sections (typically functions) // that happened to have the same contents. It usually reduces output size // by a few percent. // // In ICF, two sections are considered identical if they have the same // section flags, section data, and relocations. Relocations are tricky, // because two relocations are considered the same if they have the same // relocation types, values, and if they point to the same sections *in // terms of ICF*. // // Here is an example. If foo and bar defined below are compiled to the // same machine instructions, ICF can and should merge the two, although // their relocations point to each other. // // void foo() { bar(); } // void bar() { foo(); } // // If you merge the two, their relocations point to the same section and // thus you know they are mergeable, but how do you know they are // mergeable in the first place? This is not an easy problem to solve. // // What we are doing in LLD is to partition sections into equivalence // classes. Sections in the same equivalence class when the algorithm // terminates are considered identical. Here are details: // // 1. First, we partition sections using their hash values as keys. Hash // values contain section types, section contents and numbers of // relocations. During this step, relocation targets are not taken into // account. We just put sections that apparently differ into different // equivalence classes. // // 2. Next, for each equivalence class, we visit sections to compare // relocation targets. Relocation targets are considered equivalent if // their targets are in the same equivalence class. Sections with // different relocation targets are put into different equivalence // classes. // // 3. If we split an equivalence class in step 2, two relocations // previously target the same equivalence class may now target // different equivalence classes. Therefore, we repeat step 2 until a // convergence is obtained. // // 4. For each equivalence class C, pick an arbitrary section in C, and // merge all the other sections in C with it. // // For small programs, this algorithm needs 3-5 iterations. For large // programs such as Chromium, it takes more than 20 iterations. // // This algorithm was mentioned as an "optimistic algorithm" in [1], // though gold implements a different algorithm than this. // // We parallelize each step so that multiple threads can work on different // equivalence classes concurrently. That gave us a large performance // boost when applying ICF on large programs. For example, MSVC link.exe // or GNU gold takes 10-20 seconds to apply ICF on Chromium, whose output // size is about 1.5 GB, but LLD can finish it in less than 2 seconds on a // 2.8 GHz 40 core machine. Even without threading, LLD's ICF is still // faster than MSVC or gold though. // // [1] Safe ICF: Pointer Safe and Unwinding aware Identical Code Folding // in the Gold Linker // http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf // //===----------------------------------------------------------------------===// #include "ICF.h" #include "Config.h" #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/xxhash.h" #include <algorithm> #include <atomic> usingnamespacellvm; usingnamespacellvm::ELF; usingnamespacellvm::object; usingnamespacelld; usingnamespacelld::elf; namespace { template <class ELFT> class ICF { … }; } // Returns true if section S is subject of ICF. static bool isEligible(InputSection *s) { … } // Split an equivalence class into smaller classes. template <class ELFT> void ICF<ELFT>::segregate(size_t begin, size_t end, uint32_t eqClassBase, bool constant) { … } // Compare two lists of relocations. template <class ELFT> template <class RelTy> bool ICF<ELFT>::constantEq(const InputSection *secA, Relocs<RelTy> ra, const InputSection *secB, Relocs<RelTy> rb) { … } // Compare "non-moving" part of two InputSections, namely everything // except relocation targets. template <class ELFT> bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) { … } // Compare two lists of relocations. Returns true if all pairs of // relocations point to the same section in terms of ICF. template <class ELFT> template <class RelTy> bool ICF<ELFT>::variableEq(const InputSection *secA, Relocs<RelTy> ra, const InputSection *secB, Relocs<RelTy> rb) { … } // Compare "moving" part of two InputSections, namely relocation targets. template <class ELFT> bool ICF<ELFT>::equalsVariable(const InputSection *a, const InputSection *b) { … } template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t begin, size_t end) { … } // Sections in the same equivalence class are contiguous in Sections // vector. Therefore, Sections vector can be considered as contiguous // groups of sections, grouped by the class. // // This function calls Fn on every group within [Begin, End). template <class ELFT> void ICF<ELFT>::forEachClassRange(size_t begin, size_t end, llvm::function_ref<void(size_t, size_t)> fn) { … } // Call Fn on each equivalence class. template <class ELFT> void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) { … } // Combine the hashes of the sections referenced by the given section into its // hash. template <class RelTy> static void combineRelocHashes(unsigned cnt, InputSection *isec, Relocs<RelTy> rels) { … } static void print(const Twine &s) { … } // The main function of ICF. template <class ELFT> void ICF<ELFT>::run() { … } // ICF entry point function. template <class ELFT> void elf::doIcf() { … } template void elf::doIcf<ELF32LE>(); template void elf::doIcf<ELF32BE>(); template void elf::doIcf<ELF64LE>(); template void elf::doIcf<ELF64BE>();