[llvm] IR: Add prefalign attribute for function definitions. (PR #155527)

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 27 16:16:04 PDT 2025


https://github.com/pcc updated https://github.com/llvm/llvm-project/pull/155527

>From 9c7c77e25a2ab3009d9c63168797003150d6220f Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter at pcc.me.uk>
Date: Tue, 26 Aug 2025 17:12:11 -0700
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.6-beta.1
---
 llvm/docs/LangRef.rst                     | 31 +++++++++++++++++------
 llvm/include/llvm/AsmParser/LLParser.h    |  2 +-
 llvm/include/llvm/AsmParser/LLToken.h     |  1 +
 llvm/include/llvm/IR/Function.h           |  9 ++++++-
 llvm/lib/AsmParser/LLLexer.cpp            |  1 +
 llvm/lib/AsmParser/LLParser.cpp           | 23 +++++++++--------
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  7 +++++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |  4 ++-
 llvm/lib/IR/AsmWriter.cpp                 |  2 ++
 llvm/test/Bitcode/compatibility.ll        | 14 ++++++++++
 10 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index b122fd352eaf5..80f9b7c150b67 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -877,7 +877,9 @@ an optional ``unnamed_addr`` attribute, a return type, an optional
 name, a (possibly empty) argument list (each with optional :ref:`parameter
 attributes <paramattrs>`), optional :ref:`function attributes <fnattrs>`,
 an optional address space, an optional section, an optional partition,
-an optional alignment, an optional :ref:`comdat <langref_comdats>`,
+an optional minimum alignment,
+an optional preferred alignment,
+an optional :ref:`comdat <langref_comdats>`,
 an optional :ref:`garbage collector name <gc>`, an optional :ref:`prefix <prefixdata>`,
 an optional :ref:`prologue <prologuedata>`,
 an optional :ref:`personality <personalityfn>`,
@@ -891,8 +893,8 @@ Syntax::
            <ResultType> @<FunctionName> ([argument list])
            [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [fn Attrs]
            [section "name"] [partition "name"] [comdat [($name)]] [align N]
-           [gc] [prefix Constant] [prologue Constant] [personality Constant]
-           (!name !N)* { ... }
+           [prefalign N] [gc] [prefix Constant] [prologue Constant]
+           [personality Constant] (!name !N)* { ... }
 
 The argument list is a comma-separated sequence of arguments where each
 argument is of the following form:
@@ -942,11 +944,24 @@ LLVM allows an explicit section to be specified for functions. If the
 target supports it, it will emit functions to the section specified.
 Additionally, the function can be placed in a COMDAT.
 
-An explicit alignment may be specified for a function. If not present,
-or if the alignment is set to zero, the alignment of the function is set
-by the target to whatever it feels convenient. If an explicit alignment
-is specified, the function is forced to have at least that much
-alignment. All alignments must be a power of 2.
+An explicit minimum alignment (``align``) may be specified for a
+function. If not present, or if the alignment is set to zero, the
+alignment of the function is set according to the preferred alignment
+rules described below. If an explicit minimum alignment is specified, the
+function is forced to have at least that much alignment. All alignments
+must be a power of 2.
+
+An explicit preferred alignment (``prefalign``) may also be specified
+for a function (definitions only, and must be a power of 2). If a
+function does not have a preferred alignment attribute, the preferred
+alignment is determined in a target-specific way. The final alignment
+of the function is determined in the following way: if the function
+size is less than the minimum alignment, the function's alignment will
+be at least the minimum alignment. Otherwise, if the function size is
+between the minimum alignment and the preferred alignment, the function's
+alignment will be at least the power of 2 greater than or equal to the
+function size. Otherwise, the function's alignment will be at least the
+preferred alignment.
 
 If the ``unnamed_addr`` attribute is given, the address is known to not
 be significant and two identical functions can be merged.
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index c01de4a289a69..5970b388b6bcd 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -311,7 +311,7 @@ namespace llvm {
                                  GlobalValueSummary::ImportKind &Res);
     void parseOptionalDLLStorageClass(unsigned &Res);
     bool parseOptionalCallingConv(unsigned &CC);
-    bool parseOptionalAlignment(MaybeAlign &Alignment,
+    bool parseOptionalAlignment(lltok::Kind KW, MaybeAlign &Alignment,
                                 bool AllowParens = false);
     bool parseOptionalCodeModel(CodeModel::Model &model);
     bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index e6a0eae9da30c..65d52747abc62 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -130,6 +130,7 @@ enum Kind {
   kw_prefix,
   kw_prologue,
   kw_c,
+  kw_prefalign,
 
   kw_cc,
   kw_ccc,
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index d3497716ca844..0f9f526556847 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -85,7 +85,8 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
   unsigned BlockNumEpoch = 0;
 
   mutable Argument *Arguments = nullptr;  ///< The formal arguments
-  size_t NumArgs;
+  uint32_t NumArgs;
+  MaybeAlign PreferredAlign;
   std::unique_ptr<ValueSymbolTable>
       SymTab;                             ///< Symbol table of args/instructions
   AttributeList AttributeSets;            ///< Parameter attributes
@@ -1043,6 +1044,12 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
   /// defined.
   void setAlignment(MaybeAlign Align) { GlobalObject::setAlignment(Align); }
 
+  /// Returns the prefalign of the given function.
+  MaybeAlign getPreferredAlignment() const { return PreferredAlign; }
+
+  /// Sets the prefalign attribute of the Function.
+  void setPreferredAlignment(MaybeAlign Align) { PreferredAlign = Align; }
+
   /// Return the value for vscale based on the vscale_range attribute or 0 when
   /// unknown.
   unsigned getVScaleValue() const;
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 3d5bd6155536e..e51ab2c584770 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -625,6 +625,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(gc);
   KEYWORD(prefix);
   KEYWORD(prologue);
+  KEYWORD(prefalign);
 
   KEYWORD(no_sanitize_address);
   KEYWORD(no_sanitize_hwaddress);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 1bc2906f63b07..415a7b99a3c80 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1449,7 +1449,7 @@ bool LLParser::parseGlobal(const std::string &Name, unsigned NameID,
         return true;
     } else if (Lex.getKind() == lltok::kw_align) {
       MaybeAlign Alignment;
-      if (parseOptionalAlignment(Alignment))
+      if (parseOptionalAlignment(lltok::kw_align, Alignment))
         return true;
       if (Alignment)
         GV->setAlignment(*Alignment);
@@ -1548,7 +1548,7 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
         return true;
       Alignment = Align(Value);
     } else {
-      if (parseOptionalAlignment(Alignment, true))
+      if (parseOptionalAlignment(lltok::kw_align, Alignment, true))
         return true;
     }
     B.addAlignmentAttr(Alignment);
@@ -2382,10 +2382,11 @@ bool LLParser::parseOptionalFunctionMetadata(Function &F) {
 
 /// parseOptionalAlignment
 ///   ::= /* empty */
-///   ::= 'align' 4
-bool LLParser::parseOptionalAlignment(MaybeAlign &Alignment, bool AllowParens) {
+///   ::= KW 4
+bool LLParser::parseOptionalAlignment(lltok::Kind KW, MaybeAlign &Alignment,
+                                      bool AllowParens) {
   Alignment = std::nullopt;
-  if (!EatIfPresent(lltok::kw_align))
+  if (!EatIfPresent(KW))
     return false;
   LocTy AlignLoc = Lex.getLoc();
   uint64_t Value = 0;
@@ -2695,7 +2696,7 @@ bool LLParser::parseOptionalCommaAlign(MaybeAlign &Alignment,
     if (Lex.getKind() != lltok::kw_align)
       return error(Lex.getLoc(), "expected metadata or 'align'");
 
-    if (parseOptionalAlignment(Alignment))
+    if (parseOptionalAlignment(lltok::kw_align, Alignment))
       return true;
   }
 
@@ -6705,7 +6706,7 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
   LocTy BuiltinLoc;
   std::string Section;
   std::string Partition;
-  MaybeAlign Alignment;
+  MaybeAlign Alignment, PrefAlignment;
   std::string GC;
   GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
   unsigned AddrSpace = 0;
@@ -6722,7 +6723,8 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
       (EatIfPresent(lltok::kw_section) && parseStringConstant(Section)) ||
       (EatIfPresent(lltok::kw_partition) && parseStringConstant(Partition)) ||
       parseOptionalComdat(FunctionName, C) ||
-      parseOptionalAlignment(Alignment) ||
+      parseOptionalAlignment(lltok::kw_align, Alignment) ||
+      parseOptionalAlignment(lltok::kw_prefalign, PrefAlignment) ||
       (EatIfPresent(lltok::kw_gc) && parseStringConstant(GC)) ||
       (EatIfPresent(lltok::kw_prefix) && parseGlobalTypeAndValue(Prefix)) ||
       (EatIfPresent(lltok::kw_prologue) && parseGlobalTypeAndValue(Prologue)) ||
@@ -6824,6 +6826,7 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
   Fn->setUnnamedAddr(UnnamedAddr);
   if (Alignment)
     Fn->setAlignment(*Alignment);
+  Fn->setPreferredAlignment(PrefAlignment);
   Fn->setSection(Section);
   Fn->setPartition(Partition);
   Fn->setComdat(C);
@@ -8446,7 +8449,7 @@ int LLParser::parseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
   bool AteExtraComma = false;
   if (EatIfPresent(lltok::comma)) {
     if (Lex.getKind() == lltok::kw_align) {
-      if (parseOptionalAlignment(Alignment))
+      if (parseOptionalAlignment(lltok::kw_align, Alignment))
         return true;
       if (parseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma))
         return true;
@@ -8461,7 +8464,7 @@ int LLParser::parseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
         return true;
       if (EatIfPresent(lltok::comma)) {
         if (Lex.getKind() == lltok::kw_align) {
-          if (parseOptionalAlignment(Alignment))
+          if (parseOptionalAlignment(lltok::kw_align, Alignment))
             return true;
           if (parseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma))
             return true;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 22a0d0ffdbaab..abdd58eeed612 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -4385,6 +4385,13 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
     Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18]));
   }
 
+  if (Record.size() > 19) {
+    MaybeAlign PrefAlignment;
+    if (Error Err = parseAlignmentValue(Record[19], PrefAlignment))
+      return Err;
+    Func->setPreferredAlignment(PrefAlignment);
+  }
+
   ValueList.push_back(Func, getVirtualTypeID(Func->getType(), FTyID));
 
   if (OperandInfo.PersonalityFn || OperandInfo.Prefix || OperandInfo.Prologue)
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index a1d5b36bde64d..edb125a214405 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1644,7 +1644,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
     // FUNCTION:  [strtab offset, strtab size, type, callingconv, isproto,
     //             linkage, paramattrs, alignment, section, visibility, gc,
     //             unnamed_addr, prologuedata, dllstorageclass, comdat,
-    //             prefixdata, personalityfn, DSO_Local, addrspace]
+    //             prefixdata, personalityfn, DSO_Local, addrspace,
+    //             partition_strtab, partition_size, prefalign]
     Vals.push_back(addToStrtab(F.getName()));
     Vals.push_back(F.getName().size());
     Vals.push_back(VE.getTypeID(F.getFunctionType()));
@@ -1671,6 +1672,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
     Vals.push_back(F.getAddressSpace());
     Vals.push_back(addToStrtab(F.getPartition()));
     Vals.push_back(F.getPartition().size());
+    Vals.push_back(getEncodedAlign(F.getPreferredAlignment()));
 
     unsigned AbbrevToUse = 0;
     Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index dc6d599fa9585..3d3d3ba2eee33 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -4229,6 +4229,8 @@ void AssemblyWriter::printFunction(const Function *F) {
   maybePrintComdat(Out, *F);
   if (MaybeAlign A = F->getAlign())
     Out << " align " << A->value();
+  if (MaybeAlign A = F->getPreferredAlignment())
+    Out << " prefalign " << A->value();
   if (F->hasGC())
     Out << " gc \"" << F->getGC() << '"';
   if (F->hasPrefixData()) {
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 0b5ce08c00a23..b02cf1feed04e 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -759,6 +759,20 @@ declare void @f.align4() align 4
 declare void @f.align8() align 8
 ; CHECK: declare void @f.align8() align 8
 
+; Functions -- prefalign
+define void @f.prefalign2() prefalign 2 {
+  ret void
+}
+; CHECK: define void @f.prefalign2() prefalign 2
+define void @f.prefalign4() prefalign 4 {
+  ret void
+}
+; CHECK: define void @f.prefalign4() prefalign 4
+define void @f.prefalign8() prefalign 8 {
+  ret void
+}
+; CHECK: define void @f.prefalign8() prefalign 8
+
 ; Functions -- GC
 declare void @f.gcshadow() gc "shadow-stack"
 ; CHECK: declare void @f.gcshadow() gc "shadow-stack"

>From 01306bf7ecc9529ef73b638139686d06fd155a2c Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter at pcc.me.uk>
Date: Wed, 27 Aug 2025 16:15:49 -0700
Subject: [PATCH 2/2] Reword langref

Created using spr 1.3.6-beta.1
---
 llvm/docs/LangRef.rst | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 80f9b7c150b67..12337beb7e579 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -951,17 +951,13 @@ rules described below. If an explicit minimum alignment is specified, the
 function is forced to have at least that much alignment. All alignments
 must be a power of 2.
 
-An explicit preferred alignment (``prefalign``) may also be specified
-for a function (definitions only, and must be a power of 2). If a
-function does not have a preferred alignment attribute, the preferred
-alignment is determined in a target-specific way. The final alignment
-of the function is determined in the following way: if the function
-size is less than the minimum alignment, the function's alignment will
-be at least the minimum alignment. Otherwise, if the function size is
-between the minimum alignment and the preferred alignment, the function's
-alignment will be at least the power of 2 greater than or equal to the
-function size. Otherwise, the function's alignment will be at least the
-preferred alignment.
+An explicit preferred alignment (``prefalign``) may also be specified for
+a function (definitions only, and must be a power of 2). If a function
+does not have a preferred alignment attribute, the preferred alignment
+is determined in a target-specific way. The preferred alignment, if
+provided, is treated as a hint; the final alignment of the function will
+generally be set to a value somewhere between the minimum alignment and
+the preferred alignment.
 
 If the ``unnamed_addr`` attribute is given, the address is known to not
 be significant and two identical functions can be merged.



More information about the llvm-commits mailing list