| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 1 | //===- ICF.cpp ------------------------------------------------------------===// | 
|  | 2 | // | 
|  | 3 | //                             The LLVM Linker | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 10 | // ICF is short for Identical Code Folding. That is a size optimization to | 
|  | 11 | // identify and merge two or more read-only sections (typically functions) | 
|  | 12 | // that happened to have the same contents. It usually reduces output size | 
|  | 13 | // by a few percent. | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 14 | // | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 15 | // On Windows, ICF is enabled by default. | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 16 | // | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 17 | // See ELF/ICF.cpp for the details about the algortihm. | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 18 | // | 
|  | 19 | //===----------------------------------------------------------------------===// | 
|  | 20 |  | 
|  | 21 | #include "Chunks.h" | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 22 | #include "Error.h" | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 23 | #include "Symbols.h" | 
| Rui Ueyama | aa95e5a | 2015-09-18 21:06:34 +0000 | [diff] [blame] | 24 | #include "lld/Core/Parallel.h" | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 25 | #include "llvm/ADT/Hashing.h" | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 26 | #include "llvm/Support/Debug.h" | 
|  | 27 | #include "llvm/Support/raw_ostream.h" | 
|  | 28 | #include <algorithm> | 
| Rui Ueyama | e629a45 | 2015-09-18 22:31:15 +0000 | [diff] [blame] | 29 | #include <atomic> | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 30 | #include <vector> | 
|  | 31 |  | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 32 | using namespace llvm; | 
|  | 33 |  | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 34 | namespace lld { | 
|  | 35 | namespace coff { | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 36 |  | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 37 | class ICF { | 
|  | 38 | public: | 
| Rui Ueyama | e8d1c59 | 2015-09-18 21:17:44 +0000 | [diff] [blame] | 39 | void run(const std::vector<Chunk *> &V); | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 40 |  | 
|  | 41 | private: | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 42 | void segregate(size_t Begin, size_t End, bool Constant); | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 43 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 44 | bool equalsConstant(const SectionChunk *A, const SectionChunk *B); | 
|  | 45 | bool equalsVariable(const SectionChunk *A, const SectionChunk *B); | 
|  | 46 |  | 
|  | 47 | uint32_t getHash(SectionChunk *C); | 
|  | 48 | bool isEligible(SectionChunk *C); | 
|  | 49 |  | 
|  | 50 | size_t findBoundary(size_t Begin, size_t End); | 
|  | 51 |  | 
|  | 52 | void forEachColorRange(size_t Begin, size_t End, | 
|  | 53 | std::function<void(size_t, size_t)> Fn); | 
|  | 54 |  | 
|  | 55 | void forEachColor(std::function<void(size_t, size_t)> Fn); | 
|  | 56 |  | 
|  | 57 | std::vector<SectionChunk *> Chunks; | 
|  | 58 | int Cnt = 0; | 
|  | 59 | std::atomic<uint32_t> NextId = {1}; | 
|  | 60 | std::atomic<bool> Repeat = {false}; | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 61 | }; | 
|  | 62 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 63 | // Returns a hash value for S. | 
|  | 64 | uint32_t ICF::getHash(SectionChunk *C) { | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 65 | return hash_combine(C->getPermissions(), | 
|  | 66 | hash_value(C->SectionName), | 
|  | 67 | C->NumRelocs, | 
| Rui Ueyama | 548d22c | 2015-09-25 16:50:12 +0000 | [diff] [blame] | 68 | C->getAlign(), | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 69 | uint32_t(C->Header->SizeOfRawData), | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 70 | C->Checksum); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 71 | } | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 72 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 73 | // Returns true if section S is subject of ICF. | 
|  | 74 | bool ICF::isEligible(SectionChunk *C) { | 
|  | 75 | bool Global = C->Sym && C->Sym->isExternal(); | 
|  | 76 | bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; | 
|  | 77 | return C->isCOMDAT() && C->isLive() && Global && !Writable; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | // Split a range into smaller ranges by recoloring sections | 
|  | 81 | void ICF::segregate(size_t Begin, size_t End, bool Constant) { | 
|  | 82 | while (Begin < End) { | 
|  | 83 | // Divide [Begin, End) into two. Let Mid be the start index of the | 
|  | 84 | // second group. | 
|  | 85 | auto Bound = std::stable_partition( | 
|  | 86 | Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { | 
|  | 87 | if (Constant) | 
|  | 88 | return equalsConstant(Chunks[Begin], S); | 
|  | 89 | return equalsVariable(Chunks[Begin], S); | 
|  | 90 | }); | 
|  | 91 | size_t Mid = Bound - Chunks.begin(); | 
|  | 92 |  | 
|  | 93 | // Split [Begin, End) into [Begin, Mid) and [Mid, End). | 
|  | 94 | uint32_t Id = NextId++; | 
|  | 95 | for (size_t I = Begin; I < Mid; ++I) | 
|  | 96 | Chunks[I]->Color[(Cnt + 1) % 2] = Id; | 
|  | 97 |  | 
|  | 98 | // If we created a group, we need to iterate the main loop again. | 
|  | 99 | if (Mid != End) | 
|  | 100 | Repeat = true; | 
|  | 101 |  | 
|  | 102 | Begin = Mid; | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 103 | } | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 104 | } | 
|  | 105 |  | 
|  | 106 | // Compare "non-moving" part of two sections, namely everything | 
|  | 107 | // except relocation targets. | 
|  | 108 | bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { | 
|  | 109 | if (A->NumRelocs != B->NumRelocs) | 
|  | 110 | return false; | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 111 |  | 
| Rui Ueyama | 7d8263b | 2015-09-18 01:30:56 +0000 | [diff] [blame] | 112 | // Compare relocations. | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 113 | auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 114 | if (R1.Type != R2.Type || | 
|  | 115 | R1.VirtualAddress != R2.VirtualAddress) { | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 116 | return false; | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 117 | } | 
|  | 118 | SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); | 
|  | 119 | SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 120 | if (B1 == B2) | 
|  | 121 | return true; | 
| Rui Ueyama | 603d511 | 2015-09-18 02:40:54 +0000 | [diff] [blame] | 122 | if (auto *D1 = dyn_cast<DefinedRegular>(B1)) | 
|  | 123 | if (auto *D2 = dyn_cast<DefinedRegular>(B2)) | 
|  | 124 | return D1->getValue() == D2->getValue() && | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 125 | D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2]; | 
| Rui Ueyama | 603d511 | 2015-09-18 02:40:54 +0000 | [diff] [blame] | 126 | return false; | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 127 | }; | 
| Rui Ueyama | 7d8263b | 2015-09-18 01:30:56 +0000 | [diff] [blame] | 128 | if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) | 
|  | 129 | return false; | 
|  | 130 |  | 
| Rui Ueyama | 603d511 | 2015-09-18 02:40:54 +0000 | [diff] [blame] | 131 | // Compare section attributes and contents. | 
|  | 132 | return A->getPermissions() == B->getPermissions() && | 
|  | 133 | A->SectionName == B->SectionName && | 
| Rui Ueyama | 548d22c | 2015-09-25 16:50:12 +0000 | [diff] [blame] | 134 | A->getAlign() == B->getAlign() && | 
| Rui Ueyama | 603d511 | 2015-09-18 02:40:54 +0000 | [diff] [blame] | 135 | A->Header->SizeOfRawData == B->Header->SizeOfRawData && | 
|  | 136 | A->Checksum == B->Checksum && | 
|  | 137 | A->getContents() == B->getContents(); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 138 | } | 
|  | 139 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 140 | // Compare "moving" part of two sections, namely relocation targets. | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 141 | bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { | 
| Rui Ueyama | c9a6e82 | 2015-09-18 01:51:37 +0000 | [diff] [blame] | 142 | // Compare relocations. | 
|  | 143 | auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { | 
|  | 144 | SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); | 
| Rui Ueyama | 5f38915 | 2015-09-20 20:19:12 +0000 | [diff] [blame] | 145 | SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); | 
|  | 146 | if (B1 == B2) | 
|  | 147 | return true; | 
|  | 148 | if (auto *D1 = dyn_cast<DefinedRegular>(B1)) | 
| Rui Ueyama | e8d1c59 | 2015-09-18 21:17:44 +0000 | [diff] [blame] | 149 | if (auto *D2 = dyn_cast<DefinedRegular>(B2)) | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 150 | return D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2]; | 
| Rui Ueyama | e8d1c59 | 2015-09-18 21:17:44 +0000 | [diff] [blame] | 151 | return false; | 
| Rui Ueyama | c9a6e82 | 2015-09-18 01:51:37 +0000 | [diff] [blame] | 152 | }; | 
|  | 153 | return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 154 | } | 
|  | 155 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 156 | size_t ICF::findBoundary(size_t Begin, size_t End) { | 
|  | 157 | for (size_t I = Begin + 1; I < End; ++I) | 
|  | 158 | if (Chunks[Begin]->Color[Cnt % 2] != Chunks[I]->Color[Cnt % 2]) | 
|  | 159 | return I; | 
|  | 160 | return End; | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | void ICF::forEachColorRange(size_t Begin, size_t End, | 
|  | 164 | std::function<void(size_t, size_t)> Fn) { | 
|  | 165 | if (Begin > 0) | 
|  | 166 | Begin = findBoundary(Begin - 1, End); | 
|  | 167 |  | 
|  | 168 | while (Begin < End) { | 
|  | 169 | size_t Mid = findBoundary(Begin, Chunks.size()); | 
|  | 170 | Fn(Begin, Mid); | 
|  | 171 | Begin = Mid; | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 172 | } | 
|  | 173 | } | 
|  | 174 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 175 | // Call Fn on each color group. | 
|  | 176 | void ICF::forEachColor(std::function<void(size_t, size_t)> Fn) { | 
|  | 177 | // If the number of sections are too small to use threading, | 
|  | 178 | // call Fn sequentially. | 
|  | 179 | if (Chunks.size() < 1024) { | 
|  | 180 | forEachColorRange(0, Chunks.size(), Fn); | 
|  | 181 | return; | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 182 | } | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 183 |  | 
|  | 184 | // Split sections into 256 shards and call Fn in parallel. | 
|  | 185 | size_t NumShards = 256; | 
|  | 186 | size_t Step = Chunks.size() / NumShards; | 
|  | 187 | parallel_for(size_t(0), NumShards, [&](size_t I) { | 
|  | 188 | forEachColorRange(I * Step, (I + 1) * Step, Fn); | 
|  | 189 | }); | 
|  | 190 | forEachColorRange(Step * NumShards, Chunks.size(), Fn); | 
| Rui Ueyama | 7b276e2 | 2015-07-30 22:57:21 +0000 | [diff] [blame] | 191 | } | 
|  | 192 |  | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 193 | // Merge identical COMDAT sections. | 
| Rui Ueyama | ef907ec | 2015-09-04 21:35:54 +0000 | [diff] [blame] | 194 | // Two sections are considered the same if their section headers, | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 195 | // contents and relocations are all the same. | 
| Rui Ueyama | e8d1c59 | 2015-09-18 21:17:44 +0000 | [diff] [blame] | 196 | void ICF::run(const std::vector<Chunk *> &Vec) { | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 197 | // Collect only mergeable sections and group by hash value. | 
| Rui Ueyama | e8d1c59 | 2015-09-18 21:17:44 +0000 | [diff] [blame] | 198 | for (Chunk *C : Vec) { | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 199 | auto *SC = dyn_cast<SectionChunk>(C); | 
|  | 200 | if (!SC) | 
|  | 201 | continue; | 
|  | 202 |  | 
|  | 203 | if (isEligible(SC)) { | 
|  | 204 | // Set MSB to 1 to avoid collisions with non-hash colors. | 
|  | 205 | SC->Color[0] = getHash(SC) | (1 << 31); | 
|  | 206 | Chunks.push_back(SC); | 
|  | 207 | } else { | 
|  | 208 | SC->Color[0] = NextId++; | 
| Rui Ueyama | 5b93aa5 | 2015-09-11 04:29:03 +0000 | [diff] [blame] | 209 | } | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 210 | } | 
|  | 211 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 212 | if (Chunks.empty()) | 
|  | 213 | return; | 
|  | 214 |  | 
| Rui Ueyama | aa95e5a | 2015-09-18 21:06:34 +0000 | [diff] [blame] | 215 | // From now on, sections in Chunks are ordered so that sections in | 
| Rui Ueyama | 92298d5 | 2015-09-16 14:19:10 +0000 | [diff] [blame] | 216 | // the same group are consecutive in the vector. | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 217 | std::stable_sort(Chunks.begin(), Chunks.end(), | 
|  | 218 | [](SectionChunk *A, SectionChunk *B) { | 
|  | 219 | return A->Color[0] < B->Color[0]; | 
|  | 220 | }); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 221 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 222 | // Compare static contents and assign unique IDs for each static content. | 
|  | 223 | forEachColor([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); | 
|  | 224 | ++Cnt; | 
| Rui Ueyama | aa95e5a | 2015-09-18 21:06:34 +0000 | [diff] [blame] | 225 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 226 | // Split groups by comparing relocations until convergence is obtained. | 
|  | 227 | do { | 
|  | 228 | Repeat = false; | 
|  | 229 | forEachColor( | 
|  | 230 | [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); | 
| Rui Ueyama | 66c06ce | 2015-09-16 23:55:39 +0000 | [diff] [blame] | 231 | ++Cnt; | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 232 | } while (Repeat); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 233 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 234 | if (Config->Verbose) | 
|  | 235 | outs() << "\nICF needed " << Cnt << " iterations\n"; | 
|  | 236 |  | 
|  | 237 | // Merge sections in the same colors. | 
|  | 238 | forEachColor([&](size_t Begin, size_t End) { | 
|  | 239 | if (End - Begin == 1) | 
|  | 240 | return; | 
|  | 241 |  | 
| Rui Ueyama | df985af | 2015-10-26 16:20:00 +0000 | [diff] [blame] | 242 | if (Config->Verbose) | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 243 | outs() << "Selected " << Chunks[Begin]->getDebugName() << "\n"; | 
|  | 244 | for (size_t I = Begin + 1; I < End; ++I) { | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 245 | if (Config->Verbose) | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 246 | outs() << "  Removed " << Chunks[I]->getDebugName() << "\n"; | 
|  | 247 | Chunks[Begin]->replace(Chunks[I]); | 
| Rui Ueyama | 9cb2870 | 2015-09-16 03:26:31 +0000 | [diff] [blame] | 248 | } | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 249 | }); | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 250 | } | 
|  | 251 |  | 
| Rui Ueyama | 3a618e5 | 2016-12-02 08:03:58 +0000 | [diff] [blame^] | 252 | // Entry point to ICF. | 
|  | 253 | void doICF(const std::vector<Chunk *> &Chunks) { ICF().run(Chunks); } | 
|  | 254 |  | 
| Rui Ueyama | 49560c7 | 2015-06-24 20:40:03 +0000 | [diff] [blame] | 255 | } // namespace coff | 
|  | 256 | } // namespace lld |