diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2025-09-12 14:34:10 -0700 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2025-09-12 14:34:10 -0700 |
commit | ecfc7c072576dfdd211361eec08b84ea86d5246a (patch) | |
tree | 262893407429b63e487c3a8ac99a58a9f5d28ccb | |
parent | e1efb51080801575712069a0b17a1656b66e7dfe (diff) | |
download | llvm-users/pcc/spr/main.codegen-introduce-machinefunctiongetpreferredalignment.zip llvm-users/pcc/spr/main.codegen-introduce-machinefunctiongetpreferredalignment.tar.gz llvm-users/pcc/spr/main.codegen-introduce-machinefunctiongetpreferredalignment.tar.bz2 |
[𝘀𝗽𝗿] changes to main this commit is based onusers/pcc/spr/main.codegen-introduce-machinefunctiongetpreferredalignment
Created using spr 1.3.6-beta.1
[skip ci]
31 files changed, 304 insertions, 35 deletions
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 84f5ab3..d4b7fd6 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -420,6 +420,7 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest, NotCompatible, "with") VALUE_LANGOPT(FunctionAlignment, 5, 0, Compatible, "Default alignment for functions") +VALUE_LANGOPT(PreferredFunctionAlignment, 5, 0, Compatible, "Preferred alignment for functions") VALUE_LANGOPT(LoopAlignment, 32, 0, Compatible, "Default alignment for loops") LANGOPT(FixedPoint, 1, 0, NotCompatible, "fixed point types") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index a7c514e..2c04ed9 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1550,6 +1550,8 @@ defm access_control : BoolFOption<"access-control", PosFlag<SetTrue>>; def falign_functions : Flag<["-"], "falign-functions">, Group<f_Group>; def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<f_Group>; +def fpreferred_function_alignment_EQ : + Joined<["-"], "fpreferred-function-alignment=">, Group<f_Group>; def falign_loops_EQ : Joined<["-"], "falign-loops=">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"<N>">, HelpText<"N must be a power of two. Align loops to the boundary">, @@ -8471,6 +8473,9 @@ def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signa def function_alignment : Separate<["-"], "function-alignment">, HelpText<"default alignment for functions">, MarshallingInfoInt<LangOpts<"FunctionAlignment">>; +def preferred_function_alignment : Separate<["-"], "preferred-function-alignment">, + HelpText<"preferred alignment for functions">, + MarshallingInfoInt<LangOpts<"PreferredFunctionAlignment">>; def fhalf_no_semantic_interposition : Flag<["-"], "fhalf-no-semantic-interposition">, HelpText<"Like -fno-semantic-interposition but don't use local aliases">, MarshallingInfoFlag<LangOpts<"HalfNoSemanticInterposition">>; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a16dfb5..73e3378 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2798,13 +2798,19 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, F->addFnAttrs(B); - unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); - if (alignment) - F->setAlignment(llvm::Align(alignment)); - - if (!D->hasAttr<AlignedAttr>()) - if (LangOpts.FunctionAlignment) - F->setAlignment(llvm::Align(1ull << LangOpts.FunctionAlignment)); + llvm::MaybeAlign ExplicitAlignment; + if (unsigned alignment = D->getMaxAlignment() / Context.getCharWidth()) + ExplicitAlignment = llvm::Align(alignment); + else if (LangOpts.FunctionAlignment) + ExplicitAlignment = llvm::Align(1ull << LangOpts.FunctionAlignment); + + if (ExplicitAlignment) { + F->setAlignment(ExplicitAlignment); + F->setPreferredAlignment(ExplicitAlignment); + } else if (LangOpts.PreferredFunctionAlignment) { + F->setPreferredAlignment( + llvm::Align(1ull << LangOpts.PreferredFunctionAlignment)); + } // Some C++ ABIs require 2-byte alignment for member functions, in order to // reserve a bit for differentiating between virtual and non-virtual member diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 946b1e3..efb35f4 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -46,6 +46,7 @@ #include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/YAMLParser.h" @@ -5485,6 +5486,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); } + if (const Arg *A = Args.getLastArg(options::OPT_fpreferred_function_alignment_EQ)) { + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536 || + !llvm::isPowerOf2_32(Value)) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + + CmdArgs.push_back("-preferred-function-alignment"); + CmdArgs.push_back(Args.MakeArgString( + std::to_string(llvm::Log2_32_Ceil(std::min(Value, 65536u))))); + } + // We support -falign-loops=N where N is a power of 2. GCC supports more // forms. if (const Arg *A = Args.getLastArg(options::OPT_falign_loops_EQ)) { diff --git a/clang/test/CodeGen/prefalign.c b/clang/test/CodeGen/prefalign.c new file mode 100644 index 0000000..2370585 --- /dev/null +++ b/clang/test/CodeGen/prefalign.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown-linux -preferred-function-alignment 4 %s -o - | FileCheck %s + +// CHECK: define {{.*}} void @f() {{.*}} prefalign 16 +void f() {} diff --git a/clang/test/CodeGenCXX/member-alignment.cpp b/clang/test/CodeGenCXX/member-alignment.cpp index d5c9a5a..37ee733 100644 --- a/clang/test/CodeGenCXX/member-alignment.cpp +++ b/clang/test/CodeGenCXX/member-alignment.cpp @@ -31,9 +31,9 @@ public: [[gnu::aligned(16)]] void t::baz(void) { -// CHECK-NOEXTRAALIGN: @_ZN1t3bazEv({{.*}}) #0 align 16 { -// CHECK-EXTRAALIGN: @_ZN1t3bazEv({{.*}}) #0 align 16 { -// CHECK-MSVC: @"?baz@t@@QEAAXXZ"({{.*}}) #0 align 16 { +// CHECK-NOEXTRAALIGN: @_ZN1t3bazEv({{.*}}) #0 align 16 prefalign 16 { +// CHECK-EXTRAALIGN: @_ZN1t3bazEv({{.*}}) #0 align 16 prefalign 16 { +// CHECK-MSVC: @"?baz@t@@QEAAXXZ"({{.*}}) #0 align 16 prefalign 16 { } void diff --git a/clang/test/Driver/prefalign.c b/clang/test/Driver/prefalign.c new file mode 100644 index 0000000..de52f2d --- /dev/null +++ b/clang/test/Driver/prefalign.c @@ -0,0 +1,5 @@ +// RUN: %clang -### -fpreferred-function-alignment=16 %s 2>&1 | FileCheck %s -check-prefix CHECK-16 +// RUN: not %clang -### -fpreferred-function-alignment=3 %s 2>&1 | FileCheck %s -check-prefix CHECK-INVALID + +// CHECK-16: "-preferred-function-alignment" "4" +// CHECK-INVALID: invalid integral value '3' in '-fpreferred-function-alignment=3' diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst index 89a0e80..ecce9e1 100644 --- a/llvm/docs/Extensions.rst +++ b/llvm/docs/Extensions.rst @@ -28,6 +28,21 @@ hexadecimal format instead of decimal if desired. .section .data .float 0x1c2.2ap3 +``.prefalign`` directive +------------------------ + +The ``.prefalign`` directive sets the preferred alignment for a section, +and enables the section's final alignment to be set in a way that is +dependent on the section size (currently only supported with ELF). + +If the section size is less than the section's minimum alignment as +determined using ``.align`` family directives, the section's alignment +will be equal to its minimum alignment. Otherwise, if the section size is +between the minimum alignment and the preferred alignment, the section's +alignment will be equal to the power of 2 greater than or equal to the +section size. Otherwise, the section's alignment will be equal to the +preferred alignment. + Machine-specific Assembly Syntax ================================ diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index d61ea07..0429c947 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,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 c01de4a..5970b38 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 e6a0eae..65d5274 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 d349771..0f9f5265 100644 --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -85,7 +85,8 @@ private: 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 @@ public: /// 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/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h index 6c12cd3..af52e30 100644 --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -301,6 +301,9 @@ protected: // most targets, so defaults to true. bool HasFunctionAlignment = true; + // True if the target respects .prefalign directives. + bool HasPreferredAlignment = false; + /// True if the target has .type and .size directives, this is true for most /// ELF targets. Defaults to true. bool HasDotTypeDotSizeDirective = true; @@ -603,6 +606,7 @@ public: } bool hasFunctionAlignment() const { return HasFunctionAlignment; } + bool hasPreferredAlignment() const { return HasPreferredAlignment; } bool hasDotTypeDotSizeDirective() const { return HasDotTypeDotSizeDirective; } bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } bool hasIdentDirective() const { return HasIdentDirective; } diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h index b9e813b..5f5c504 100644 --- a/llvm/include/llvm/MC/MCObjectStreamer.h +++ b/llvm/include/llvm/MC/MCObjectStreamer.h @@ -137,6 +137,7 @@ public: unsigned MaxBytesToEmit = 0) override; void emitCodeAlignment(Align ByteAlignment, const MCSubtargetInfo *STI, unsigned MaxBytesToEmit = 0) override; + void emitPrefAlign(Align Alignment) override; void emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) override; void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h index 12389d6..f8b9c38 100644 --- a/llvm/include/llvm/MC/MCSection.h +++ b/llvm/include/llvm/MC/MCSection.h @@ -525,6 +525,7 @@ private: MCSymbol *End = nullptr; /// The alignment requirement of this section. Align Alignment; + MaybeAlign PreferredAlignment; /// The section index in the assemblers section list. unsigned Ordinal = 0; // If not -1u, the first linker-relaxable fragment's order within the @@ -585,6 +586,19 @@ public: Alignment = MinAlignment; } + Align getPreferredAlignment() const { + if (!PreferredAlignment || Alignment > *PreferredAlignment) + return Alignment; + return *PreferredAlignment; + } + + void ensurePreferredAlignment(Align PrefAlign) { + if (!PreferredAlignment || PrefAlign > *PreferredAlignment) + PreferredAlignment = PrefAlign; + } + + Align getAlignmentForObjectFile(uint64_t Size) const; + unsigned getOrdinal() const { return Ordinal; } void setOrdinal(unsigned Value) { Ordinal = Value; } diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 79c715e..0cc42f0 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -839,6 +839,8 @@ public: virtual void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI, unsigned MaxBytesToEmit = 0); + virtual void emitPrefAlign(Align A); + /// Emit some number of copies of \p Value until the byte offset \p /// Offset is reached. /// diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 3d5bd61..e51ab2c 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 1bc2906..415a7b9 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 22a0d0f..abdd58e 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 a1d5b36..edb125a 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 094678f..7425c9a 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -4231,6 +4231,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/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index 759d3e0..3d7f503 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -912,10 +912,10 @@ void ELFWriter::writeSectionHeader(uint32_t GroupSymbolIndex, uint64_t Offset, sh_link = Sym->getSection().getOrdinal(); } - writeSectionHeaderEntry(StrTabBuilder.getOffset(Section.getName()), - Section.getType(), Section.getFlags(), 0, Offset, - Size, sh_link, sh_info, Section.getAlign(), - Section.getEntrySize()); + writeSectionHeaderEntry( + StrTabBuilder.getOffset(Section.getName()), Section.getType(), + Section.getFlags(), 0, Offset, Size, sh_link, sh_info, + Section.getAlignmentForObjectFile(Size), Section.getEntrySize()); } void ELFWriter::writeSectionHeaders() { diff --git a/llvm/lib/MC/MCAsmInfoELF.cpp b/llvm/lib/MC/MCAsmInfoELF.cpp index cdae9d7..cb5244f 100644 --- a/llvm/lib/MC/MCAsmInfoELF.cpp +++ b/llvm/lib/MC/MCAsmInfoELF.cpp @@ -41,6 +41,7 @@ bool MCAsmInfoELF::useCodeAlign(const MCSection &Sec) const { MCAsmInfoELF::MCAsmInfoELF() { HasIdentDirective = true; + HasPreferredAlignment = true; WeakRefDirective = "\t.weak\t"; PrivateGlobalPrefix = ".L"; PrivateLabelPrefix = ".L"; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index be8c022..47002db 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -274,6 +274,7 @@ public: void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI, unsigned MaxBytesToEmit = 0) override; + void emitPrefAlign(Align Alignment) override; void emitValueToOffset(const MCExpr *Offset, unsigned char Value, @@ -1540,6 +1541,11 @@ void MCAsmStreamer::emitCodeAlignment(Align Alignment, emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit); } +void MCAsmStreamer::emitPrefAlign(Align Alignment) { + OS << "\t.prefalign\t" << Alignment.value(); + EmitEOL(); +} + void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) { diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 59265bc..f638783 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -664,6 +664,10 @@ void MCObjectStreamer::emitCodeAlignment(Align Alignment, F->STI = STI; } +void MCObjectStreamer::emitPrefAlign(Align Alignment) { + getCurrentSectionOnly()->ensurePreferredAlignment(Alignment); +} + void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) { diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 5fa1539..7a9a9dd 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -418,6 +418,7 @@ private: DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, + DK_PREFALIGN, DK_ORG, DK_FILL, DK_ENDR, @@ -565,6 +566,7 @@ private: bool parseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool parseDirectiveAlign(bool IsPow2, uint8_t ValueSize); + bool parseDirectivePrefAlign(); // ".file", ".line", ".loc", ".loc_label", ".stabs" bool parseDirectiveFile(SMLoc DirectiveLoc); @@ -2002,6 +2004,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); case DK_P2ALIGNL: return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + case DK_PREFALIGN: + return parseDirectivePrefAlign(); case DK_ORG: return parseDirectiveOrg(); case DK_FILL: @@ -3427,6 +3431,21 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, uint8_t ValueSize) { return ReturnVal; } +bool AsmParser::parseDirectivePrefAlign() { + SMLoc AlignmentLoc = getLexer().getLoc(); + int64_t Alignment; + if (checkForValidSection() || parseAbsoluteExpression(Alignment)) + return true; + if (parseEOL()) + return true; + + if (!isPowerOf2_64(Alignment)) + return Error(AlignmentLoc, "alignment must be a power of 2"); + getStreamer().emitPrefAlign(Align(Alignment)); + + return false; +} + /// parseDirectiveFile /// ::= .file filename /// ::= .file number [directory] filename [md5 checksum] [source source-text] @@ -5365,6 +5384,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".p2align"] = DK_P2ALIGN; DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW; DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL; + DirectiveKindMap[".prefalign"] = DK_PREFALIGN; DirectiveKindMap[".org"] = DK_ORG; DirectiveKindMap[".fill"] = DK_FILL; DirectiveKindMap[".zero"] = DK_ZERO; diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp index a668e79..8285379 100644 --- a/llvm/lib/MC/MCSection.cpp +++ b/llvm/lib/MC/MCSection.cpp @@ -30,6 +30,16 @@ MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) { return End; } +Align MCSection::getAlignmentForObjectFile(uint64_t Size) const { + if (Size < getAlign().value()) + return getAlign(); + + if (Size < getPreferredAlignment().value()) + return Align(NextPowerOf2(Size - 1)); + + return getPreferredAlignment(); +} + bool MCSection::hasEnded() const { return End && End->isInSection(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index bc73981..f33e4348 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1339,6 +1339,7 @@ void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {} void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) {} void MCStreamer::emitValueToAlignment(Align, int64_t, uint8_t, unsigned) {} +void MCStreamer::emitPrefAlign(Align A) {} void MCStreamer::emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI, unsigned MaxBytesToEmit) {} void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index 0b5ce08..b02cf1f 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" diff --git a/llvm/test/MC/ELF/prefalign-errors.s b/llvm/test/MC/ELF/prefalign-errors.s new file mode 100644 index 0000000..363638f --- /dev/null +++ b/llvm/test/MC/ELF/prefalign-errors.s @@ -0,0 +1,5 @@ +// RUN: not llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s + +.section .text.f1,"ax",@progbits +// CHECK: error: alignment must be a power of 2 +.prefalign 3 diff --git a/llvm/test/MC/ELF/prefalign.s b/llvm/test/MC/ELF/prefalign.s new file mode 100644 index 0000000..0732b64 --- /dev/null +++ b/llvm/test/MC/ELF/prefalign.s @@ -0,0 +1,104 @@ +// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readelf -SW - | FileCheck --check-prefix=OBJ %s + +// Minimum alignment >= preferred alignment, no effect on sh_addralign. +// ASM: .section .text.f1lt +// ASM: .p2align 2 +// ASM: .prefalign 2 +// OBJ: .text.f1lt PROGBITS 0000000000000000 000040 000003 00 AX 0 0 4 +.section .text.f1lt,"ax",@progbits +.p2align 2 +.prefalign 2 +.rept 3 +nop +.endr + +// ASM: .section .text.f1eq +// ASM: .p2align 2 +// ASM: .prefalign 2 +// OBJ: .text.f1eq PROGBITS 0000000000000000 000044 000004 00 AX 0 0 4 +.section .text.f1eq,"ax",@progbits +.p2align 2 +.prefalign 2 +.rept 4 +nop +.endr + +// ASM: .section .text.f1gt +// ASM: .p2align 2 +// ASM: .prefalign 2 +// OBJ: .text.f1gt PROGBITS 0000000000000000 000048 000005 00 AX 0 0 4 +.section .text.f1gt,"ax",@progbits +.p2align 2 +.prefalign 2 +.rept 5 +nop +.endr + +// Minimum alignment < preferred alignment, sh_addralign influenced by section size. +// Use maximum of all .prefalign directives. +// ASM: .section .text.f2lt +// ASM: .p2align 2 +// ASM: .prefalign 8 +// ASM: .prefalign 16 +// ASM: .prefalign 8 +// OBJ: .text.f2lt PROGBITS 0000000000000000 000050 000003 00 AX 0 0 4 +.section .text.f2lt,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 3 +nop +.endr + +// ASM: .section .text.f2between1 +// OBJ: .text.f2between1 PROGBITS 0000000000000000 000054 000008 00 AX 0 0 8 +.section .text.f2between1,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 8 +nop +.endr + +// OBJ: .text.f2between2 PROGBITS 0000000000000000 00005c 000009 00 AX 0 0 16 +.section .text.f2between2,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 9 +nop +.endr + +// OBJ: .text.f2between3 PROGBITS 0000000000000000 000068 000010 00 AX 0 0 16 +.section .text.f2between3,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 16 +nop +.endr + +// OBJ: .text.f2gt1 PROGBITS 0000000000000000 000078 000011 00 AX 0 0 16 +.section .text.f2gt1,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 17 +nop +.endr + +// OBJ: .text.f2gt2 PROGBITS 0000000000000000 00008c 000021 00 AX 0 0 16 +.section .text.f2gt2,"ax",@progbits +.p2align 2 +.prefalign 8 +.prefalign 16 +.prefalign 8 +.rept 33 +nop +.endr |