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,6 @@ +int test1(int x) { + if (x >= 1) { + return x + 1; + } + return x; +} Index: test/CodeGen/Inputs/code-coverage-filter2.h =================================================================== --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1,6 @@ +int test2(int x) { + if (x >= 1) { + return x + 1; + } + return x; +} Index: test/CodeGen/code-coverage-filter.c =================================================================== --- /dev/null +++ test/CodeGen/code-coverage-filter.c @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data %s -o - \ +// RUN: | FileCheck -check-prefix=ALL %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-exclude=.*\\.h %s -o - \ +// RUN: | FileCheck -check-prefix=NOH %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-filter=.*\\.c %s -o - \ +// RUN: | FileCheck -check-prefix=NOH %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-filter=.*\\.c %s -o - \ +// RUN: | FileCheck -check-prefix=NOH %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-filter=.*\\.c:.*1\\.h %s -o - \ +// RUN: | FileCheck -check-prefix=NOH2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-exclude=.*2\\.h:.*1\\.h %s -o - \ +// RUN: | FileCheck -check-prefix=C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-exclude=.*code\\-coverage\\-filter\\.c %s -o - \ +// RUN: | FileCheck -check-prefix=H %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-filter=.*\\.c -coverage-exclude=.*\\.c %s -o - \ +// RUN: | FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -coverage-filter=.*\\.c -coverage-exclude=.*\\.h %s -o - \ +// RUN: | FileCheck -check-prefix=C %s + +#include "Inputs/code-coverage-filter1.h" +#include "Inputs/code-coverage-filter2.h" + +int test(int a) { + int x = 0; + if (a == 1) { + x = test1(a) + test2(a); + } + + return x; +} + +// ALL: define i32 @test1(i32 %x) #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret i32 {{.*}} +// ALL: define i32 @test2(i32 %x) #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret i32 {{.*}} +// ALL: define i32 @test(i32 %a) #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret i32 {{.*}} + +// NOH: define i32 @test1(i32 %x) #0 {{.*}} +// NOH-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH: ret i32 {{.*}} +// NOH: define i32 @test2(i32 %x) #0 {{.*}} +// NOH-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH: ret i32 {{.*}} +// NOH: define i32 @test(i32 %a) #0 {{.*}} +// NOH: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH: ret i32 {{.*}} + +// NOH2: define i32 @test1(i32 %x) #0 {{.*}} +// NOH2: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH2: ret i32 {{.*}} +// NOH2: define i32 @test2(i32 %x) #0 {{.*}} +// NOH2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH2: ret i32 {{.*}} +// NOH2: define i32 @test(i32 %a) #0 {{.*}} +// NOH2: {{.*}}__llvm_gcov_ctr{{.*}} +// NOH2: ret i32 {{.*}} + +// C: define i32 @test1(i32 %x) #0 {{.*}} +// C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// C: ret i32 {{.*}} +// C: define i32 @test2(i32 %x) #0 {{.*}} +// C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// C: ret i32 {{.*}} +// C: define i32 @test(i32 %a) #0 {{.*}} +// C: {{.*}}__llvm_gcov_ctr{{.*}} +// C: ret i32 {{.*}} + +// H: define i32 @test1(i32 %x) #0 {{.*}} +// H: {{.*}}__llvm_gcov_ctr{{.*}} +// H: ret i32 {{.*}} +// H: define i32 @test2(i32 %x) #0 {{.*}} +// H: {{.*}}__llvm_gcov_ctr{{.*}} +// H: ret i32 {{.*}} +// H: define i32 @test(i32 %a) #0 {{.*}} +// H-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// H: ret i32 {{.*}} + +// NONE: define i32 @test1(i32 %x) #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret i32 {{.*}} +// NONE: define i32 @test2(i32 %x) #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret i32 {{.*}} +// NONE: define i32 @test(i32 %a) #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret i32 {{.*}}