diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 9e850089ad87f..d25f59bcc0f25 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -419,6 +419,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 60c4ad408ee43..427f686175883 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1551,6 +1551,8 @@ defm access_control : BoolFOption<"access-control", PosFlag>; def falign_functions : Flag<["-"], "falign-functions">, Group; def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group; +def fpreferred_function_alignment_EQ : + Joined<["-"], "fpreferred-function-alignment=">, Group; def falign_loops_EQ : Joined<["-"], "falign-loops=">, Group, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, HelpText<"N must be a power of two. Align loops to the boundary">, @@ -8505,6 +8507,9 @@ def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signa def function_alignment : Separate<["-"], "function-alignment">, HelpText<"default alignment for functions">, MarshallingInfoInt>; +def preferred_function_alignment : Separate<["-"], "preferred-function-alignment">, + HelpText<"preferred alignment for functions">, + MarshallingInfoInt>; def fhalf_no_semantic_interposition : Flag<["-"], "fhalf-no-semantic-interposition">, HelpText<"Like -fno-semantic-interposition but don't use local aliases">, MarshallingInfoFlag>; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8d019d4b2da25..5dc52c3eee826 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2822,13 +2822,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()) - 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 107b9ffd439a3..7a49decfb7d79 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -47,6 +47,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" @@ -5468,6 +5469,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 0000000000000..2370585a8e457 --- /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 d5c9a5a02b160..37ee733e18ff5 100644 --- a/clang/test/CodeGenCXX/member-alignment.cpp +++ b/clang/test/CodeGenCXX/member-alignment.cpp @@ -31,9 +31,9 @@ class t { [[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 0000000000000..de52f2dcf28bc --- /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'