Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -742,6 +742,8 @@ def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>; def : Flag<["-"], "findirect-virtual-calls">, Alias; def finline_functions : Flag<["-"], "finline-functions">, Group, Flags<[CC1Option]>; +def finline_implicit_hint: Flag<["-"], "finline-implicit-hint">, Group, Flags<[CC1Option]>; +def fno_inline_implicit_hint: Flag<["-"], "fno-inline-implicit-hint">, Group, Flags<[CC1Option]>; def finline : Flag<["-"], "finline">, Group; def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group; def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -99,6 +99,9 @@ CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated. CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled. ///< Disables use of the inline keyword. +CODEGENOPT(ImplicitInlineHint, 1, 0) ///< Set when -finline-implicit-hint is enabled. + ///< Add inline hint on implicitly inline + ///< functions. CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss. /// \brief Method of Objective-C dispatch to use. Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -699,12 +699,14 @@ Fn->addFnAttr(llvm::Attribute::SafeStack); // 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. + // declaration, or implicitly in the case of -finline-implicit-hint. + // Also, in the case of -fno-inline attach NoInline attribute to all + // function that are not marked AlwaysInline. if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (!CGM.getCodeGenOpts().NoInline) { for (auto RI : FD->redecls()) - if (RI->isInlineSpecified()) { + if (RI->isInlineSpecified() || + (CGM.getCodeGenOpts().ImplicitInlineHint && RI->isInlined())) { Fn->addFnAttr(llvm::Attribute::InlineHint); break; } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -447,6 +447,8 @@ InlineArg->getOption().matches(options::OPT_finline_functions) ? CodeGenOptions::NormalInlining : CodeGenOptions::OnlyAlwaysInlining); } + Opts.ImplicitInlineHint = Args.hasFlag(OPT_finline_implicit_hint, + OPT_fno_inline_implicit_hint, false); if (Arg *A = Args.getLastArg(OPT_fveclib)) { StringRef Name = A->getValue(); Index: test/CodeGenCXX/inline-hint.cpp =================================================================== --- test/CodeGenCXX/inline-hint.cpp +++ test/CodeGenCXX/inline-hint.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -fno-inline-implicit-hint -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=EXPLICIT +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-implicit-hint -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=IMPLICIT +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-implicit-hint -fno-inline -emit-llvm -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; } +}; + +int B::explicitFunction(int a) { return a + a; } +// CHECK: @_ZN1B14noHintFunctionEi({{.*}}) [[NOHINT_ATTR:#[0-9]+]] +int B::noHintFunction(int a) { return a + 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]+]] + b2.implicitFunction(1); +// CHECK: @_ZN1B16explicitFunctionEi({{.*}}) [[EXPLICIT_ATTR:#[0-9]+]] + b2.explicitFunction(2); + b2.noHintFunction(3); +// CHECK: @_ZN1B15optNoneFunctionEi({{.*}}) [[OPTNONE_ATTR:#[0-9]+]] + b2.optNoneFunction(4); +// CHECK: @_Z17constexprFunctioni({{.*}}) [[IMPLICIT_ATTR]] + constexprFunction(5); +// CHECK: @_ZN1BD2Ev({{.*}}) unnamed_addr [[IMPLICIT_CONSTR_ATTR]] +} + +// EXPLICIT-NOT: attributes [[NOHINT_ATTR]] = { {{.*}}inlinehint{{.*}} } +// IMPLICIT-NOT: attributes [[NOHINT_ATTR]] = { {{.*}}inlinehint{{.*}} } +// NOINLINE-DAG: attributes [[NOHINT_ATTR]] = { noinline{{.*}} } + +// EXPLICIT-NOT: attributes [[IMPLICIT_ATTR]] = { {{.*}}inlinehint{{.*}} } +// IMPLICIT-DAG: attributes [[IMPLICIT_ATTR]] = { inlinehint{{.*}} } +// NOINLINE-DAG: attributes [[IMPLICIT_ATTR]] = { noinline{{.*}} } + +// EXPLICIT-DAG: attributes [[IMPLICIT_CONSTR_ATTR]] = { inlinehint{{.*}} } +// IMPLICIT-DAG: attributes [[IMPLICIT_CONSTR_ATTR]] = { inlinehint{{.*}} } +// NOINLINE-DAG: attributes [[IMPLICIT_CONSTR_ATTR]] = { noinline{{.*}} } + +// EXPLICIT-DAG: attributes [[EXPLICIT_ATTR]] = { inlinehint{{.*}} } +// IMPLICIT-DAG: attributes [[EXPLICIT_ATTR]] = { inlinehint{{.*}} } +// NOINLINE-DAG: attributes [[EXPLICIT_ATTR]] = { noinline{{.*}} } + +// CHECK-DAG: attributes [[OPTNONE_ATTR]] = { noinline{{.*}} }