[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