Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -535,6 +535,12 @@ def findirect_virtual_calls : Flag<["-"], "findirect-virtual-calls">, Alias; def finline_functions : Flag<["-"], "finline-functions">, Group; def finline : Flag<["-"], "finline">, Group; +def finstrument_functions_exclude_function_list : CommaJoined<["-"], + "finstrument-functions-exclude-function-list=">, Group, Flags<[CC1Option]>, + HelpText<"Exclude given (mangled, if C++) functions from function instrumentation.">; +def finstrument_functions_exclude_file_list : CommaJoined<["-"], + "finstrument-functions-exclude-file-list=">, Group, Flags<[CC1Option]>, + HelpText<"Exclude given path segments from function instrumentation.">; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; def fkeep_inline_functions : Flag<["-"], "fkeep-inline-functions">, Group; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -131,6 +131,12 @@ /// A list of dependent libraries. std::vector DependentLibraries; + /// Functions to exclude from function instrumentation. + std::vector InstrumentFunctionExclusionsFunctions; + + /// Path segments to exclude from function instrumentation, eg, '/bits' + std::vector InstrumentFunctionExclusionsPathSegments; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1202,7 +1202,7 @@ /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls - bool ShouldInstrumentFunction(); + bool ShouldInstrumentFunction(llvm::Function *Fn); /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -29,6 +29,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" +#include using namespace clang; using namespace CodeGen; @@ -232,7 +233,7 @@ // Emit function epilog (to return). EmitReturnBlock(); - if (ShouldInstrumentFunction()) + if (ShouldInstrumentFunction(CurFn)) EmitFunctionInstrumentation("__cyg_profile_func_exit"); // Emit debug descriptor for function end. @@ -277,13 +278,77 @@ EmitDeclMetadata(); } +#if !defined(_MSC_VER) +// Assume that __cxa_demangle is provided by libcxxabi (except for Windows). +extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, + size_t *length, int *status); +#endif + /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls -bool CodeGenFunction::ShouldInstrumentFunction() { +bool CodeGenFunction::ShouldInstrumentFunction(llvm::Function *Fn) { + typedef std::vector::const_iterator CIt; if (!CGM.getCodeGenOpts().InstrumentFunctions) return false; if (!CurFuncDecl || CurFuncDecl->hasAttr()) return false; + + // Inline functions that are not externally visible mustn't be instrumented. + // They create a named reference to the inlined function, as the first + // parameter to __cyg_profile_* functions, which a linker will never be able + // to resolve. + if (const FunctionDecl *ActualFuncDecl = + dyn_cast(CurFuncDecl)) { + if (ActualFuncDecl->isInlined() && + !ActualFuncDecl->isInlineDefinitionExternallyVisible()) + return false; + } + + SourceLocation SLoc = CurFuncDecl->getLocation(); + static std::map cache; + + if (SLoc.isFileID()) { + if (cache.find(SLoc) == cache.end()) { + ASTContext &ctx = CurFuncDecl->getASTContext(); + const SourceManager &SM = ctx.getSourceManager(); + + PresumedLoc PLoc = SM.getPresumedLoc(SLoc); + cache[SLoc] = PLoc.getFilename(); + } + std::string FunctionDeclPath = cache[SLoc]; + + const std::vector &PathSearch = + CGM.getCodeGenOpts().InstrumentFunctionExclusionsPathSegments; + + for (CIt i = PathSearch.begin(), e = PathSearch.end(); i != e; ++i) { + if(FunctionDeclPath.find(*i) != std::string::npos) { + return false; + } + } + } + + // Demangle the name if it's mangled + std::string FunctionName = Fn->getName(); +#if !defined(_MSC_VER) + int status = 0; + char *result = __cxa_demangle(FunctionName.c_str(), 0, 0, &status); + + assert((status == 0 || status == -2) && "Couldn't demangle name."); + + if (status == 0) { + FunctionName = result; + free(result); + } +#endif + + const std::vector &FunctionSearch = + CGM.getCodeGenOpts().InstrumentFunctionExclusionsFunctions; + for (CIt i = FunctionSearch.begin(), e = FunctionSearch.end(); i != e; ++i) { + if(FunctionName.find(*i) != std::string::npos) { + return false; + } + } + return true; } @@ -567,7 +632,7 @@ DI->EmitFunctionStart(GD, FnType, CurFn, Builder); } - if (ShouldInstrumentFunction()) + if (ShouldInstrumentFunction(CurFn)) EmitFunctionInstrumentation("__cyg_profile_func_enter"); if (CGM.getCodeGenOpts().InstrumentForProfiling) Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -2620,6 +2620,12 @@ Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasArg(options::OPT_finstrument_functions)) { + Args.AddAllArgs(CmdArgs, + options::OPT_finstrument_functions_exclude_file_list); + Args.AddAllArgs(CmdArgs, + options::OPT_finstrument_functions_exclude_function_list); + } if (Args.hasArg(options::OPT_ftest_coverage) || Args.hasArg(options::OPT_coverage)) Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -432,6 +432,13 @@ } Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + if (Opts.InstrumentFunctions) { + Opts.InstrumentFunctionExclusionsFunctions + = Args.getAllArgValues(OPT_finstrument_functions_exclude_function_list); + Opts.InstrumentFunctionExclusionsPathSegments + = Args.getAllArgValues(OPT_finstrument_functions_exclude_file_list); + } + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);