[lld] [lld-macho] Fix branch extension thunk estimation logic (PR #120529)

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 19 11:28:55 PST 2024


https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/120529

>From fe6369ae90d7a69dc013781678b54b6ac39ea9d0 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Wed, 18 Dec 2024 23:37:48 -0800
Subject: [PATCH 1/4] [lld-macho] Fix branch extension thunk estimation logic

---
 lld/MachO/ConcatOutputSection.cpp | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp
index 6a9301f84a03ef..9610a80e309bac 100644
--- a/lld/MachO/ConcatOutputSection.cpp
+++ b/lld/MachO/ConcatOutputSection.cpp
@@ -184,6 +184,15 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
     InputSection *isec = inputs[i];
     isecEnd = alignToPowerOf2(isecEnd, isec->align) + isec->getSize();
   }
+
+  // Tally up any thunks that have already been placed that have address higher
+  // than the equivalent callIdx. We first find the index of the first thunk
+  // that is beyond the current inputs[callIdx].
+  auto itPostcallIdxThunks = std::partition_point(
+      thunks.begin(), thunks.end(),
+      [isecVA](const ConcatInputSection *t) { return t->getVA() <= isecVA; });
+  uint32_t existingForwardThunks = thunks.end() - itPostcallIdxThunks;
+
   // Estimate the address after which call sites can safely call stubs
   // directly rather than through intermediary thunks.
   uint64_t forwardBranchRange = target->forwardBranchRange;
@@ -191,8 +200,21 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
          "should not run thunk insertion if all code fits in jump range");
   assert(isecEnd - isecVA <= forwardBranchRange &&
          "should only finalize sections in jump range");
-  uint64_t stubsInRangeVA = isecEnd + maxPotentialThunks * target->thunkSize +
-                            in.stubs->getSize() - forwardBranchRange;
+
+  // Estimate the maximum size of the code, right before the stubs section
+  uint32_t maxTextSize = 0;
+  // Add the size of all the inputs, including the unprocessed ones.
+  maxTextSize += isecEnd;
+
+  // Add the size of the thunks that may be created in the future
+  maxTextSize += maxPotentialThunks * target->thunkSize;
+
+  // Add the size of the thunks that have already been created that are ahead
+  maxTextSize += existingForwardThunks * target->thunkSize;
+
+  uint64_t stubsInRangeVA =
+      maxTextSize + in.stubs->getSize() - forwardBranchRange;
+
   log("thunks = " + std::to_string(thunkMap.size()) +
       ", potential = " + std::to_string(maxPotentialThunks) +
       ", stubs = " + std::to_string(in.stubs->getSize()) + ", isecVA = " +

>From bc5e3426d0f71a2fc364258a4009b3848f856d95 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 19 Dec 2024 09:53:27 -0800
Subject: [PATCH 2/4] uint32 => uint64 + extra comments

---
 lld/MachO/ConcatOutputSection.cpp | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp
index 9610a80e309bac..cf3ab72c351e4c 100644
--- a/lld/MachO/ConcatOutputSection.cpp
+++ b/lld/MachO/ConcatOutputSection.cpp
@@ -191,7 +191,7 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
   auto itPostcallIdxThunks = std::partition_point(
       thunks.begin(), thunks.end(),
       [isecVA](const ConcatInputSection *t) { return t->getVA() <= isecVA; });
-  uint32_t existingForwardThunks = thunks.end() - itPostcallIdxThunks;
+  uint64_t existingForwardThunks = thunks.end() - itPostcallIdxThunks;
 
   // Estimate the address after which call sites can safely call stubs
   // directly rather than through intermediary thunks.
@@ -201,26 +201,30 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
   assert(isecEnd - isecVA <= forwardBranchRange &&
          "should only finalize sections in jump range");
 
-  // Estimate the maximum size of the code, right before the stubs section
-  uint32_t maxTextSize = 0;
+  // Estimate the maximum size of the code, right before the stubs section.
+  uint64_t maxTextSize = 0;
   // Add the size of all the inputs, including the unprocessed ones.
   maxTextSize += isecEnd;
 
-  // Add the size of the thunks that may be created in the future
+  // Add the size of the thunks that may be created in the future. Since
+  // 'maxPotentialThunks' overcounts, this is an estimate of the upper limit.
   maxTextSize += maxPotentialThunks * target->thunkSize;
 
   // Add the size of the thunks that have already been created that are ahead
   maxTextSize += existingForwardThunks * target->thunkSize;
 
-  uint64_t stubsInRangeVA =
-      maxTextSize + in.stubs->getSize() - forwardBranchRange;
+  // Estimated maximum VA of last stub.
+  uint64_t maxVAOfLastStub = maxTextSize + in.stubs->getSize();
+
+  // Calculaate the first address that is gueranteed to not need a thunk to
+  // reach any stub.git
+  uint64_t stubsInRangeVA = maxVAOfLastStub - forwardBranchRange;
 
   log("thunks = " + std::to_string(thunkMap.size()) +
-      ", potential = " + std::to_string(maxPotentialThunks) +
-      ", stubs = " + std::to_string(in.stubs->getSize()) + ", isecVA = " +
-      utohexstr(isecVA) + ", threshold = " + utohexstr(stubsInRangeVA) +
-      ", isecEnd = " + utohexstr(isecEnd) +
-      ", tail = " + utohexstr(isecEnd - isecVA) +
+      ", potential = " + std::to_string(maxPotentialThunks) + ", stubs = " +
+      std::to_string(in.stubs->getSize()) + ", isecVA = " + utohexstr(isecVA) +
+      ", threshold = " + utohexstr(stubsInRangeVA) + ", isecEnd = " +
+      utohexstr(isecEnd) + ", tail = " + utohexstr(isecEnd - isecVA) +
       ", slop = " + utohexstr(forwardBranchRange - (isecEnd - isecVA)));
   return stubsInRangeVA;
 }

>From 43949e0e11fe3f8d26ae3d8367744582d631ae5f Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 19 Dec 2024 09:59:44 -0800
Subject: [PATCH 3/4] Undo fixing unrelated formatting

---
 lld/MachO/ConcatOutputSection.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp
index cf3ab72c351e4c..a55e8db2cd27a7 100644
--- a/lld/MachO/ConcatOutputSection.cpp
+++ b/lld/MachO/ConcatOutputSection.cpp
@@ -221,10 +221,11 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
   uint64_t stubsInRangeVA = maxVAOfLastStub - forwardBranchRange;
 
   log("thunks = " + std::to_string(thunkMap.size()) +
-      ", potential = " + std::to_string(maxPotentialThunks) + ", stubs = " +
-      std::to_string(in.stubs->getSize()) + ", isecVA = " + utohexstr(isecVA) +
-      ", threshold = " + utohexstr(stubsInRangeVA) + ", isecEnd = " +
-      utohexstr(isecEnd) + ", tail = " + utohexstr(isecEnd - isecVA) +
+      ", potential = " + std::to_string(maxPotentialThunks) +
+      ", stubs = " + std::to_string(in.stubs->getSize()) + ", isecVA = " +
+      utohexstr(isecVA) + ", threshold = " + utohexstr(stubsInRangeVA) +
+      ", isecEnd = " + utohexstr(isecEnd) +
+      ", tail = " + utohexstr(isecEnd - isecVA) +
       ", slop = " + utohexstr(forwardBranchRange - (isecEnd - isecVA)));
   return stubsInRangeVA;
 }

>From e1408deac4bf34854c4696ed092d486c28050258 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 19 Dec 2024 11:28:41 -0800
Subject: [PATCH 4/4] Fix typo + add better comments to code.

---
 lld/MachO/ConcatOutputSection.cpp | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp
index a55e8db2cd27a7..e6dc65b9d4d2c3 100644
--- a/lld/MachO/ConcatOutputSection.cpp
+++ b/lld/MachO/ConcatOutputSection.cpp
@@ -185,9 +185,9 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
     isecEnd = alignToPowerOf2(isecEnd, isec->align) + isec->getSize();
   }
 
-  // Tally up any thunks that have already been placed that have address higher
-  // than the equivalent callIdx. We first find the index of the first thunk
-  // that is beyond the current inputs[callIdx].
+  // Tally up any thunks that have already been placed that have VA higher than
+  // inputs[callIdx]. First, find the index of the first thunk that is beyond
+  // the current inputs[callIdx].
   auto itPostcallIdxThunks = std::partition_point(
       thunks.begin(), thunks.end(),
       [isecVA](const ConcatInputSection *t) { return t->getVA() <= isecVA; });
@@ -206,18 +206,20 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
   // Add the size of all the inputs, including the unprocessed ones.
   maxTextSize += isecEnd;
 
+  // Add the size of the thunks that have already been created that are ahead of
+  // inputs[callIdx]. These are already created thunks that will be interleaved
+  // with inputs[callIdx...end].
+  maxTextSize += existingForwardThunks * target->thunkSize;
+
   // Add the size of the thunks that may be created in the future. Since
   // 'maxPotentialThunks' overcounts, this is an estimate of the upper limit.
   maxTextSize += maxPotentialThunks * target->thunkSize;
 
-  // Add the size of the thunks that have already been created that are ahead
-  maxTextSize += existingForwardThunks * target->thunkSize;
-
   // Estimated maximum VA of last stub.
   uint64_t maxVAOfLastStub = maxTextSize + in.stubs->getSize();
 
   // Calculaate the first address that is gueranteed to not need a thunk to
-  // reach any stub.git
+  // reach any stub.
   uint64_t stubsInRangeVA = maxVAOfLastStub - forwardBranchRange;
 
   log("thunks = " + std::to_string(thunkMap.size()) +



More information about the llvm-commits mailing list