From 7c0418d29ddffa1c3a8d7347fb300a9e6c7a85fd Mon Sep 17 00:00:00 2001 From: Hans Wennborg <hans@hanshq.net> Date: Wed, 22 Jun 2016 16:56:16 +0000 Subject: [PATCH] Add support for /Ob1 and -finline-hint-functions flags Add support for /Ob1 (and equivalent -finline-hint-functions), which enable inlining only for functions marked inline, either explicitly (via inline keyword, for example), or implicitly (function definition in class body, for example). This works by enabling inlining pass, and adding noinline attribute to every function not marked inline. Patch by Rudy Pons <rudy.pons@ilod.org>! Differential Revision: http://reviews.llvm.org/D20647 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@273440 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/CLCompatOptions.td | 1 - include/clang/Driver/Options.td | 5 +- include/clang/Frontend/CodeGenOptions.h | 1 + lib/CodeGen/BackendUtil.cpp | 3 +- lib/CodeGen/CodeGenFunction.cpp | 10 ++- lib/Driver/MSVCToolChain.cpp | 2 +- lib/Driver/Tools.cpp | 1 + lib/Frontend/CompilerInvocation.cpp | 11 ++- test/CodeGen/inline-optim.c | 5 ++ test/CodeGenCXX/inline-hint.cpp | 96 +++++++++++++++++++++++++ test/Driver/cl-options.c | 5 +- 11 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 test/CodeGenCXX/inline-hint.cpp diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index 5f959220992..5e85b618884 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -291,7 +291,6 @@ def _SLASH_FS : CLIgnoredFlag<"FS">, HelpText<"Force synchronous PDB writes">; def _SLASH_GF : CLIgnoredFlag<"GF">; def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">; def _SLASH_nologo : CLIgnoredFlag<"nologo">; -def _SLASH_Ob1 : CLIgnoredFlag<"Ob1">; def _SLASH_Og : CLIgnoredFlag<"Og">; def _SLASH_openmp_ : CLIgnoredFlag<"openmp-">; def _SLASH_RTC : CLIgnoredJoined<"RTC">; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 99287581117..4a60fe7027b 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -746,7 +746,10 @@ def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>, def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">, Flags<[CC1Option]>; def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>; def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>; -def finline_functions : Flag<["-"], "finline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>; +def finline_functions : Flag<["-"], "finline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Inline suitable functions">; +def finline_hint_functions: Flag<["-"], "finline-hint-functions">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Inline functions wich are (explicitly or implicitly) marked inline">; def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>; def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>; def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>; diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index fd456e08ecb..4bc3120908f 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -46,6 +46,7 @@ public: enum InliningMethod { NoInlining, // Perform no inlining whatsoever. NormalInlining, // Use the standard function inlining pass. + OnlyHintInlining, // Inline only (implicitly) hinted functions. OnlyAlwaysInlining // Only run the always inlining pass. }; diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index fc1a456c0c7..36706696791 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -328,7 +328,8 @@ void EmitAssemblyHelper::CreatePasses(ModuleSummaryIndex *ModuleSummary) { switch (Inlining) { case CodeGenOptions::NoInlining: break; - case CodeGenOptions::NormalInlining: { + case CodeGenOptions::NormalInlining: + case CodeGenOptions::OnlyHintInlining: { PMBuilder.Inliner = createFunctionInliningPass(OptLevel, CodeGenOpts.OptimizeSize); break; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 99f40e3ade6..1d46eea45fd 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -686,14 +686,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, // Pass inline keyword to optimizer if it appears explicitly on any // declaration. Also, in the case of -fno-inline attach NoInline - // attribute to all function that are not marked AlwaysInline. + // attribute to all functions that are not marked AlwaysInline, or + // to all functions that are not marked inline or implicitly inline + // in the case of -finline-hint-functions. if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { - if (!CGM.getCodeGenOpts().NoInline) { + const CodeGenOptions& CodeGenOpts = CGM.getCodeGenOpts(); + if (!CodeGenOpts.NoInline) { for (auto RI : FD->redecls()) if (RI->isInlineSpecified()) { Fn->addFnAttr(llvm::Attribute::InlineHint); break; } + if (CodeGenOpts.getInlining() == CodeGenOptions::OnlyHintInlining && + !FD->isInlined() && !Fn->hasFnAttribute(llvm::Attribute::InlineHint)) + Fn->addFnAttr(llvm::Attribute::NoInline); } else if (!FD->hasAttr<AlwaysInlineAttr>()) Fn->addFnAttr(llvm::Attribute::NoInline); if (CGM.getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>()) diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp index 190df24e5a0..567c7e31d3d 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/MSVCToolChain.cpp @@ -728,7 +728,7 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); break; case '1': - // TODO: Inline calls to 'inline functions' only. + DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); break; case '2': DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index c0d6c52db80..b0a3f348b3c 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -5405,6 +5405,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-inline"); if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, options::OPT_fno_inline_functions)) InlineArg->render(Args, CmdArgs); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0836bdcc9f4..ba6f6918aa8 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -442,10 +442,15 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, // -fno-inline-functions overrides OptimizationLevel > 1. Opts.NoInline = Args.hasArg(OPT_fno_inline); if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, options::OPT_fno_inline_functions)) { - Opts.setInlining( - InlineArg->getOption().matches(options::OPT_finline_functions) ? - CodeGenOptions::NormalInlining : CodeGenOptions::OnlyAlwaysInlining); + const Option& InlineOpt = InlineArg->getOption(); + if (InlineOpt.matches(options::OPT_finline_functions)) + Opts.setInlining(CodeGenOptions::NormalInlining); + else if (InlineOpt.matches(options::OPT_finline_hint_functions)) + Opts.setInlining(CodeGenOptions::OnlyHintInlining); + else + Opts.setInlining(CodeGenOptions::OnlyAlwaysInlining); } if (Arg *A = Args.getLastArg(OPT_fveclib)) { diff --git a/test/CodeGen/inline-optim.c b/test/CodeGen/inline-optim.c index 7ee9c033410..f8b355afd9c 100644 --- a/test/CodeGen/inline-optim.c +++ b/test/CodeGen/inline-optim.c @@ -2,6 +2,7 @@ // RUN: %clang_cc1 -triple i686-pc-win32 -emit-llvm %s -o - | FileCheck -check-prefix=NOINLINE %s // RUN: %clang_cc1 -triple i686-pc-win32 -O3 -fno-inline-functions -emit-llvm %s -o - | FileCheck -check-prefix=NOINLINE %s +// RUN: %clang_cc1 -triple i686-pc-win32 -finline-hint-functions -emit-llvm %s -o - | FileCheck -check-prefix=HINT %s // RUN: %clang_cc1 -triple i686-pc-win32 -finline-functions -emit-llvm %s -o - | FileCheck -check-prefix=INLINE %s inline int inline_hint(int a, int b) { return(a+b); } @@ -13,14 +14,18 @@ inline __attribute__ ((__always_inline__)) int inline_always(int a, int b) { ret volatile int *pa = (int*) 0x1000; void foo() { // NOINLINE-LABEL: @foo +// HINT-LABEL: @foo // INLINE-LABEL: @foo // NOINLINE: call i32 @inline_hint +// HINT-NOT: call i32 @inline_hint // INLINE-NOT: call i32 @inline_hint pa[0] = inline_hint(pa[1],pa[2]); // NOINLINE-NOT: call i32 @inline_always +// HINT-NOT: call i32 @inline_always // INLINE-NOT: call i32 @inline_always pa[3] = inline_always(pa[4],pa[5]); // NOINLINE: call i32 @inline_no_hint +// HINT: call i32 @inline_no_hint // INLINE-NOT: call i32 @inline_no_hint pa[6] = inline_no_hint(pa[7], pa[8]); } diff --git a/test/CodeGenCXX/inline-hint.cpp b/test/CodeGenCXX/inline-hint.cpp new file mode 100644 index 00000000000..9c14032f9f6 --- /dev/null +++ b/test/CodeGenCXX/inline-hint.cpp @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-functions -emit-llvm -disable-llvm-optzns -o - | FileCheck %s --check-prefix=CHECK --check-prefix=SUITABLE +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-hint-functions -emit-llvm -disable-llvm-optzns -o - | FileCheck %s --check-prefix=CHECK --check-prefix=HINTED +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -fno-inline -emit-llvm -disable-llvm-optzns -o - | FileCheck %s --check-prefix=CHECK --check-prefix=NOINLINE + +// Force non-trivial implicit constructors/destructors/operators for B by having explicit ones for A +struct A { + A() {} + A(const A&) {} + A& operator=(const A&) { return *this; } + ~A() {} +}; + +struct B { + A member; + int implicitFunction(int a) { return a + a; } + inline int explicitFunction(int a); + int noHintFunction(int a); + __attribute__((optnone)) int optNoneFunction(int a) { return a + a; } + template<int N> int implicitTplFunction(int a) { return N + a; } + template<int N> inline int explicitTplFunction(int a) { return N + a; } + template<int N> int noHintTplFunction(int a); + template<int N> int explicitRedeclTplFunction(int a); +}; + +int B::explicitFunction(int a) { return a + a; } +// CHECK: @_ZN1B14noHintFunctionEi({{.*}}) [[NOHINT_ATTR:#[0-9]+]] +int B::noHintFunction(int a) { return a + a; } + +// CHECK: @_ZN1B19implicitTplFunctionILi0EEEii({{.*}}) [[NOHINT_ATTR]] +template<> int B::implicitTplFunction<0>(int a) { return a + a; } +// CHECK: @_ZN1B19explicitTplFunctionILi0EEEii({{.*}}) [[NOHINT_ATTR]] +template<> int B::explicitTplFunction<0>(int a) { return a + a; } +// CHECK: @_ZN1B17noHintTplFunctionILi0EEEii({{.*}}) [[NOHINT_ATTR]] +template<> int B::noHintTplFunction<0>(int a) { return a + a; } +template<> inline int B::implicitTplFunction<1>(int a) { return a; } +template<> inline int B::explicitTplFunction<1>(int a) { return a; } +template<> inline int B::noHintTplFunction<1>(int a) { return a; } +template<int N> int B::noHintTplFunction(int a) { return N + a; } +template<int N> inline int B::explicitRedeclTplFunction(int a) { return N + a; } + +constexpr int constexprFunction(int a) { return a + a; } + +void foo() +{ +// CHECK: @_ZN1BC1Ev({{.*}}) unnamed_addr [[IMPLICIT_CONSTR_ATTR:#[0-9]+]] + B b1; +// CHECK: @_ZN1BC1ERKS_({{.*}}) unnamed_addr [[IMPLICIT_CONSTR_ATTR]] + B b2(b1); +// CHECK: @_ZN1BaSERKS_({{.*}}) [[IMPLICIT_CONSTR_ATTR]] + b2 = b1; +// CHECK: @_ZN1B16implicitFunctionEi({{.*}}) [[IMPLICIT_ATTR:#[0-9]+]] + b1.implicitFunction(1); +// CHECK: @_ZN1B16explicitFunctionEi({{.*}}) [[EXPLICIT_ATTR:#[0-9]+]] + b1.explicitFunction(2); + b1.noHintFunction(3); +// CHECK: @_ZN1B15optNoneFunctionEi({{.*}}) [[OPTNONE_ATTR:#[0-9]+]] + b1.optNoneFunction(4); +// CHECK: @_Z17constexprFunctioni({{.*}}) [[IMPLICIT_ATTR]] + constexprFunction(5); + b1.implicitTplFunction<0>(6); +// CHECK: @_ZN1B19implicitTplFunctionILi1EEEii({{.*}}) [[EXPLICIT_ATTR]] + b1.implicitTplFunction<1>(7); +// CHECK: @_ZN1B19implicitTplFunctionILi2EEEii({{.*}}) [[IMPLICIT_ATTR]] + b1.implicitTplFunction<2>(8); + b1.explicitTplFunction<0>(9); +// CHECK: @_ZN1B19explicitTplFunctionILi1EEEii({{.*}}) [[EXPLICIT_ATTR]] + b1.explicitTplFunction<1>(10); +// CHECK: @_ZN1B19explicitTplFunctionILi2EEEii({{.*}}) [[EXPLICIT_ATTR]] + b1.explicitTplFunction<2>(11); + b1.noHintTplFunction<0>(12); +// CHECK: @_ZN1B17noHintTplFunctionILi1EEEii({{.*}}) [[EXPLICIT_ATTR]] + b1.noHintTplFunction<1>(13); +// CHECK: @_ZN1B17noHintTplFunctionILi2EEEii({{.*}}) [[NOHINT_ATTR]] + b1.noHintTplFunction<2>(14); +// CHECK: @_ZN1B25explicitRedeclTplFunctionILi2EEEii({{.*}}) [[EXPLICIT_ATTR]] + b1.explicitRedeclTplFunction<2>(15); +// CHECK: @_ZN1BD2Ev({{.*}}) unnamed_addr [[IMPLICIT_CONSTR_ATTR]] +} + +// SUITABLE-NOT: attributes [[NOHINT_ATTR]] = { {{.*}}noinline{{.*}} } +// HINTED-DAG: attributes [[NOHINT_ATTR]] = { noinline{{.*}} } +// NOINLINE-DAG: attributes [[NOHINT_ATTR]] = { noinline{{.*}} } + +// SUITABLE-NOT: attributes [[IMPLICIT_ATTR]] = { {{.*}}noinline{{.*}} } +// HINTED-NOT: attributes [[IMPLICIT_ATTR]] = { {{.*}}noinline{{.*}} } +// NOINLINE-DAG: attributes [[IMPLICIT_ATTR]] = { noinline{{.*}} } + +// SUITABLE-NOT: attributes [[IMPLICIT_CONSTR_ATTR]] = { {{.*}}noinline{{.*}} } +// HINTED-NOT: attributes [[IMPLICIT_ATTR]] = { {{.*}}noinline{{.*}} } +// NOINLINE-DAG: attributes [[IMPLICIT_CONSTR_ATTR]] = { noinline{{.*}} } + +// SUITABLE-NOT: attributes [[EXPLICIT_ATTR]] = { {{.*}}noinline{{.*}} } +// HINTED-NOT: attributes [[IMPLICIT_ATTR]] = { {{.*}}noinline{{.*}} } +// NOINLINE-DAG: attributes [[EXPLICIT_ATTR]] = { noinline{{.*}} } + +// CHECK-DAG: attributes [[OPTNONE_ATTR]] = { noinline{{.*}} } diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index 3954ddb0e05..ce63aba9d42 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -113,6 +113,10 @@ // Ob2-NOT: warning: argument unused during compilation: '/O2' // Ob2: -finline-functions +// RUN: %clang_cl /Ob1 -### -- %s 2>&1 | FileCheck -check-prefix=Ob1 %s +// RUN: %clang_cl /Odb1 -### -- %s 2>&1 | FileCheck -check-prefix=Ob1 %s +// Ob1: -finline-hint-functions + // RUN: %clang_cl /Od -### -- %s 2>&1 | FileCheck -check-prefix=Od %s // Od: -O0 @@ -280,7 +284,6 @@ // RUN: /GS- \ // RUN: /kernel- \ // RUN: /nologo \ -// RUN: /Ob1 \ // RUN: /openmp- \ // RUN: /RTC1 \ // RUN: /sdl \ -- GitLab