Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -226,6 +226,14 @@ HelpText<"Emit CFG checksum for functions in .gcno files.">; def coverage_no_function_names_in_data : Flag<["-"], "coverage-no-function-names-in-data">, HelpText<"Emit function names in .gcda files.">; +def coverage_filter : Separate<["-"], "coverage-filter">, + HelpText<"Instrument only functions from files where names match any regex separate by a colon">; +def coverage_filter_EQ : Joined<["-"], "coverage-filter=">, + Alias; +def coverage_exclude : Separate<["-"], "coverage-exclude">, + HelpText<"Instrument only functions from files where names don't match all the regex separate by a colon">; +def coverage_exclude_EQ : Joined<["-"], "coverage-exclude=">, + Alias; def coverage_exit_block_before_body : Flag<["-"], "coverage-exit-block-before-body">, HelpText<"Emit the exit block before the body blocks in .gcno files.">; def coverage_version_EQ : Joined<["-"], "coverage-version=">, Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -125,6 +125,12 @@ /// The filename with path we use for coverage notes files. std::string CoverageNotesFile; + /// Regex separated by a colon to filter the files to instrument. + std::string CoverageFilter; + + /// Regex separated by a colon to filter the files to not instrument. + std::string CoverageExclude; + /// The version string to put into coverage files. char CoverageVersion[4]; Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -503,6 +503,8 @@ Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum; Options.NoRedZone = CodeGenOpts.DisableRedZone; Options.FunctionNamesInData = !CodeGenOpts.CoverageNoFunctionNamesInData; + Options.Filter = CodeGenOpts.CoverageFilter; + Options.Exclude = CodeGenOpts.CoverageExclude; Options.ExitBlockBeforeBody = CodeGenOpts.CoverageExitBlockBeforeBody; return Options; } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -801,6 +801,8 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); + Opts.CoverageFilter = Args.getLastArgValue(OPT_coverage_filter); + Opts.CoverageExclude = Args.getLastArgValue(OPT_coverage_exclude); Opts.CoverageExitBlockBeforeBody = Args.hasArg(OPT_coverage_exit_block_before_body); if (Args.hasArg(OPT_coverage_version_EQ)) { Index: test/CodeGen/Inputs/code-coverage-filter1.h =================================================================== --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1,2 @@ +void test1() { +} Index: test/CodeGen/Inputs/code-coverage-filter2.h =================================================================== --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1,2 @@ +void test2() { +} Index: test/CodeGen/code-coverage-filter.c =================================================================== --- /dev/null +++ test/CodeGen/code-coverage-filter.c @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes %s -o - \ +// RUN: | FileCheck -check-prefix=ALL %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-exclude=".*\.h$" %s -o - \ +// RUN: | FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-filter=".*\.c$" %s -o - \ +// RUN: | FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-filter=".*\.c$:.*1\.h$" %s -o - \ +// RUN: | FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-exclude=".*2\.h$:.*1\.h$" %s -o - \ +// RUN: | FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-exclude=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN: | FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-filter=".*\.c$" -coverage-exclude=".*\.c$" %s -o - \ +// RUN: | FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -coverage-filter=".*\.c$" -coverage-exclude=".*\.h$" %s -o - \ +// RUN: | FileCheck -check-prefix=JUST-C %s + +#include "Inputs/code-coverage-filter1.h" +#include "Inputs/code-coverage-filter2.h" + +void test() { + test1(); + test2(); +} + +// ALL: define void @test1() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: define void @test2() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: define void @test() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void + +// NO-HEADER: define void @test1() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: define void @test2() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: define void @test() #0 {{.*}} +// NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void + +// NO-HEADER2: define void @test1() #0 {{.*}} +// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void +// NO-HEADER2: define void @test2() #0 {{.*}} +// NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void +// NO-HEADER2: define void @test() #0 {{.*}} +// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void + +// JUST-C: define void @test1() #0 {{.*}} +// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void +// JUST-C: define void @test2() #0 {{.*}} +// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void +// JUST-C: define void @test() #0 {{.*}} +// JUST-C: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void + +// HEADER: define void @test1() #0 {{.*}} +// HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void +// HEADER: define void @test2() #0 {{.*}} +// HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void +// HEADER: define void @test() #0 {{.*}} +// HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void + +// NONE: define void @test1() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void +// NONE: define void @test2() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void +// NONE: define void @test() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void