Close the gap between ELF and COFF ICF implementations. NFC.

We originally wrote the ICF code for COFF and ported it to ELF.
They started diverging since then. This patch closes the gap.

llvm-svn: 303801
This commit is contained in:
Rui Ueyama 2017-05-24 19:56:29 +00:00
parent bb20b5d5c3
commit 27abe98cfa
1 changed files with 13 additions and 21 deletions

View File

@ -56,7 +56,6 @@ private:
std::vector<SectionChunk *> Chunks; std::vector<SectionChunk *> Chunks;
int Cnt = 0; int Cnt = 0;
std::atomic<uint32_t> NextId = {1};
std::atomic<bool> Repeat = {false}; std::atomic<bool> Repeat = {false};
}; };
@ -98,10 +97,10 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) {
}); });
size_t Mid = Bound - Chunks.begin(); size_t Mid = Bound - Chunks.begin();
// Split [Begin, End) into [Begin, Mid) and [Mid, End). // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
uint32_t Id = NextId++; // equivalence class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I) for (size_t I = Begin; I < Mid; ++I)
Chunks[I]->Class[(Cnt + 1) % 2] = Id; Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
// If we created a group, we need to iterate the main loop again. // If we created a group, we need to iterate the main loop again.
if (Mid != End) if (Mid != End)
@ -186,6 +185,7 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// call Fn sequentially. // call Fn sequentially.
if (Chunks.size() < 1024) { if (Chunks.size() < 1024) {
forEachClassRange(0, Chunks.size(), Fn); forEachClassRange(0, Chunks.size(), Fn);
++Cnt;
return; return;
} }
@ -196,6 +196,7 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step;
forEachClassRange(I * Step, End, Fn); forEachClassRange(I * Step, End, Fn);
}); });
++Cnt;
} }
// Merge identical COMDAT sections. // Merge identical COMDAT sections.
@ -203,22 +204,15 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// contents and relocations are all the same. // contents and relocations are all the same.
void ICF::run(const std::vector<Chunk *> &Vec) { void ICF::run(const std::vector<Chunk *> &Vec) {
// Collect only mergeable sections and group by hash value. // Collect only mergeable sections and group by hash value.
for (Chunk *C : Vec) { for (Chunk *C : Vec)
auto *SC = dyn_cast<SectionChunk>(C); if (auto *SC = dyn_cast<SectionChunk>(C))
if (!SC) if (isEligible(SC))
continue; Chunks.push_back(SC);
if (isEligible(SC)) { // Initially, we use hash values to partition sections.
// Set MSB to 1 to avoid collisions with non-hash classs. for (SectionChunk *SC : Chunks)
SC->Class[0] = getHash(SC) | (1 << 31); // Set MSB to 1 to avoid collisions with non-hash classs.
Chunks.push_back(SC); SC->Class[0] = getHash(SC) | (1 << 31);
} else {
SC->Class[0] = NextId++;
}
}
if (Chunks.empty())
return;
// From now on, sections in Chunks are ordered so that sections in // From now on, sections in Chunks are ordered so that sections in
// the same group are consecutive in the vector. // the same group are consecutive in the vector.
@ -229,14 +223,12 @@ void ICF::run(const std::vector<Chunk *> &Vec) {
// Compare static contents and assign unique IDs for each static content. // Compare static contents and assign unique IDs for each static content.
forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
++Cnt;
// Split groups by comparing relocations until convergence is obtained. // Split groups by comparing relocations until convergence is obtained.
do { do {
Repeat = false; Repeat = false;
forEachClass( forEachClass(
[&](size_t Begin, size_t End) { segregate(Begin, End, false); }); [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
++Cnt;
} while (Repeat); } while (Repeat);
log("ICF needed " + Twine(Cnt) + " iterations"); log("ICF needed " + Twine(Cnt) + " iterations");