diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 20bd8113cdb32..730ffabe829d6 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -969,7 +969,9 @@ an optional ``unnamed_addr`` attribute, a return type, an optional name, a (possibly empty) argument list (each with optional :ref:`parameter attributes `), optional :ref:`function attributes `, an optional address space, an optional section, an optional partition, -an optional alignment, an optional :ref:`comdat `, +an optional minimum alignment, +an optional preferred alignment, +an optional :ref:`comdat `, an optional :ref:`garbage collector name `, an optional :ref:`prefix `, an optional :ref:`prologue `, an optional :ref:`personality `, @@ -983,8 +985,8 @@ Syntax:: @ ([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: @@ -1034,11 +1036,20 @@ 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 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. 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 d976d40e5e956..c0614687ce2d9 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 { unsigned BlockNumEpoch = 0; mutable Argument *Arguments = nullptr; ///< The formal arguments - size_t NumArgs; + uint32_t NumArgs; + MaybeAlign PreferredAlign; std::unique_ptr SymTab; ///< Symbol table of args/instructions AttributeList AttributeSets; ///< Parameter attributes @@ -1043,6 +1044,12 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node { /// 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 f6937d38eb38c..00cf8a5202329 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 897e679095906..fb999970ce1c4 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1452,7 +1452,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); @@ -1551,7 +1551,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); @@ -2394,10 +2394,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; @@ -2707,7 +2708,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; } @@ -6717,7 +6718,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; @@ -6734,7 +6735,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)) || @@ -6836,6 +6838,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); @@ -8458,7 +8461,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; @@ -8473,7 +8476,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 832aa9ff7ed3d..59d3b102c8053 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4385,6 +4385,13 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef 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 c4070e1f44688..77c4b44fabfff 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 245129f3f791f..936de833e0180 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -4169,6 +4169,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"