[llvm] [MC][test] Add relax-branch-align.s demonstrating unnecessary branch relaxation (PR #184551)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 3 22:09:27 PST 2026
https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/184551
The two-pass relaxation approach (relaxFragment, then layoutSection)
can unnecessarily relax a backward branch from short (2B) to near (5B).
When a forward branch relaxes (2B->6B), it shifts the backward target
by +4B. A .p2align between target and source absorbs this growth. The
true displacement is -125 (fits short), but the two-pass approach
evaluates the backward branch with stale target offsets, seeing -129
(beyond [-128,127]) and relaxing it unnecessarily.
>From 0c82e768ddbec46f1a0e967e055ff63eacd748f7 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Tue, 3 Mar 2026 22:08:48 -0800
Subject: [PATCH] [MC][test] Add relax-branch-align.s demonstrating unnecessary
branch relaxation
The two-pass relaxation approach (relaxFragment, then layoutSection)
can unnecessarily relax a backward branch from short (2B) to near (5B).
When a forward branch relaxes (2B->6B), it shifts the backward target
by +4B. A .p2align between target and source absorbs this growth. The
true displacement is -125 (fits short), but the two-pass approach
evaluates the backward branch with stale target offsets, seeing -129
(beyond [-128,127]) and relaxing it unnecessarily.
---
llvm/test/MC/ELF/relax-branch-align.s | 49 +++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 llvm/test/MC/ELF/relax-branch-align.s
diff --git a/llvm/test/MC/ELF/relax-branch-align.s b/llvm/test/MC/ELF/relax-branch-align.s
new file mode 100644
index 0000000000000..680bd98d452c5
--- /dev/null
+++ b/llvm/test/MC/ELF/relax-branch-align.s
@@ -0,0 +1,49 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: llvm-objdump -d --no-show-raw-insn %t.o | FileCheck %s
+
+## In the initial all-short layout, `jmp target` has displacement -129 (1 beyond
+## [-128,127]). `je far_target` relaxes from 2B to 6B, shifting `target` by
+## +4B, and `.p2align 4` absorbs this growth. With fresh offsets, the true
+## displacement is -125, which fits in a short jmp.
+##
+## The two-pass approach (relaxFragment, then layoutSection) evaluates the
+## backward jmp with stale target offsets (before je relaxation shifts it),
+## causing unnecessary relaxation from short (2B) to near (5B).
+
+ .text
+ .p2align 4
+func:
+ je far_target
+target:
+ pushq %rbp
+ pushq %rbx
+ movl %edi, %ebx
+ xorl %eax, %eax
+ movq 8(%rsi), %rcx
+ .rept 28
+ testq %rcx, %rcx
+ .endr
+ jmp past_loop
+ .p2align 4
+loop:
+ movq (%r8), %r8
+ testq %r8, %r8
+ je after
+past_loop:
+ cmpq %rdi, (%r8)
+ jne loop
+ cmpl %esi, 8(%r8)
+## The jmp is unnecessarily relaxed to near (5B). after is at 0x86 instead of
+## 0x83.
+# CHECK: 81: jmp 0x6 <target>
+# CHECK-EMPTY:
+# CHECK-NEXT: 0000000000000086 <after>:
+ jmp target
+after:
+ popq %rbx
+ popq %rbp
+ ret
+
+ .space 200
+far_target:
+ ret
More information about the llvm-commits
mailing list