Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1025,6 +1025,10 @@ 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_cygprofile_exit : Flag<["-"], "fno-cygprofile-exit">, Group, Flags<[CC1Option]>, + HelpText<"When using -finstrument-functions, don't instrument function exit">; +def fno_cygprofile_args : Flag<["-"], "fno-cygprofile-args">, Group, Flags<[CC1Option]>, + HelpText<"When using -finstrument-functions, don't pass any arguments to the __cyg_profile* functions">; 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,7 +76,11 @@ CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. - +CODEGENOPT(CygProfileExit , 1, 1) ///< Whether to instrument function exits + ///< when using InstrumentFunctions. +CODEGENOPT(CygProfileArgs , 1, 1) ///< Whether to pass arguments to the + ///< __cyg_profile* functions when using + ///< InstrumentFunctions. CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1773,17 +1773,20 @@ void EnterDtorCleanups(const CXXDestructorDecl *Dtor, CXXDtorType Type); /// ShouldInstrumentFunction - Return true if the current function should be - /// instrumented with __cyg_profile_func_* calls - bool ShouldInstrumentFunction(); + /// instrumented with __cyg_profile_func_* calls. If true, sets CygProfileExit + /// and CygProfileArgs to indicate whether function exit should be + /// instrumented and whether the __cyg_profile calls take arguments, + /// respectively. + bool ShouldInstrumentFunction(bool *CygProfileExit, bool *CygProfileArgs); /// ShouldXRayInstrument - Return true if the current function should be /// 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); + /// instrumentation function with the current function and the call site. + /// If CygProfileArgs is false, don't pass any arguments to the function. + void EmitFunctionInstrumentation(const char *Fn, bool CygProfileArgs); /// EmitMCountInstrumentation - Emit call to .mcount. void EmitMCountInstrumentation(); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -352,8 +352,9 @@ // Emit function epilog (to return). llvm::DebugLoc Loc = EmitReturnBlock(); - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_exit"); + bool CygProfileExit, CygProfileArgs; + if (ShouldInstrumentFunction(&CygProfileExit, &CygProfileArgs) && CygProfileExit) + EmitFunctionInstrumentation("__cyg_profile_func_exit", CygProfileArgs); // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) @@ -423,11 +424,16 @@ /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls -bool CodeGenFunction::ShouldInstrumentFunction() { +bool CodeGenFunction::ShouldInstrumentFunction(bool *CygProfileExit, + bool *CygProfileArgs) { if (!CGM.getCodeGenOpts().InstrumentFunctions) return false; if (!CurFuncDecl || CurFuncDecl->hasAttr()) return false; + + *CygProfileExit = CGM.getCodeGenOpts().CygProfileExit; + *CygProfileArgs = CGM.getCodeGenOpts().CygProfileArgs; + return true; } @@ -477,8 +483,18 @@ /// 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) { +void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn, + bool CygProfileArgs) { auto NL = ApplyDebugLocation::CreateArtificial(*this); + + if (!CygProfileArgs) { + // Call the function without passing any arguments. + llvm::FunctionType *FunctionTy = llvm::FunctionType::get(VoidTy, false); + llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn); + EmitNounwindRuntimeCall(F); + return; + } + // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); llvm::PointerType *PointerTy = Int8PtrTy; llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; @@ -987,8 +1003,9 @@ DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder); } - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_enter"); + bool CygProfileExit, CygProfileArgs; + if (ShouldInstrumentFunction(&CygProfileExit, &CygProfileArgs)) + EmitFunctionInstrumentation("__cyg_profile_func_enter", CygProfileArgs); // Since emitting the mcount call here impacts optimizations such as function // inlining, we just add an attribute to insert a mcount call in backend. Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -3553,6 +3553,8 @@ CmdArgs.push_back("-fno-unique-section-names"); Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + Args.AddAllArgs(CmdArgs, options::OPT_fno_cygprofile_exit); + Args.AddAllArgs(CmdArgs, options::OPT_fno_cygprofile_args); addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -776,6 +776,8 @@ Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.CygProfileExit = !Args.hasArg(OPT_fno_cygprofile_exit); + Opts.CygProfileArgs = !Args.hasArg(OPT_fno_cygprofile_args); 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,27 @@ -// 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 | FileCheck --check-prefix=DEFAULT --check-prefix=CHECK %s +// RUN: %clang_cc1 -S -debug-info-kind=standalone -emit-llvm -o - %s -finstrument-functions -fno-cygprofile-exit | FileCheck --check-prefix=NOEXIT --check-prefix=CHECK %s +// RUN: %clang_cc1 -S -debug-info-kind=standalone -emit-llvm -o - %s -finstrument-functions -fno-cygprofile-args | FileCheck --check-prefix=NOARGS --check-prefix=CHECK %s -// CHECK: @test1 +// CHECK-LABEL: @test1 int test1(int x) { -// CHECK: call void @__cyg_profile_func_enter({{.*}}, !dbg -// CHECK: call void @__cyg_profile_func_exit({{.*}}, !dbg -// CHECK: ret +// DEFAULT: call void @__cyg_profile_func_enter(i8*{{.*}}, i8*{{.*}}){{.*}}, !dbg +// DEFAULT: call void @__cyg_profile_func_exit(i8*{{.*}}, i8*{{.*}}){{.*}}, !dbg + +// NOEXIT: call void @__cyg_profile_func_enter(i8*{{.*}}, i8*{{.*}}){{.*}}, !dbg +// NOEXIT-NOT: @__cyg_profile_func_exit + +// NOARGS: call void @__cyg_profile_func_enter(){{.*}}, !dbg +// NOARGS: call void @__cyg_profile_func_exit(){{.*}}, !dbg + +// CHECK: ret i32 %0 return x; } -// CHECK: @test2 +// CHECK-LABEL: @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: ret +// CHECK: ret i32 %0 return x; }