[llvm] [AsmPrinter] Fix redundant/weaker .prefalign when IR align attr >= prefalign (PR #191675)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 11 16:38:30 PDT 2026
https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/191675
PR #155529 (only fired with -ffunction-sections, then modified by PR
184032) compared `MF->getAlignment()` (the backend's minimum function
alignment) against `MF->getPreferredAlignment()` to decide whether to
emit `.prefalign`. This ignored the IR function's own align attribute,
which `emitAlignment` picks up later via `getGVAlignment`, so the
comparison was against the wrong minimum.
Consequences on x86 (backend min = 1, target pref = 16):
* `[[gnu::aligned(32)]] void g(){}` lowers to `align 32 prefalign(32)`.
.p2align 5
.prefalign 5, .Lfunc_end, nop
The .prefalign is fully redundant: .p2align 5 already forces the
desired 32-byte alignment.
* `define void @f4() align 32 prefalign(16)`.
.p2align 5
.prefalign 4, .Lfunc_end, nop
Here .prefalign with a weak alignment is harmless but the assembly
output is nonsensical.
This patch updates `emitAlignment` to return the effective alignment it
emits and use that as the true minimum in `emitFunctionHeader`.
>From 03f14231d293a9e8d21feee48ba0e5b4471c3206 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 11 Apr 2026 14:24:15 -0700
Subject: [PATCH] [AsmPrinter] Fix redundant/weaker .prefalign when IR align
attr >= prefalign
PR #155529 (only fired with -ffunction-sections, then modified by PR
184032) compared `MF->getAlignment()` (the backend's minimum function
alignment) against `MF->getPreferredAlignment()` to decide whether to
emit `.prefalign`. This ignored the IR function's own align attribute,
which `emitAlignment` picks up later via `getGVAlignment`, so the
comparison was against the wrong minimum.
Consequences on x86 (backend min = 1, target pref = 16):
* `[[gnu::aligned(32)]] void g(){}` lowers to `align 32 prefalign(32)`.
.p2align 5
.prefalign 5, .Lfunc_end, nop
The .prefalign is fully redundant: .p2align 5 already forces the
desired 32-byte alignment.
* `define void @f4() align 32 prefalign(16)`.
.p2align 5
.prefalign 4, .Lfunc_end, nop
Here .prefalign with a weak alignment is harmless but the assembly
output is nonsensical.
This patch updates `emitAlignment` to return the effective alignment it
emits and use that as the true minimum in `emitFunctionHeader`.
---
llvm/include/llvm/CodeGen/AsmPrinter.h | 7 +++--
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 32 ++++++++++++----------
llvm/test/CodeGen/X86/prefalign.ll | 15 ++++++++++
3 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 7b480e45cab88..7b25ca43c2de9 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -570,9 +570,10 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
/// Emit an alignment directive to the specified power of two boundary. If a
/// global value is specified, and if that global has an explicit alignment
/// requested, it will override the alignment request if required for
- /// correctness.
- void emitAlignment(Align Alignment, const GlobalObject *GV = nullptr,
- unsigned MaxBytesToEmit = 0) const;
+ /// correctness. Returns the effective alignment that was emitted (which may
+ /// exceed \p Alignment when \p GV has a stricter explicit alignment).
+ Align emitAlignment(Align Alignment, const GlobalObject *GV = nullptr,
+ unsigned MaxBytesToEmit = 0) const;
/// Lower the specified LLVM Constant to an MCExpr.
/// When BaseCV is present, we are lowering the element at BaseCV plus Offset.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index a5ac1ca100d96..2225c24fcd7be 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1049,17 +1049,20 @@ void AsmPrinter::emitFunctionHeader() {
emitLinkage(&F, CurrentFnSym);
if (MAI->hasFunctionAlignment()) {
Align PrefAlign = MF->getPreferredAlignment();
- // Use .prefalign when the integrated assembler supports it and the target
- // has a preferred alignment distinct from the minimum. The end symbol must
- // be created here, before the function body, so that .prefalign can
- // reference it; emitFunctionBody will emit the label at the function end.
- if (MAI->useIntegratedAssembler() && MAI->hasPreferredAlignment() &&
- MF->getAlignment() != PrefAlign) {
- emitAlignment(MF->getAlignment(), &F);
- CurrentFnEnd = createTempSymbol("func_end");
- OutStreamer->emitPrefAlign(PrefAlign, *CurrentFnEnd,
- /*EmitNops=*/true, /*Fill=*/0,
- getSubtargetInfo());
+ if (MAI->useIntegratedAssembler() && MAI->hasPreferredAlignment()) {
+ // Emit .p2align for the effective minimum alignment (which accounts for
+ // F's own align attribute via getGVAlignment), then emit .prefalign only
+ // when the preferred alignment is greater. The end symbol must be
+ // created here, before the function body, so that .prefalign can
+ // reference it; emitFunctionBody will emit the label at the function
+ // end.
+ Align MinAlign = emitAlignment(MF->getAlignment(), &F);
+ if (MinAlign < PrefAlign) {
+ CurrentFnEnd = createTempSymbol("func_end");
+ OutStreamer->emitPrefAlign(PrefAlign, *CurrentFnEnd,
+ /*EmitNops=*/true, /*Fill=*/0,
+ getSubtargetInfo());
+ }
} else {
emitAlignment(PrefAlign, &F);
}
@@ -3840,13 +3843,13 @@ void AsmPrinter::emitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset,
// two boundary. If a global value is specified, and if that global has
// an explicit alignment requested, it will override the alignment request
// if required for correctness.
-void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV,
- unsigned MaxBytesToEmit) const {
+Align AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV,
+ unsigned MaxBytesToEmit) const {
if (GV)
Alignment = getGVAlignment(GV, GV->getDataLayout(), Alignment);
if (Alignment == Align(1))
- return; // 1-byte aligned: no need to emit alignment.
+ return Alignment; // 1-byte aligned: no need to emit alignment.
if (getCurrentSection()->isText()) {
const MCSubtargetInfo *STI = nullptr;
@@ -3857,6 +3860,7 @@ void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV,
OutStreamer->emitCodeAlignment(Alignment, STI, MaxBytesToEmit);
} else
OutStreamer->emitValueToAlignment(Alignment, 0, 1, MaxBytesToEmit);
+ return Alignment;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/X86/prefalign.ll b/llvm/test/CodeGen/X86/prefalign.ll
index c5d5a9223c2ba..3a95bbfdbd4db 100644
--- a/llvm/test/CodeGen/X86/prefalign.ll
+++ b/llvm/test/CodeGen/X86/prefalign.ll
@@ -23,3 +23,18 @@ define void @f2() prefalign(1) {
define void @f3() align 2 prefalign(4) {
ret void
}
+
+;; When align >= prefalign, the .prefalign would be redundant.
+; CHECK: .globl f4
+; CHECK-NEXT: .p2align 5
+; CHECK-NOT: .prefalign
+define void @f4() align 32 prefalign(16) {
+ ret void
+}
+
+; CHECK: .globl f5
+; CHECK-NEXT: .p2align 4
+; CHECK-NOT: .prefalign
+define void @f5() align 16 prefalign(16) {
+ ret void
+}
More information about the llvm-commits
mailing list