[lld] [lld-macho][arm64] Enhance safe ICF with thunk-based deduplication (PR #106573)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 5 08:34:29 PDT 2024
================
@@ -251,6 +252,74 @@ void ICF::forEachClassRange(size_t begin, size_t end,
}
}
+// Given a range of identical icfInputs, replace address significant functions
+// with a thunk that is just a direct branch to the first function in the
+// series. This way we keep only one main body of the function but we still
+// retain the address uniqueness of relevant functions by having them be a
+// direct branch thunk rather than containing a full copy of the actual function
+// body.
+void ICF::applySafeThunksToRange(size_t begin, size_t end) {
+ // If the functions we're dealing with are smaller than the thunk size, then
+ // just leave them all as-is - creating thunks would be a net loss.
+ uint32_t thunkSize = target->getICFSafeThunkSize();
+ if (icfInputs[begin]->data.size() <= thunkSize)
+ return;
+
+ // The standard ICF algorithm will merge all functions in the [begin + 1, end)
+ // range into icfInputs[begin].So, the body of the first function is always
+ // kept, even if it is not keepUnique. To make safe_thunks nicely play with
+ // this behavior, we ensure that the first function in the range is
+ // keepUnique.
+ if (!icfInputs[begin]->keepUnique) {
+ bool haveKeepUnique = false;
+ for (size_t i = begin + 1; i < end; ++i) {
+ if (icfInputs[i]->keepUnique) {
+ std::swap(icfInputs[begin], icfInputs[i]);
+ haveKeepUnique = true;
+ break;
+ }
+ }
+ // If we don't have keepUnique funcs, we can just return
+ if (!haveKeepUnique)
+ return;
+ }
+
+ // When creating a unique ICF thunk, use the first section as the section that
+ // all thunks will branch to.
+ ConcatInputSection *masterIsec = icfInputs[begin];
+
+ static std::mutex thunkInsertionMutex;
+ for (size_t i = begin + 1; i < end; ++i) {
+ ConcatInputSection *isec = icfInputs[i];
+ if (!isec->keepUnique)
+ continue;
+
+ // applySafeThunksToRange is called from multiple threads, but
+ // `makeSyntheticInputSection` and `addInputSection` are not thread safe. So
+ // we need to guard them with a mutex.
+ ConcatInputSection *thunk;
+ {
+ std::lock_guard<std::mutex> lock(thunkInsertionMutex);
+ thunk = makeSyntheticInputSection(isec->getSegName(), isec->getName());
+ addInputSection(thunk);
+ }
+
+ target->initICFSafeThunkBody(thunk, masterIsec);
+ thunk->foldIdentical(isec);
+
+ // Since we're folding the target function into a thunk, we need to adjust
----------------
alx32 wrote:
I added a test for this by checking the .map file.
When doing so - I discovered that the thunks were showing up as size 0 because of the map printing logic.
So I've added `Symbol::ICFFoldKind` (and related logic) to address this
https://github.com/llvm/llvm-project/pull/106573
More information about the llvm-commits
mailing list