[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