2015-06-25 04:40:03 +08:00
|
|
|
//===- ICF.cpp ------------------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2015-06-25 04:40:03 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2016-12-02 16:03:58 +08:00
|
|
|
// ICF is short for Identical Code Folding. That 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.
|
2015-09-11 12:29:03 +08:00
|
|
|
//
|
2016-12-02 16:03:58 +08:00
|
|
|
// On Windows, ICF is enabled by default.
|
2015-09-11 12:29:03 +08:00
|
|
|
//
|
2019-09-25 04:17:54 +08:00
|
|
|
// See ELF/ICF.cpp for the details about the algorithm.
|
2015-06-25 04:40:03 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-02-21 06:09:59 +08:00
|
|
|
#include "ICF.h"
|
2015-06-25 04:40:03 +08:00
|
|
|
#include "Chunks.h"
|
2015-07-31 06:57:21 +08:00
|
|
|
#include "Symbols.h"
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2018-01-18 03:16:26 +08:00
|
|
|
#include "lld/Common/Timer.h"
|
2015-07-31 06:57:21 +08:00
|
|
|
#include "llvm/ADT/Hashing.h"
|
2015-09-11 12:29:03 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2017-05-11 08:03:52 +08:00
|
|
|
#include "llvm/Support/Parallel.h"
|
2015-09-11 12:29:03 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-08-01 02:04:58 +08:00
|
|
|
#include "llvm/Support/xxhash.h"
|
2015-09-11 12:29:03 +08:00
|
|
|
#include <algorithm>
|
2015-09-19 06:31:15 +08:00
|
|
|
#include <atomic>
|
2015-06-25 04:40:03 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2015-07-31 06:57:21 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2015-06-25 04:40:03 +08:00
|
|
|
namespace lld {
|
|
|
|
namespace coff {
|
2015-09-11 12:29:03 +08:00
|
|
|
|
2018-01-18 03:16:26 +08:00
|
|
|
static Timer icfTimer("ICF", Timer::root());
|
|
|
|
|
2015-09-16 22:19:10 +08:00
|
|
|
class ICF {
|
|
|
|
public:
|
2021-02-27 08:38:24 +08:00
|
|
|
ICF(ICFLevel icfLevel) : icfLevel(icfLevel){};
|
2017-12-08 09:09:21 +08:00
|
|
|
void run(ArrayRef<Chunk *> v);
|
2015-09-16 22:19:10 +08:00
|
|
|
|
|
|
|
private:
|
2016-12-02 16:03:58 +08:00
|
|
|
void segregate(size_t begin, size_t end, bool constant);
|
2015-09-16 22:19:10 +08:00
|
|
|
|
2021-03-30 10:10:09 +08:00
|
|
|
bool assocEquals(const SectionChunk *a, const SectionChunk *b);
|
2018-05-12 10:12:40 +08:00
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
bool equalsConstant(const SectionChunk *a, const SectionChunk *b);
|
|
|
|
bool equalsVariable(const SectionChunk *a, const SectionChunk *b);
|
2015-09-16 22:19:10 +08:00
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
bool isEligible(SectionChunk *c);
|
|
|
|
|
|
|
|
size_t findBoundary(size_t begin, size_t end);
|
|
|
|
|
2017-05-06 07:52:24 +08:00
|
|
|
void forEachClassRange(size_t begin, size_t end,
|
2016-12-02 16:03:58 +08:00
|
|
|
std::function<void(size_t, size_t)> fn);
|
|
|
|
|
2017-05-06 07:52:24 +08:00
|
|
|
void forEachClass(std::function<void(size_t, size_t)> fn);
|
2016-12-02 16:03:58 +08:00
|
|
|
|
|
|
|
std::vector<SectionChunk *> chunks;
|
|
|
|
int cnt = 0;
|
|
|
|
std::atomic<bool> repeat = {false};
|
2021-02-27 08:38:24 +08:00
|
|
|
ICFLevel icfLevel = ICFLevel::All;
|
2016-12-02 16:03:58 +08:00
|
|
|
};
|
2015-07-31 06:57:21 +08:00
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
// Returns true if section S is subject of ICF.
|
2017-04-28 07:03:22 +08:00
|
|
|
//
|
|
|
|
// Microsoft's documentation
|
|
|
|
// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April
|
|
|
|
// 2017) says that /opt:icf folds both functions and read-only data.
|
|
|
|
// Despite that, the MSVC linker folds only functions. We found
|
|
|
|
// a few instances of programs that are not safe for data merging.
|
2018-05-11 07:31:58 +08:00
|
|
|
// Therefore, we merge only functions just like the MSVC tool. However, we also
|
|
|
|
// merge read-only sections in a couple of cases where the address of the
|
|
|
|
// section is insignificant to the user program and the behaviour matches that
|
|
|
|
// of the Visual C++ linker.
|
2016-12-02 16:03:58 +08:00
|
|
|
bool ICF::isEligible(SectionChunk *c) {
|
2019-10-10 10:04:56 +08:00
|
|
|
// Non-comdat chunks, dead chunks, and writable chunks are not eligible.
|
2018-04-20 04:03:24 +08:00
|
|
|
bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
|
2018-08-31 15:45:20 +08:00
|
|
|
if (!c->isCOMDAT() || !c->live || writable)
|
2017-11-18 03:50:10 +08:00
|
|
|
return false;
|
|
|
|
|
2021-02-27 08:38:24 +08:00
|
|
|
// Under regular (not safe) ICF, all code sections are eligible.
|
|
|
|
if ((icfLevel == ICFLevel::All) &&
|
|
|
|
c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
|
2017-11-18 03:50:10 +08:00
|
|
|
return true;
|
|
|
|
|
2018-05-12 10:12:40 +08:00
|
|
|
// .pdata and .xdata unwind info sections are eligible.
|
|
|
|
StringRef outSecName = c->getSectionName().split('$').first;
|
|
|
|
if (outSecName == ".pdata" || outSecName == ".xdata")
|
2018-05-11 07:31:58 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// So are vtables.
|
2018-08-24 01:44:42 +08:00
|
|
|
if (c->sym && c->sym->getName().startswith("??_7"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Anything else not in an address-significance table is eligible.
|
|
|
|
return !c->keepUnique;
|
2016-12-02 16:03:58 +08:00
|
|
|
}
|
|
|
|
|
2017-05-06 07:52:24 +08:00
|
|
|
// Split an equivalence class into smaller classes.
|
2016-12-02 16:03:58 +08:00
|
|
|
void ICF::segregate(size_t begin, size_t end, bool constant) {
|
|
|
|
while (begin < end) {
|
|
|
|
// Divide [Begin, End) into two. Let Mid be the start index of the
|
|
|
|
// second group.
|
|
|
|
auto bound = std::stable_partition(
|
|
|
|
chunks.begin() + begin + 1, chunks.begin() + end, [&](SectionChunk *s) {
|
|
|
|
if (constant)
|
|
|
|
return equalsConstant(chunks[begin], s);
|
|
|
|
return equalsVariable(chunks[begin], s);
|
|
|
|
});
|
|
|
|
size_t mid = bound - chunks.begin();
|
|
|
|
|
2017-05-25 03:56:29 +08:00
|
|
|
// Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
|
|
|
|
// equivalence class ID because every group ends with a unique index.
|
2016-12-02 16:03:58 +08:00
|
|
|
for (size_t i = begin; i < mid; ++i)
|
2017-05-25 03:56:29 +08:00
|
|
|
chunks[i]->eqClass[(cnt + 1) % 2] = mid;
|
2016-12-02 16:03:58 +08:00
|
|
|
|
|
|
|
// If we created a group, we need to iterate the main loop again.
|
|
|
|
if (mid != end)
|
|
|
|
repeat = true;
|
|
|
|
|
|
|
|
begin = mid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 10:10:09 +08:00
|
|
|
// Returns true if two sections' associative children are equal.
|
|
|
|
bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) {
|
|
|
|
// Ignore associated metadata sections that don't participate in ICF, such as
|
|
|
|
// debug info and CFGuard metadata.
|
|
|
|
auto considerForICF = [](const SectionChunk &assoc) {
|
|
|
|
StringRef Name = assoc.getSectionName();
|
|
|
|
return !(Name.startswith(".debug") || Name == ".gfids$y" ||
|
|
|
|
Name == ".giats$y" || Name == ".gljmp$y");
|
2018-05-12 10:12:40 +08:00
|
|
|
};
|
2021-03-30 10:10:09 +08:00
|
|
|
auto ra = make_filter_range(a->children(), considerForICF);
|
|
|
|
auto rb = make_filter_range(b->children(), considerForICF);
|
|
|
|
return std::equal(ra.begin(), ra.end(), rb.begin(), rb.end(),
|
|
|
|
[&](const SectionChunk &ia, const SectionChunk &ib) {
|
|
|
|
return ia.eqClass[cnt % 2] == ib.eqClass[cnt % 2];
|
|
|
|
});
|
2018-05-12 10:12:40 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
// Compare "non-moving" part of two sections, namely everything
|
|
|
|
// except relocation targets.
|
2015-09-16 22:19:10 +08:00
|
|
|
bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) {
|
2019-05-04 04:17:14 +08:00
|
|
|
if (a->relocsSize != b->relocsSize)
|
2015-07-31 06:57:21 +08:00
|
|
|
return false;
|
|
|
|
|
COFF: Optimize ICF by comparing relocations before section contents.
equalsConstants() is the heaviest function in ICF, and that consumes
more than half of total ICF execution time. Of which, section content
comparison accounts for roughly one third.
Previously, we compared section contents at the beginning of the
function after comparing their checksums. The comparison is very
likely to succeed because when the control reaches that comparison,
their checksums are always equal. And because checksums are 64-bit
CRC, they are unlikely to collide.
We compared relocations and associative sections after that.
If they are different, the time we spent on byte-by-byte comparison
of section contents were wasted.
This patch moves the comparison at the end of function. If the
comparison fails, the time we spent on relocation comparison are
wasted, but as I wrote it's very unlikely to happen.
LLD took 1198 ms to link itself to produce a 27.11 MB executable.
Of which, ICF accounted for 536 ms. This patch cuts it by 90 ms,
which is 17% speedup of ICF and 7.5% speedup overall. All numbers
are median of ten runs.
llvm-svn: 247961
2015-09-18 09:30:56 +08:00
|
|
|
// Compare relocations.
|
2015-07-31 06:57:21 +08:00
|
|
|
auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
|
2015-09-16 11:26:31 +08:00
|
|
|
if (r1.Type != r2.Type ||
|
|
|
|
r1.VirtualAddress != r2.VirtualAddress) {
|
2015-07-31 06:57:21 +08:00
|
|
|
return false;
|
2015-09-16 11:26:31 +08:00
|
|
|
}
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
|
|
|
|
Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
|
2015-07-31 06:57:21 +08:00
|
|
|
if (b1 == b2)
|
|
|
|
return true;
|
2015-09-18 10:40:54 +08:00
|
|
|
if (auto *d1 = dyn_cast<DefinedRegular>(b1))
|
|
|
|
if (auto *d2 = dyn_cast<DefinedRegular>(b2))
|
|
|
|
return d1->getValue() == d2->getValue() &&
|
2017-05-06 07:52:24 +08:00
|
|
|
d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
|
2015-09-18 10:40:54 +08:00
|
|
|
return false;
|
2015-07-31 06:57:21 +08:00
|
|
|
};
|
2019-05-04 04:17:14 +08:00
|
|
|
if (!std::equal(a->getRelocs().begin(), a->getRelocs().end(),
|
|
|
|
b->getRelocs().begin(), eq))
|
COFF: Optimize ICF by comparing relocations before section contents.
equalsConstants() is the heaviest function in ICF, and that consumes
more than half of total ICF execution time. Of which, section content
comparison accounts for roughly one third.
Previously, we compared section contents at the beginning of the
function after comparing their checksums. The comparison is very
likely to succeed because when the control reaches that comparison,
their checksums are always equal. And because checksums are 64-bit
CRC, they are unlikely to collide.
We compared relocations and associative sections after that.
If they are different, the time we spent on byte-by-byte comparison
of section contents were wasted.
This patch moves the comparison at the end of function. If the
comparison fails, the time we spent on relocation comparison are
wasted, but as I wrote it's very unlikely to happen.
LLD took 1198 ms to link itself to produce a 27.11 MB executable.
Of which, ICF accounted for 536 ms. This patch cuts it by 90 ms,
which is 17% speedup of ICF and 7.5% speedup overall. All numbers
are median of ten runs.
llvm-svn: 247961
2015-09-18 09:30:56 +08:00
|
|
|
return false;
|
|
|
|
|
2015-09-18 10:40:54 +08:00
|
|
|
// Compare section attributes and contents.
|
2018-04-20 04:03:24 +08:00
|
|
|
return a->getOutputCharacteristics() == b->getOutputCharacteristics() &&
|
2019-05-04 04:17:14 +08:00
|
|
|
a->getSectionName() == b->getSectionName() &&
|
2015-09-18 10:40:54 +08:00
|
|
|
a->header->SizeOfRawData == b->header->SizeOfRawData &&
|
2018-05-12 10:12:40 +08:00
|
|
|
a->checksum == b->checksum && a->getContents() == b->getContents() &&
|
2021-03-30 10:10:09 +08:00
|
|
|
assocEquals(a, b);
|
2015-09-16 11:26:31 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
// Compare "moving" part of two sections, namely relocation targets.
|
2015-09-16 22:19:10 +08:00
|
|
|
bool ICF::equalsVariable(const SectionChunk *a, const SectionChunk *b) {
|
2015-09-18 09:51:37 +08:00
|
|
|
// Compare relocations.
|
|
|
|
auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
|
|
|
|
Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
|
2015-09-21 04:19:12 +08:00
|
|
|
if (b1 == b2)
|
|
|
|
return true;
|
|
|
|
if (auto *d1 = dyn_cast<DefinedRegular>(b1))
|
2015-09-19 05:17:44 +08:00
|
|
|
if (auto *d2 = dyn_cast<DefinedRegular>(b2))
|
2017-05-06 07:52:24 +08:00
|
|
|
return d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
|
2015-09-19 05:17:44 +08:00
|
|
|
return false;
|
2015-09-18 09:51:37 +08:00
|
|
|
};
|
2019-05-04 04:17:14 +08:00
|
|
|
return std::equal(a->getRelocs().begin(), a->getRelocs().end(),
|
|
|
|
b->getRelocs().begin(), eq) &&
|
2021-03-30 10:10:09 +08:00
|
|
|
assocEquals(a, b);
|
2015-09-16 11:26:31 +08:00
|
|
|
}
|
|
|
|
|
2018-03-27 14:08:35 +08:00
|
|
|
// Find the first Chunk after Begin that has a different class from Begin.
|
2016-12-02 16:03:58 +08:00
|
|
|
size_t ICF::findBoundary(size_t begin, size_t end) {
|
|
|
|
for (size_t i = begin + 1; i < end; ++i)
|
2017-05-06 07:52:24 +08:00
|
|
|
if (chunks[begin]->eqClass[cnt % 2] != chunks[i]->eqClass[cnt % 2])
|
2016-12-02 16:03:58 +08:00
|
|
|
return i;
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
|
2017-05-06 07:52:24 +08:00
|
|
|
void ICF::forEachClassRange(size_t begin, size_t end,
|
2016-12-02 16:03:58 +08:00
|
|
|
std::function<void(size_t, size_t)> fn) {
|
|
|
|
while (begin < end) {
|
2018-03-27 14:08:35 +08:00
|
|
|
size_t mid = findBoundary(begin, end);
|
2016-12-02 16:03:58 +08:00
|
|
|
fn(begin, mid);
|
|
|
|
begin = mid;
|
2015-09-16 11:26:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-06 07:52:24 +08:00
|
|
|
// Call Fn on each class group.
|
|
|
|
void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {
|
2016-12-02 16:03:58 +08:00
|
|
|
// If the number of sections are too small to use threading,
|
|
|
|
// call Fn sequentially.
|
|
|
|
if (chunks.size() < 1024) {
|
2017-05-06 07:52:24 +08:00
|
|
|
forEachClassRange(0, chunks.size(), fn);
|
2017-05-25 03:56:29 +08:00
|
|
|
++cnt;
|
2016-12-02 16:03:58 +08:00
|
|
|
return;
|
2015-09-16 11:26:31 +08:00
|
|
|
}
|
2016-12-02 16:03:58 +08:00
|
|
|
|
2018-03-27 14:08:35 +08:00
|
|
|
// Shard into non-overlapping intervals, and call Fn in parallel.
|
|
|
|
// The sharding must be completed before any calls to Fn are made
|
|
|
|
// so that Fn can modify the Chunks in its shard without causing data
|
|
|
|
// races.
|
|
|
|
const size_t numShards = 256;
|
2016-12-02 16:03:58 +08:00
|
|
|
size_t step = chunks.size() / numShards;
|
2018-03-27 14:08:35 +08:00
|
|
|
size_t boundaries[numShards + 1];
|
|
|
|
boundaries[0] = 0;
|
|
|
|
boundaries[numShards] = chunks.size();
|
2018-11-27 04:07:07 +08:00
|
|
|
parallelForEachN(1, numShards, [&](size_t i) {
|
2018-03-27 14:08:35 +08:00
|
|
|
boundaries[i] = findBoundary((i - 1) * step, chunks.size());
|
|
|
|
});
|
2018-11-27 04:07:07 +08:00
|
|
|
parallelForEachN(1, numShards + 1, [&](size_t i) {
|
2018-03-27 14:08:35 +08:00
|
|
|
if (boundaries[i - 1] < boundaries[i]) {
|
|
|
|
forEachClassRange(boundaries[i - 1], boundaries[i], fn);
|
|
|
|
}
|
2016-12-02 16:03:58 +08:00
|
|
|
});
|
2017-05-25 03:56:29 +08:00
|
|
|
++cnt;
|
2015-07-31 06:57:21 +08:00
|
|
|
}
|
|
|
|
|
2015-06-25 04:40:03 +08:00
|
|
|
// Merge identical COMDAT sections.
|
2015-09-05 05:35:54 +08:00
|
|
|
// Two sections are considered the same if their section headers,
|
2015-06-25 04:40:03 +08:00
|
|
|
// contents and relocations are all the same.
|
2017-12-08 09:09:21 +08:00
|
|
|
void ICF::run(ArrayRef<Chunk *> vec) {
|
2018-01-18 03:16:26 +08:00
|
|
|
ScopedTimer t(icfTimer);
|
|
|
|
|
2015-09-16 22:19:10 +08:00
|
|
|
// Collect only mergeable sections and group by hash value.
|
2017-05-25 04:32:23 +08:00
|
|
|
uint32_t nextId = 1;
|
|
|
|
for (Chunk *c : vec) {
|
|
|
|
if (auto *sc = dyn_cast<SectionChunk>(c)) {
|
2017-05-25 03:56:29 +08:00
|
|
|
if (isEligible(sc))
|
|
|
|
chunks.push_back(sc);
|
2017-05-25 04:32:23 +08:00
|
|
|
else
|
|
|
|
sc->eqClass[0] = nextId++;
|
|
|
|
}
|
|
|
|
}
|
2015-09-05 05:35:54 +08:00
|
|
|
|
2018-03-16 05:14:02 +08:00
|
|
|
// Make sure that ICF doesn't merge sections that are being handled by string
|
|
|
|
// tail merging.
|
2019-05-23 04:21:52 +08:00
|
|
|
for (MergeChunk *mc : MergeChunk::instances)
|
|
|
|
if (mc)
|
|
|
|
for (SectionChunk *sc : mc->sections)
|
|
|
|
sc->eqClass[0] = nextId++;
|
2018-03-16 05:14:02 +08:00
|
|
|
|
2017-05-25 03:56:29 +08:00
|
|
|
// Initially, we use hash values to partition sections.
|
2018-11-27 04:07:07 +08:00
|
|
|
parallelForEach(chunks, [&](SectionChunk *sc) {
|
2019-01-23 07:54:49 +08:00
|
|
|
sc->eqClass[0] = xxHash64(sc->getContents());
|
2018-11-22 05:29:35 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// Combine the hashes of the sections referenced by each section into its
|
|
|
|
// hash.
|
2019-01-23 07:54:49 +08:00
|
|
|
for (unsigned cnt = 0; cnt != 2; ++cnt) {
|
|
|
|
parallelForEach(chunks, [&](SectionChunk *sc) {
|
|
|
|
uint32_t hash = sc->eqClass[cnt % 2];
|
|
|
|
for (Symbol *b : sc->symbols())
|
|
|
|
if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
|
|
|
|
hash += sym->getChunk()->eqClass[cnt % 2];
|
2019-10-10 10:04:56 +08:00
|
|
|
// Set MSB to 1 to avoid collisions with non-hash classes.
|
2019-01-23 07:54:49 +08:00
|
|
|
sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31);
|
|
|
|
});
|
|
|
|
}
|
2016-12-02 16:03:58 +08:00
|
|
|
|
2015-09-19 05:06:34 +08:00
|
|
|
// From now on, sections in Chunks are ordered so that sections in
|
2015-09-16 22:19:10 +08:00
|
|
|
// the same group are consecutive in the vector.
|
2019-04-23 10:42:06 +08:00
|
|
|
llvm::stable_sort(chunks, [](const SectionChunk *a, const SectionChunk *b) {
|
|
|
|
return a->eqClass[0] < b->eqClass[0];
|
|
|
|
});
|
2016-12-02 16:03:58 +08:00
|
|
|
|
|
|
|
// Compare static contents and assign unique IDs for each static content.
|
2017-05-06 07:52:24 +08:00
|
|
|
forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); });
|
2016-12-02 16:03:58 +08:00
|
|
|
|
|
|
|
// Split groups by comparing relocations until convergence is obtained.
|
|
|
|
do {
|
|
|
|
repeat = false;
|
2017-05-06 07:52:24 +08:00
|
|
|
forEachClass(
|
2016-12-02 16:03:58 +08:00
|
|
|
[&](size_t begin, size_t end) { segregate(begin, end, false); });
|
|
|
|
} while (repeat);
|
|
|
|
|
2017-02-22 07:22:56 +08:00
|
|
|
log("ICF needed " + Twine(cnt) + " iterations");
|
2016-12-02 16:03:58 +08:00
|
|
|
|
2019-10-10 10:04:56 +08:00
|
|
|
// Merge sections in the same classes.
|
2017-05-06 07:52:24 +08:00
|
|
|
forEachClass([&](size_t begin, size_t end) {
|
2016-12-02 16:03:58 +08:00
|
|
|
if (end - begin == 1)
|
|
|
|
return;
|
|
|
|
|
2017-02-22 07:22:56 +08:00
|
|
|
log("Selected " + chunks[begin]->getDebugName());
|
2016-12-02 16:03:58 +08:00
|
|
|
for (size_t i = begin + 1; i < end; ++i) {
|
2017-02-22 07:22:56 +08:00
|
|
|
log(" Removed " + chunks[i]->getDebugName());
|
2016-12-02 16:03:58 +08:00
|
|
|
chunks[begin]->replace(chunks[i]);
|
2015-09-11 12:29:03 +08:00
|
|
|
}
|
2016-12-02 16:03:58 +08:00
|
|
|
});
|
2015-06-25 04:40:03 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 16:03:58 +08:00
|
|
|
// Entry point to ICF.
|
2021-02-27 08:38:24 +08:00
|
|
|
void doICF(ArrayRef<Chunk *> chunks, ICFLevel icfLevel) {
|
|
|
|
ICF(icfLevel).run(chunks);
|
|
|
|
}
|
2016-12-02 16:03:58 +08:00
|
|
|
|
2015-06-25 04:40:03 +08:00
|
|
|
} // namespace coff
|
|
|
|
} // namespace lld
|