[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