-
Notifications
You must be signed in to change notification settings - Fork 15.2k
IR: Add prefalign attribute for function definitions. #155527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
IR: Add prefalign attribute for function definitions. #155527
Conversation
Created using spr 1.3.6-beta.1
@llvm/pr-subscribers-llvm-ir Author: Peter Collingbourne (pcc) ChangesThe prefalign attribute determines the function's preferred alignment. The backend logic will be added in followup patches. Part of this RFC: Full diff: https://github.com/llvm/llvm-project/pull/155527.diff 10 Files Affected:
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"
|
llvm/docs/LangRef.rst
Outdated
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems overly specific: if you read it literally, it means that we have to precisely compute the size of the function, which is probably not feasible in general, and that optimizations aren't allowed to modify prefalign. I think I'd prefer to say it's a hint, which can be overriden by PGO/CFI jump tables/etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted this to describe the lower bound on the alignment (because e.g. non-ELF or -fno-function-sections can result in a higher alignment), but yeah, it's probably best just to say that it's a hint; the actual rules are too complex to specify here. Done.
Created using spr 1.3.6-beta.1
Ping |
Ping |
The prefalign attribute determines the function's preferred alignment.
By default, the function's preferred alignment is set in a target-specific
way, but it may be overridden with this attribute.
The backend logic will be added in followup patches.
Part of this RFC:
https://discourse.llvm.org/t/rfc-enhancing-function-alignment-attributes/88019