[lld] ELF: Add branch-to-branch optimization. (PR #138366)
Peter Smith via llvm-commits
llvm-commits at lists.llvm.org
Thu May 22 09:09:07 PDT 2025
================
@@ -975,6 +977,62 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
}
}
+static std::optional<uint64_t> getControlTransferAddend(InputSection &is,
+ Relocation &r) {
+ // Identify a control transfer relocation for the branch-to-branch
+ // optimization. A "control transfer relocation" means a B or BL
+ // target but it also includes relative vtable relocations for example.
+ //
+ // We require the relocation type to be JUMP26, CALL26 or PLT32. With a
+ // relocation type of PLT32 the value may be assumed to be used for branching
+ // directly to the symbol and the addend is only used to produce the relocated
+ // value (hence the effective addend is always 0). This is because if a PLT is
+ // needed the addend will be added to the address of the PLT, and it doesn't
+ // make sense to branch into the middle of a PLT. For example, relative vtable
+ // relocations use PLT32 and 0 or a positive value as the addend but still are
+ // used to branch to the symbol.
+ //
+ // With JUMP26 or CALL26 the only reasonable interpretation of a non-zero
+ // addend is that we are branching to symbol+addend so that becomes the
+ // effective addend.
+ if (r.type == R_AARCH64_PLT32)
+ return 0;
+ if (r.type == R_AARCH64_JUMP26 || r.type == R_AARCH64_CALL26)
+ return r.addend;
+ return std::nullopt;
+}
+
+static std::pair<Relocation *, uint64_t> getBranchInfo(InputSection &is,
+ uint64_t offset) {
+ auto *i = std::lower_bound(
+ is.relocations.begin(), is.relocations.end(), offset,
+ [](Relocation &r, uint64_t offset) { return r.offset < offset; });
+ if (i != is.relocations.end() && i->offset == offset &&
+ i->type == R_AARCH64_JUMP26) {
+ return {i, i->addend};
+ }
----------------
smithp35 wrote:
If you know that the incoming relocation is `R_AARCH64_JUMP26` or `R_AARCH64_CALL26`, and the destination is a BTI, then in theory you could check to see if the next instruction was a direct branch.
Probably unlikely enough to not need handling though.
NOPs, at least those at the start of a function, are probably not safe to skip as these can be used for hot-patching.
https://github.com/llvm/llvm-project/pull/138366
More information about the llvm-commits
mailing list