[llvm] [JITLink][RISCV] Avoid quadratic removal of alignment edges (PR #222317)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 9 06:15:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Thrrreeee (Thrrreeee)
<details>
<summary>Changes</summary>
We encountered this issue while using BOLT to instrument clang on RISC-V. JITLink spent significant time removing alignment edges during relaxation finalization in large code blocks with many alignment relocations.
During RISC-V relaxation finalization, finalizeBlockRelax removes AlignRelaxable edges individually from a block's edge vector. Each erase shifts the remaining suffix, making this cleanup quadratic when the number of alignment edges grows with the total edge count.
Compact surviving edges once and remove the trailing entries from the back, preserving edge order and making cleanup linear. Count the trailing entries before erasing to avoid comparing an invalidated iterator.
These results support the performance benefit, but they come from **GPT-generated** synthetic benchmarks and do not represent speedups on real BOLT workloads.
count | origin | new
-- | -- | --
16,384 | 92.6 ms | 6.2 ms
32,768 | 430.0 ms | 9.5 ms
65,536 | 1,732.3 ms | 16.2 ms
Assisted by GPT-6.
---
Full diff: https://github.com/llvm/llvm-project/pull/222317.diff
2 Files Affected:
- (modified) llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp (+9-6)
- (added) llvm/test/ExecutionEngine/JITLink/RISCV/ELF_relax_many_align.s (+29)
``````````diff
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
index 0dc97104610bb..4c9e5fb26b943 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
@@ -788,12 +788,15 @@ static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {
// Remove AlignRelaxable edges: all other relaxable edges got modified and
// will be used later while linking. Alignment is entirely handled here so we
// don't need these edges anymore.
- for (auto IE = Block.edges().begin(); IE != Block.edges().end();) {
- if (IE->getKind() == AlignRelaxable)
- IE = Block.removeEdge(IE);
- else
- ++IE;
- }
+ // Compact once: erasing each alignment edge separately repeatedly moves the
+ // remaining edges and is quadratic for large instrumented code blocks.
+ auto End = llvm::remove_if(Block.edges(), [](const Edge &E) {
+ return E.getKind() == AlignRelaxable;
+ });
+ const auto NumRemaining =
+ static_cast<size_t>(std::distance(Block.edges().begin(), End));
+ while (Block.edges_size() > NumRemaining)
+ Block.removeEdge(std::prev(Block.edges().end()));
}
static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) {
diff --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_relax_many_align.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_relax_many_align.s
new file mode 100644
index 0000000000000..257fabb7096b2
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_relax_many_align.s
@@ -0,0 +1,29 @@
+## Instrumented clang has many alignment edges mixed with call edges in one
+## code block. Removing alignment edges must preserve all remaining fixups.
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o %t.o
+# RUN: llvm-jitlink -noexec -slab-allocate 1Mb -slab-address 0x0 \
+# RUN: -slab-page-size 4096 -check %s %t.o
+
+ .text
+ .globl main, last, target
+main:
+ .rept 4096
+ call target
+ .balign 16
+ .endr
+last:
+ call target
+ .balign 16
+target:
+ ret
+ .size main, .-main
+ .size last, target-last
+ .size target, 4
+
+# jitlink-check: last - main = 65536
+# jitlink-check: target - last = 16
+# jitlink-check: decode_operand(main, 1) = (target - main)
+# jitlink-check: decode_operand(last, 1) = (target - last)
+# jitlink-check: *{4}(last + 4) = 0x13
+# jitlink-check: *{4}(last + 8) = 0x13
+# jitlink-check: *{4}(last + 12) = 0x13
``````````
</details>
https://github.com/llvm/llvm-project/pull/222317
More information about the llvm-commits
mailing list