diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index f094ba112988f..19bdc43abaac0 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -418,6 +418,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 82e8212bee12d..2dfc0872bac1f 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>; 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">, @@ -8446,6 +8448,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 7064421fe0613..e7d94ed878e10 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2794,13 +2794,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 1b44090534e82..c2ab8d9318a33 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" @@ -5503,6 +5504,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'