aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/LangOptions.def1
-rw-r--r--clang/include/clang/Driver/Options.td5
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp20
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp13
-rw-r--r--clang/test/CodeGen/prefalign.c4
-rw-r--r--clang/test/CodeGenCXX/member-alignment.cpp6
-rw-r--r--clang/test/Driver/prefalign.c5
-rw-r--r--llvm/docs/Extensions.rst15
-rw-r--r--llvm/docs/LangRef.rst27
-rw-r--r--llvm/include/llvm/AsmParser/LLParser.h2
-rw-r--r--llvm/include/llvm/AsmParser/LLToken.h1
-rw-r--r--llvm/include/llvm/IR/Function.h9
-rw-r--r--llvm/include/llvm/MC/MCAsmInfo.h4
-rw-r--r--llvm/include/llvm/MC/MCObjectStreamer.h1
-rw-r--r--llvm/include/llvm/MC/MCSection.h14
-rw-r--r--llvm/include/llvm/MC/MCStreamer.h2
-rw-r--r--llvm/lib/AsmParser/LLLexer.cpp1
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp23
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp7
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp4
-rw-r--r--llvm/lib/IR/AsmWriter.cpp2
-rw-r--r--llvm/lib/MC/ELFObjectWriter.cpp8
-rw-r--r--llvm/lib/MC/MCAsmInfoELF.cpp1
-rw-r--r--llvm/lib/MC/MCAsmStreamer.cpp6
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp4
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp20
-rw-r--r--llvm/lib/MC/MCSection.cpp10
-rw-r--r--llvm/lib/MC/MCStreamer.cpp1
-rw-r--r--llvm/test/Bitcode/compatibility.ll14
-rw-r--r--llvm/test/MC/ELF/prefalign-errors.s5
-rw-r--r--llvm/test/MC/ELF/prefalign.s104
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