Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1028,6 +1028,8 @@ def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; +def fno_instrument_functions_inline : Flag<["-"], "fno-instrument-functions-inline">, Group, Flags<[CC1Option]>, + HelpText<"When using -finstrument-functions, insert the calls after inlining">; def fxray_instrument : Flag<["-"], "fxray-instrument">, Group, Flags<[CC1Option]>, Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -76,6 +76,8 @@ CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. +CODEGENOPT(NoInstrumentFunctionsInline , 1, 0) ///< Set when + ///< -fno-instrument-functions-inline is enabled. CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1784,11 +1784,6 @@ /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; - /// EmitFunctionInstrumentation - Emit LLVM code to call the specified - /// instrumentation function with the current function and the call site, if - /// function instrumentation is enabled. - void EmitFunctionInstrumentation(const char *Fn); - /// Encode an address into a form suitable for use in a function prologue. llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F, llvm::Constant *Addr); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -354,8 +354,12 @@ // Emit function epilog (to return). llvm::DebugLoc Loc = EmitReturnBlock(); - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_exit"); + if (ShouldInstrumentFunction()) { + CurFn->addFnAttr(!CGM.getCodeGenOpts().NoInstrumentFunctionsInline + ? "instrument-function-exit" + : "instrument-function-exit-inlined", + "__cyg_profile_func_exit"); + } // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) @@ -488,31 +492,6 @@ "decoded_addr"); } -/// EmitFunctionInstrumentation - Emit LLVM code to call the specified -/// instrumentation function with the current function and the call site, if -/// function instrumentation is enabled. -void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { - auto NL = ApplyDebugLocation::CreateArtificial(*this); - // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); - llvm::PointerType *PointerTy = Int8PtrTy; - llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; - llvm::FunctionType *FunctionTy = - llvm::FunctionType::get(VoidTy, ProfileFuncArgs, false); - - llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn); - llvm::CallInst *CallSite = Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::returnaddress), - llvm::ConstantInt::get(Int32Ty, 0), - "callsite"); - - llvm::Value *args[] = { - llvm::ConstantExpr::getBitCast(CurFn, PointerTy), - CallSite - }; - - EmitNounwindRuntimeCall(F, args); -} - static void removeImageAccessQualifier(std::string& TyName) { std::string ReadOnlyQual("__read_only"); std::string::size_type ReadOnlyPos = TyName.find(ReadOnlyQual); @@ -1001,8 +980,12 @@ DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder); } - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_enter"); + if (ShouldInstrumentFunction()) { + Fn->addFnAttr(!CGM.getCodeGenOpts().NoInstrumentFunctionsInline + ? "instrument-function-entry" + : "instrument-function-entry-inlined", + "__cyg_profile_func_enter"); + } // Since emitting the mcount call here impacts optimizations such as function // inlining, we just add an attribute to insert a mcount call in backend. @@ -1012,8 +995,10 @@ if (CGM.getCodeGenOpts().CallFEntry) Fn->addFnAttr("fentry-call", "true"); else { - if (!CurFuncDecl || !CurFuncDecl->hasAttr()) - Fn->addFnAttr("counting-function", getTarget().getMCountName()); + if (!CurFuncDecl || !CurFuncDecl->hasAttr()) { + Fn->addFnAttr("instrument-function-entry-inlined", + getTarget().getMCountName()); + } } } Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -3546,6 +3546,7 @@ CmdArgs.push_back("-fno-unique-section-names"); Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + Args.AddAllArgs(CmdArgs, options::OPT_fno_instrument_functions_inline); addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -777,6 +777,8 @@ Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.NoInstrumentFunctionsInline = + Args.hasArg(OPT_fno_instrument_functions_inline); Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); Opts.XRayInstructionThreshold = getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); Index: test/CodeGen/instrument-functions.c =================================================================== --- test/CodeGen/instrument-functions.c +++ test/CodeGen/instrument-functions.c @@ -1,18 +1,21 @@ -// RUN: %clang_cc1 -S -debug-info-kind=standalone -emit-llvm -o - %s -finstrument-functions | FileCheck %s +// RUN: %clang_cc1 -S -debug-info-kind=standalone -emit-llvm -o - %s -finstrument-functions -disable-llvm-passes | FileCheck %s -// CHECK: @test1 int test1(int x) { -// CHECK: call void @__cyg_profile_func_enter({{.*}}, !dbg -// CHECK: call void @__cyg_profile_func_exit({{.*}}, !dbg +// CHECK: define i32 @test1(i32 %x) #[[ATTR1:[0-9]+]] // CHECK: ret return x; } -// CHECK: @test2 int test2(int) __attribute__((no_instrument_function)); int test2(int x) { -// CHECK-NOT: __cyg_profile_func_enter -// CHECK-NOT: __cyg_profile_func_exit +// CHECK: define i32 @test2(i32 %x) #[[ATTR2:[0-9]+]] // CHECK: ret return x; } + +// CHECK: attributes #[[ATTR1]] = +// CHECK-SAME: "instrument-function-entry"="__cyg_profile_func_enter" +// CHECK-SAME: "instrument-function-exit"="__cyg_profile_func_exit" + +// CHECK: attributes #[[ATTR2]] = +// CHECK-NOT: "instrument-function-entry" Index: test/CodeGen/mcount.c =================================================================== --- test/CodeGen/mcount.c +++ test/CodeGen/mcount.c @@ -35,9 +35,9 @@ return no_instrument(); } -// CHECK: attributes #0 = { {{.*}}"counting-function"="mcount"{{.*}} } +// CHECK: attributes #0 = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } // CHECK: attributes #1 = { {{.*}} } -// CHECK-PREFIXED: attributes #0 = { {{.*}}"counting-function"="_mcount"{{.*}} } +// CHECK-PREFIXED: attributes #0 = { {{.*}}"instrument-function-entry-inlined"="_mcount"{{.*}} } // CHECK-PREFIXED: attributes #1 = { {{.*}} } -// NO-MCOUNT-NOT: attributes #{{[0-9]}} = { {{.*}}"counting-function"={{.*}} } -// NO-MCOUNT1-NOT: attributes #1 = { {{.*}}"counting-function"={{.*}} } +// NO-MCOUNT-NOT: attributes #{{[0-9]}} = { {{.*}}"instrument-function-entry-inlined"={{.*}} } +// NO-MCOUNT1-NOT: attributes #1 = { {{.*}}"instrument-function-entry-inlined"={{.*}} } Index: test/CodeGen/x86_64-instrument-functions.c =================================================================== --- /dev/null +++ test/CodeGen/x86_64-instrument-functions.c @@ -0,0 +1,38 @@ +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -finstrument-functions -O2 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -finstrument-functions -fno-instrument-functions-inline -O2 -o - %s | FileCheck -check-prefix=NOINLINE %s + +// It's not so nice having asm tests in Clang, but we need to check that we set +// up the pipeline correctly in order to have the instrumentation inserted. + +int leaf(int x) { + return x; +// CHECK-LABEL: leaf: +// CHECK: callq __cyg_profile_func_enter +// CHECK-NOT: cyg_profile +// CHECK: callq __cyg_profile_func_exit +// CHECK-NOT: cyg_profile +// CHECK: ret +} + +int root(int x) { + return leaf(x); +// CHECK-LABEL: root: +// CHECK: callq __cyg_profile_func_enter +// CHECK-NOT: cyg_profile + +// Inlined from leaf(): +// CHECK: callq __cyg_profile_func_enter +// CHECK-NOT: cyg_profile +// CHECK: callq __cyg_profile_func_exit + +// CHECK-NOT: cyg_profile +// CHECK: callq __cyg_profile_func_exit +// CHECK: ret + +// NOINLINE-LABEL: root: +// NOINLINE: callq __cyg_profile_func_enter +// NOINLINE-NOT: cyg_profile +// NOINLINE: callq __cyg_profile_func_exit +// NOINLINE: ret +} Index: test/CodeGenCXX/instrument-functions.cpp =================================================================== --- test/CodeGenCXX/instrument-functions.cpp +++ test/CodeGenCXX/instrument-functions.cpp @@ -1,22 +1,26 @@ -// RUN: %clang_cc1 -S -emit-llvm -triple %itanium_abi_triple -o - %s -finstrument-functions | FileCheck %s +// RUN: %clang_cc1 -S -emit-llvm -triple %itanium_abi_triple -o - %s -finstrument-functions -disable-llvm-passes | FileCheck %s -// CHECK: @_Z5test1i int test1(int x) { -// CHECK: __cyg_profile_func_enter -// CHECK: __cyg_profile_func_exit +// CHECK: define i32 @_Z5test1i(i32 %x) #[[ATTR1:[0-9]+]] // CHECK: ret return x; } -// CHECK: @_Z5test2i int test2(int) __attribute__((no_instrument_function)); int test2(int x) { -// CHECK-NOT: __cyg_profile_func_enter -// CHECK-NOT: __cyg_profile_func_exit +// CHECK: define i32 @_Z5test2i(i32 %x) #[[ATTR2:[0-9]+]] // CHECK: ret return x; } +// CHECK: attributes #[[ATTR1]] = +// CHECK-SAME: "instrument-function-entry"="__cyg_profile_func_enter" +// CHECK-SAME: "instrument-function-exit"="__cyg_profile_func_exit" + +// CHECK: attributes #[[ATTR2]] = +// CHECK-NOT: "instrument-function-entry" + + // This test case previously crashed code generation. It exists solely // to test -finstrument-function does not crash codegen for this trivial // case. Index: test/Frontend/gnu-mcount.c =================================================================== --- test/Frontend/gnu-mcount.c +++ test/Frontend/gnu-mcount.c @@ -43,36 +43,36 @@ // CHECK-LABEL: f // TODO: add profiling support for arm-baremetal -// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01mcount"{{.*}} } -// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-BAREMETAL-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM64-BAREMETAL-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} } -// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="_mcount"{{.*}} } -// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01mcount"{{.*}} } -// CHECK-ARM-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM64-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} } -// CHECK-ARM64-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI-LINUX: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} } -// CHECK-ARM-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} } -// CHECK-ARM-EABI-FREEBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"=".mcount"{{.*}} } -// CHECK-ARM64-EABI-FREEBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI-NETBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="_mcount"{{.*}} } -// CHECK-ARM-EABI-NETBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} } -// CHECK-ARM-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} } -// CHECK-ARM64-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI-MEABI-GNU-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM-EABI-RTEMS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM64-EABI-RTEMS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM-EABI-CLOUDABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM-EABI-CLOUDABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } -// CHECK-ARM64-EABI-CLOUDABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} } -// CHECK-ARM64-EABI-CLOUDABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01mcount"{{.*}} } +// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-BAREMETAL-EABI: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM64-BAREMETAL-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01_mcount"{{.*}} } +// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="_mcount"{{.*}} } +// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01mcount"{{.*}} } +// CHECK-ARM-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM64-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01_mcount"{{.*}} } +// CHECK-ARM64-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI-LINUX: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01_mcount"{{.*}} } +// CHECK-ARM-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="__mcount"{{.*}} } +// CHECK-ARM-EABI-FREEBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"=".mcount"{{.*}} } +// CHECK-ARM64-EABI-FREEBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI-NETBSD: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="_mcount"{{.*}} } +// CHECK-ARM-EABI-NETBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="__mcount"{{.*}} } +// CHECK-ARM-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="__mcount"{{.*}} } +// CHECK-ARM64-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI-MEABI-GNU-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM-EABI-RTEMS-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM64-EABI-RTEMS-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM-EABI-CLOUDABI: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM-EABI-CLOUDABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} } +// CHECK-ARM64-EABI-CLOUDABI: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="mcount"{{.*}} } +// CHECK-ARM64-EABI-CLOUDABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"instrument-function-entry-inlined"="\01__gnu_mcount_nc"{{.*}} }