[PATCH] D49916: [CodeGen] Add to emitted DebugLoc information about coverage when it's required
calixte updated this revision to Diff 163062. calixte added a comment. - Use ImplicitCode instead of Covered - Set Artificial location as ImplicitCode to avoid coverage on landing pads Repository: rC Clang https://reviews.llvm.org/D49916 Files: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h Index: lib/CodeGen/CodeGenFunction.h === --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -786,7 +786,7 @@ // If we should perform a cleanup, force them now. Note that // this ends the cleanup scope before rescoping any labels. if (PerformCleanup) { -ApplyDebugLocation DL(CGF, Range.getEnd()); +ApplyDebugLocation DL(CGF, Range.getEnd(), true /* ImplicitCode */); ForceCleanup(); } } Index: lib/CodeGen/CodeGenFunction.cpp === --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -1179,7 +1179,7 @@ } // Emit a location at the end of the prologue. if (CGDebugInfo *DI = getDebugInfo()) -DI->EmitLocation(Builder, StartLoc); +DI->EmitLocation(Builder, StartLoc, true /* ImplicitCode */); // TODO: Do we need to handle this in two places like we do with // target-features/target-cpu? Index: lib/CodeGen/CGDebugInfo.h === --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -377,7 +377,9 @@ /// Emit metadata to indicate a change in line/column information in /// the source file. If the location is invalid, the previous /// location will be reused. - void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + /// \param ImplicitCode True if the Loc must have coverage information + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, +bool ImplicitCode = false); /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. @@ -657,16 +659,19 @@ /// location or preferred location of the specified Expr. class ApplyDebugLocation { private: - void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false); + void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false, +bool ImplicitCode = false); ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, - SourceLocation TemporaryLocation); + SourceLocation TemporaryLocation, + bool ImplicitCode = false); llvm::DebugLoc OriginalLocation; CodeGenFunction *CGF; public: /// Set the location to the (valid) TemporaryLocation. - ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation); + ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation, + bool ImplicitCode = false); ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E); ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc); ApplyDebugLocation(ApplyDebugLocation &&Other) : CGF(Other.CGF) { @@ -687,15 +692,17 @@ /// SourceLocation to CGDebugInfo::setLocation() will result in the /// last valid location being reused. static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF) { -return ApplyDebugLocation(CGF, false, SourceLocation()); +return ApplyDebugLocation(CGF, false, SourceLocation(), + true /* ImplicitCode */); } /// Apply TemporaryLocation if it is valid. Otherwise switch /// to an artificial debug location that has a valid scope, but no /// line information. static ApplyDebugLocation CreateDefaultArtificial(CodeGenFunction &CGF, SourceLocation TemporaryLocation) { -return ApplyDebugLocation(CGF, false, TemporaryLocation); +return ApplyDebugLocation(CGF, false, TemporaryLocation, + true /* ImplicitCode */); } /// Set the IRBuilder to not attach debug locations. Note that Index: lib/CodeGen/CGDebugInfo.cpp === --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -76,20 +76,22 @@ } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) + SourceLocation TemporaryLocation, + bool ImplicitCode) : CGF(&CGF) { - init(TemporaryLocation); + init(TemporaryLocation, false /* DefaultToEmpty */, ImplicitCode); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, - SourceLocation TemporaryLocation) + SourceLocation TemporaryLocation, +
[PATCH] D49916: [CodeGen] Add to emitted DebugLoc information about coverage when it's required
calixte updated this revision to Diff 164851. calixte added a comment. - Add some ImplicitCode when there is some stuff at the end of a function - Fix the tests Repository: rC Clang https://reviews.llvm.org/D49916 Files: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/debug-info-scope-file.c test/CodeGenCXX/debug-info-inheriting-constructor.cpp test/CodeGenCXX/debug-info-nested-exprs.cpp test/CodeGenCXX/linetable-virtual-variadic.cpp test/CodeGenObjC/arc-linetable.m test/CodeGenObjC/debug-info-blocks.m Index: test/CodeGenObjC/debug-info-blocks.m === --- test/CodeGenObjC/debug-info-blocks.m +++ test/CodeGenObjC/debug-info-blocks.m @@ -18,11 +18,9 @@ // CHECK: call {{.*}}, !dbg ![[DBG_LINE:[0-9]+]] // CHECK-NOT: ret // CHECK: load {{.*}}, !dbg ![[COPY_LINE:[0-9]+]] -// CHECK: ret void, !dbg ![[COPY_LINE]] // CHECK: define {{.*}} @__destroy_helper_block_{{.*}}(i8*) // CHECK-NOT: ret // CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]] -// CHECK: ret void, !dbg ![[DESTROY_LINE]] typedef unsigned int NSUInteger; Index: test/CodeGenObjC/arc-linetable.m === --- test/CodeGenObjC/arc-linetable.m +++ test/CodeGenObjC/arc-linetable.m @@ -60,7 +60,8 @@ - (int)testNoSideEffect:(NSString *)foo { int x = 1; return 1; // Return expression - // CHECK: ![[RET1]] = !DILocation(line: [[@LINE+1]], scope: ![[TESTNOSIDEEFFECT]]) + // CHECK: ![[RET1]] = !DILocation(line: [[@LINE+1]], scope: + // ![[TESTNOSIDEEFFECT]], isImplicitCode: true) } // Cleanup + Ret - (int)testNoCleanup { Index: test/CodeGenCXX/linetable-virtual-variadic.cpp === --- test/CodeGenCXX/linetable-virtual-variadic.cpp +++ test/CodeGenCXX/linetable-virtual-variadic.cpp @@ -11,12 +11,12 @@ void Derived::VariadicFunction(...) { } -// CHECK: define void @_ZN7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP:[0-9]+]] -// CHECK: ret void, !dbg ![[LOC:[0-9]+]] -// CHECK: define void @_ZT{{.+}}N7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP_I:[0-9]+]] -// CHECK: ret void, !dbg ![[LOC_I:[0-9]+]] +// CHECK: define void @_ZN7Derived16VariadicFunctionEz({{.*}} !dbg +// ![[SP:[0-9]+]] CHECK: ret void, !dbg ![[LOC:[0-9]+]] CHECK: define void +// @_ZT{{.+}}N7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP_I:[0-9]+]] CHECK: +// ret void, !dbg ![[LOC_I:[0-9]+]] // // CHECK: ![[SP]] = distinct !DISubprogram(name: "VariadicFunction" -// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]]) +// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]], isImplicitCode: true) // CHECK: ![[SP_I]] = distinct !DISubprogram(name: "VariadicFunction" -// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]]) +// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]], isImplicitCode: true) Index: test/CodeGenCXX/debug-info-nested-exprs.cpp === --- test/CodeGenCXX/debug-info-nested-exprs.cpp +++ test/CodeGenCXX/debug-info-nested-exprs.cpp @@ -37,7 +37,6 @@ // NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]] // NESTED: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]] // NESTED: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]] - // NESTED: store i32 {{.*}}, i32* %a,{{.*}} !dbg ![[BAR]] // COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]] // COLUMNS: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]] // COLUMNS: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]] @@ -98,7 +97,6 @@ // NONEST: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD]] // NESTED: call i32 @{{.*}}noargs{{.*}}, !dbg ![[DNOARGS:[0-9]+]] // NESTED: call i32 @{{.*}}onearg{{.*}}, !dbg ![[DECLD:[0-9]+]] - // NESTED: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD]] // COLUMNS: call i32 @{{.*}}noargs{{.*}}, !dbg ![[DNOARGS:[0-9]+]] // COLUMNS: call i32 @{{.*}}onearg{{.*}}, !dbg ![[DONEARG:[0-9]+]] // COLUMNS: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD:[0-9]+]] @@ -178,16 +176,16 @@ // NESTED: ![[RETSUB]] = !DILocation( // NESTED: ![[RETMUL]] = !DILocation( -// COLUMNS: ![[DECLA]] = !DILocation( // COLUMNS: ![[BAR]] = !DILocation( // COLUMNS: ![[BAZ]] = !DILocation( // COLUMNS: ![[QUX]] = !DILocation( +// COLUMNS: ![[DECLA]] = !DILocation( // COLUMNS: ![[ILOC]] = !DILocation( // COLUMNS: ![[BLOC]] = !DILocation( // COLUMNS: ![[CLOC]] = !DILocation( -// COLUMNS: ![[DECLD]] = !DILocation( // COLUMNS: ![[DNOARGS]] = !DILocation( // COLUMNS: ![[DONEARG]] = !DILocation( +// COLUMNS: ![[DECLD]] = !DILocation( // COLUMNS: ![[SETDNOARGS]] = !DILocation( // COLUMNS: ![[SETDONEARG]] = !DILocation( // COLUMNS: ![[SETD]] = !DILocation( Index: test/CodeGenCXX/debug-info-inheriting-constructor.cpp === --- test/CodeGenCXX/de
[PATCH] D49916: [CodeGen] Add to emitted DebugLoc information about coverage when it's required
calixte updated this revision to Diff 164860. calixte added a comment. - only put an ImplicitCode for EmitLandingPad - fix tests (were broken with clanf-format-diff) Repository: rC Clang https://reviews.llvm.org/D49916 Files: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h lib/CodeGen/CGException.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/debug-info-scope-file.c test/CodeGenCXX/debug-info-inheriting-constructor.cpp test/CodeGenCXX/linetable-virtual-variadic.cpp test/CodeGenObjC/arc-linetable.m test/CodeGenObjC/debug-info-blocks.m Index: test/CodeGenObjC/debug-info-blocks.m === --- test/CodeGenObjC/debug-info-blocks.m +++ test/CodeGenObjC/debug-info-blocks.m @@ -18,11 +18,9 @@ // CHECK: call {{.*}}, !dbg ![[DBG_LINE:[0-9]+]] // CHECK-NOT: ret // CHECK: load {{.*}}, !dbg ![[COPY_LINE:[0-9]+]] -// CHECK: ret void, !dbg ![[COPY_LINE]] // CHECK: define {{.*}} @__destroy_helper_block_{{.*}}(i8*) // CHECK-NOT: ret // CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]] -// CHECK: ret void, !dbg ![[DESTROY_LINE]] typedef unsigned int NSUInteger; Index: test/CodeGenObjC/arc-linetable.m === --- test/CodeGenObjC/arc-linetable.m +++ test/CodeGenObjC/arc-linetable.m @@ -60,7 +60,7 @@ - (int)testNoSideEffect:(NSString *)foo { int x = 1; return 1; // Return expression - // CHECK: ![[RET1]] = !DILocation(line: [[@LINE+1]], scope: ![[TESTNOSIDEEFFECT]]) + // CHECK: ![[RET1]] = !DILocation(line: [[@LINE+1]], scope: ![[TESTNOSIDEEFFECT]], isImplicitCode: true) } // Cleanup + Ret - (int)testNoCleanup { Index: test/CodeGenCXX/linetable-virtual-variadic.cpp === --- test/CodeGenCXX/linetable-virtual-variadic.cpp +++ test/CodeGenCXX/linetable-virtual-variadic.cpp @@ -17,6 +17,6 @@ // CHECK: ret void, !dbg ![[LOC_I:[0-9]+]] // // CHECK: ![[SP]] = distinct !DISubprogram(name: "VariadicFunction" -// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]]) +// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]], isImplicitCode: true) // CHECK: ![[SP_I]] = distinct !DISubprogram(name: "VariadicFunction" -// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]]) +// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]], isImplicitCode: true) Index: test/CodeGenCXX/debug-info-inheriting-constructor.cpp === --- test/CodeGenCXX/debug-info-inheriting-constructor.cpp +++ test/CodeGenCXX/debug-info-inheriting-constructor.cpp @@ -21,5 +21,5 @@ // CHECK-DAG: ![[LOC]] = !DILocation(line: 0, scope: ![[A]], inlinedAt: ![[INL:[0-9]+]]) // CHECK-DAG: ![[INL]] = !DILocation(line: [[@LINE+1]], scope: ![[FOO]]) B b(0); -// CHECK: ![[NOINL]] = !DILocation(line: [[@LINE+1]], scope: !{{[0-9]+}}) + // CHECK: ![[NOINL]] = !DILocation(line: [[@LINE+1]], scope: !{{[0-9]+}}, isImplicitCode: true) } Index: test/CodeGen/debug-info-scope-file.c === --- test/CodeGen/debug-info-scope-file.c +++ test/CodeGen/debug-info-scope-file.c @@ -5,10 +5,11 @@ // CHECK: ret void, !dbg [[F1_LINE:![0-9]*]] // CHECK: ret void, !dbg [[F2_LINE:![0-9]*]] -// CHECK: [[F1:![0-9]*]] = distinct !DISubprogram(name: "f1",{{.*}} isDefinition: true -// CHECK: [[F1_LINE]] = !DILocation({{.*}}, scope: [[F1]]) -// CHECK: [[F2:![0-9]*]] = distinct !DISubprogram(name: "f2",{{.*}} isDefinition: true -// CHECK: [[F2_LINE]] = !DILocation({{.*}}, scope: [[F2]]) +// CHECK: [[F1:![0-9]*]] = distinct !DISubprogram(name: "f1",{{.*}} +// isDefinition: true CHECK: [[F1_LINE]] = !DILocation({{.*}}, scope: [[F1]], +// isImplicitCode: true) CHECK: [[F2:![0-9]*]] = distinct !DISubprogram(name: +// "f2",{{.*}} isDefinition: true CHECK: [[F2_LINE]] = !DILocation({{.*}}, +// scope: [[F2]], isImplicitCode: true) void f1() { } Index: lib/CodeGen/CodeGenFunction.h === --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -786,7 +786,7 @@ // If we should perform a cleanup, force them now. Note that // this ends the cleanup scope before rescoping any labels. if (PerformCleanup) { -ApplyDebugLocation DL(CGF, Range.getEnd()); +ApplyDebugLocation DL(CGF, Range.getEnd(), true /* ImplicitCode */); ForceCleanup(); } } Index: lib/CodeGen/CodeGenFunction.cpp === --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -317,7 +317,7 @@ if (OnlySimpleReturnStmts) DI->EmitLocation(Builder, LastStopPoint); else - DI->EmitLocation(Builder, EndLoc); + DI->EmitLocation(Builder, EndLoc, true /* ImplicitCode */); } // Pop any cleanups that might have be
[PATCH] D51945: [Clang] Fix test to followup https://reviews.llvm.org/rL341977
calixte created this revision. calixte added a reviewer: vsk. Herald added a subscriber: cfe-commits. In the previous patch, __llvm_gcov_indirect_counter_increment has been removed. Repository: rC Clang https://reviews.llvm.org/D51945 Files: test/CodeGen/code-coverage.c Index: test/CodeGen/code-coverage.c === --- test/CodeGen/code-coverage.c +++ test/CodeGen/code-coverage.c @@ -40,8 +40,7 @@ // Check that the noredzone flag is set on the generated functions. -// CHECK: void @__llvm_gcov_indirect_counter_increment(i32* %{{.*}}, i64** %{{.*}}) unnamed_addr [[NRZ:#[0-9]+]] -// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ]] +// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]] // CHECK: void @__llvm_gcov_flush() unnamed_addr [[NRZ]] // CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]] Index: test/CodeGen/code-coverage.c === --- test/CodeGen/code-coverage.c +++ test/CodeGen/code-coverage.c @@ -40,8 +40,7 @@ // Check that the noredzone flag is set on the generated functions. -// CHECK: void @__llvm_gcov_indirect_counter_increment(i32* %{{.*}}, i64** %{{.*}}) unnamed_addr [[NRZ:#[0-9]+]] -// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ]] +// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]] // CHECK: void @__llvm_gcov_flush() unnamed_addr [[NRZ]] // CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]] ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51945: [Clang] Fix test to followup https://reviews.llvm.org/rL341977
calixte added a comment. My bad, I missed that Repository: rC Clang https://reviews.llvm.org/D51945 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte created this revision. calixte added reviewers: marco-c, vsk. Herald added a subscriber: cfe-commits. These options are taking regex separated by colons to filter files. - if both are empty then all files are instrumented - if -coverage-filter is empty then all the filenames matching any of the regex from exclude are not instrumented - if -coverage-exclude is empty then all the filenames matching any of the regex from filter are instrumented - if both aren't empty then all the filenames which match any of the regex in filter and which don't match all the regex in filter are instrumented - this patch is a follow-up of https://reviews.llvm.org/D52033 Repository: rC Clang https://reviews.llvm.org/D52034 Files: include/clang/Driver/CC1Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 {{.*}} 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/Inputs/code-coverage-filter1.h === --- /dev/null +++
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte added inline comments. Comment at: include/clang/Driver/CC1Options.td:236 +def coverage_exclude_EQ : Joined<["-"], "coverage-exclude=">, + Alias; def coverage_exit_block_before_body : Flag<["-"], "coverage-exit-block-before-body">, vsk wrote: > Have you checked whether gcc supports similar options? If so, it would be > great if we could match their name & behavior. The only one I found -finstrument-functions-exclude-file-list (https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html). But no regex and no way to include one file only. I took the names from gcovr: https://manpages.debian.org/jessie/gcovr/gcovr.1.en.html Repository: rC Clang https://reviews.llvm.org/D52034 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D49916: [CodeGen] Add to emitted DebugLoc information about coverage when it's required
calixte created this revision. calixte added reviewers: marco-c, davidxl. Herald added a subscriber: cfe-commits. Some lines have a hit counter where they should not have one. Cleanup stuff is located to the last line of the body which is most of the time a '}'. And Exception stuff is added at the beginning of a function and at the end (represented by '{' and '}'). So in such cases, the DebugLoc used in GCOVProfiling.cpp must be marked as not covered. This patch is a followup of https://reviews.llvm.org/D49915. Repository: rC Clang https://reviews.llvm.org/D49916 Files: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h Index: lib/CodeGen/CodeGenFunction.h === --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -785,7 +785,7 @@ // If we should perform a cleanup, force them now. Note that // this ends the cleanup scope before rescoping any labels. if (PerformCleanup) { -ApplyDebugLocation DL(CGF, Range.getEnd()); +ApplyDebugLocation DL(CGF, Range.getEnd(), false /* Covered */); ForceCleanup(); } } Index: lib/CodeGen/CodeGenFunction.cpp === --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -1174,7 +1174,7 @@ } // Emit a location at the end of the prologue. if (CGDebugInfo *DI = getDebugInfo()) -DI->EmitLocation(Builder, StartLoc); +DI->EmitLocation(Builder, StartLoc, false /* Covered */); // TODO: Do we need to handle this in two places like we do with // target-features/target-cpu? Index: lib/CodeGen/CGDebugInfo.h === --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -361,7 +361,8 @@ /// Emit metadata to indicate a change in line/column information in /// the source file. If the location is invalid, the previous /// location will be reused. - void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + /// \param Covered True if the Loc must have coverage information + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, bool Covered = true); /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. @@ -641,16 +642,16 @@ /// location or preferred location of the specified Expr. class ApplyDebugLocation { private: - void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false); + void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false, bool Covered = true); ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, SourceLocation TemporaryLocation); llvm::DebugLoc OriginalLocation; CodeGenFunction *CGF; public: /// Set the location to the (valid) TemporaryLocation. - ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation); + ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation, bool Covered = true); ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E); ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc); ApplyDebugLocation(ApplyDebugLocation &&Other) : CGF(Other.CGF) { Index: lib/CodeGen/CGDebugInfo.cpp === --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -76,9 +76,10 @@ } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) + SourceLocation TemporaryLocation, + bool Covered) : CGF(&CGF) { - init(TemporaryLocation); + init(TemporaryLocation, false /* DefaultToEmpty */, Covered); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, @@ -89,7 +90,8 @@ } void ApplyDebugLocation::init(SourceLocation TemporaryLocation, - bool DefaultToEmpty) { + bool DefaultToEmpty, + bool Covered) { auto *DI = CGF->getDebugInfo(); if (!DI) { CGF = nullptr; @@ -102,7 +104,7 @@ return; if (TemporaryLocation.isValid()) { -DI->EmitLocation(CGF->Builder, TemporaryLocation); +DI->EmitLocation(CGF->Builder, TemporaryLocation, Covered); return; } @@ -3444,16 +3446,16 @@ setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt()); } -void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { +void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, bool Covered) { // Update our current location setLocation(Loc); if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; llvm::MDNode *Scope = LexicalBlockStack.back(); Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( - getLineNumber(CurLoc)
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte added a comment. @vsk, gcc guys are ok for -fprofile-filter-files and -fprofile-exclude-files, are you ok with that ? Should these options prefixed by -Xclang or not ? Repository: rC Clang https://reviews.llvm.org/D52034 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D53578: [CodeGen] Fix clang test for gcov profiling (follow-up of D51974)
calixte created this revision. calixte added a reviewer: vsk. Herald added a subscriber: cfe-commits. After patch https://reviews.llvm.org/D51974 has landed, this one is required to fix a test. Repository: rC Clang https://reviews.llvm.org/D53578 Files: test/CodeGen/code-coverage.c Index: test/CodeGen/code-coverage.c === --- test/CodeGen/code-coverage.c +++ test/CodeGen/code-coverage.c @@ -29,14 +29,10 @@ // Inside function emission data structure, check that // -coverage-no-function-names-in-data uses null as the function name. -// CHECK: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant -// CHECK-SAME: { i32 {{[0-9]+}}, i8* getelementptr inbounds ({{[^,]*}}, {{[^,]*}}* @ -// CHECK-SAME: { i32 {{[0-9]+}}, i8* getelementptr inbounds ({{[^,]*}}, {{[^,]*}}* @ -// WITHOUTNAMES: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant -// WITHOUTNAMES-NOT: getelementptr inbounds ({{.*}}@ -// WITHOUTNAMES-SAME: zeroinitializer, -// WITHOUTNAMES-NOT: getelementptr inbounds ({{.*}}@ -// WITHOUTNAMES-SAME: { i32 {{[0-9]+}}, i8* null, +// CHECK: {{.*}} private unnamed{{.*}}test1\00{{.*}} +// CHECK: {{.*}} private unnamed{{.*}}test2\00{{.*}} +// WITHOUTNAMES-NOT: {{.*}} private unnamed{{.*}}test1\00{{.*}} +// WITHOUTNAMES-NOT: {{.*}} private unnamed{{.*}}test2\00{{.*}} // Check that the noredzone flag is set on the generated functions. Index: test/CodeGen/code-coverage.c === --- test/CodeGen/code-coverage.c +++ test/CodeGen/code-coverage.c @@ -29,14 +29,10 @@ // Inside function emission data structure, check that // -coverage-no-function-names-in-data uses null as the function name. -// CHECK: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant -// CHECK-SAME: { i32 {{[0-9]+}}, i8* getelementptr inbounds ({{[^,]*}}, {{[^,]*}}* @ -// CHECK-SAME: { i32 {{[0-9]+}}, i8* getelementptr inbounds ({{[^,]*}}, {{[^,]*}}* @ -// WITHOUTNAMES: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant -// WITHOUTNAMES-NOT: getelementptr inbounds ({{.*}}@ -// WITHOUTNAMES-SAME: zeroinitializer, -// WITHOUTNAMES-NOT: getelementptr inbounds ({{.*}}@ -// WITHOUTNAMES-SAME: { i32 {{[0-9]+}}, i8* null, +// CHECK: {{.*}} private unnamed{{.*}}test1\00{{.*}} +// CHECK: {{.*}} private unnamed{{.*}}test2\00{{.*}} +// WITHOUTNAMES-NOT: {{.*}} private unnamed{{.*}}test1\00{{.*}} +// WITHOUTNAMES-NOT: {{.*}} private unnamed{{.*}}test2\00{{.*}} // Check that the noredzone flag is set on the generated functions. ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte updated this revision to Diff 172752. calixte added a comment. Change options names to -fprofile-exclude-files & -fprofile-filter-files and add some doc in UserManual. Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 -fprofile-exclude-files=".*\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$:.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$:.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.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 Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverag
[PATCH] D52034: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov
calixte updated this revision to Diff 172761. calixte added a comment. Fix plural form of regex and just use ';' as separator. Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 -fprofile-exclude-files=".*\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.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 Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); +Opts.ProfileFil
[PATCH] D52034: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov
calixte updated this revision to Diff 172905. calixte added a comment. Update doc. Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 -fprofile-exclude-files=".*\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.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 Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); +Opts.ProfileFilterFiles = +Args.getLastArgValue(OPT
[PATCH] D52034: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov
calixte updated this revision to Diff 173622. calixte added a comment. Update ReleaseNotes Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/ReleaseNotes.rst docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 -fprofile-exclude-files=".*\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.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 Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); +Opts.ProfileFilterFiles = +
[PATCH] D52034: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov
calixte updated this revision to Diff 173623. calixte added a comment. Forgot the ellipsis in the release notes. Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/ReleaseNotes.rst docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 -fprofile-exclude-files=".*\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=NO-HEADER2 %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o - \ +// RUN:| FileCheck -check-prefix=JUST-C %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=HEADER %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \ +// RUN:| FileCheck -check-prefix=NONE %s +// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.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 Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); +Opts.
[PATCH] D52034: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov
This revision was automatically updated to reflect the committed changes. Closed by commit rC346642: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to… (authored by calixte, committed by ). Changed prior to commit: https://reviews.llvm.org/D52034?vs=173623&id=173627#toc Repository: rC Clang https://reviews.llvm.org/D52034 Files: docs/ReleaseNotes.rst docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c Index: docs/UsersManual.rst === --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -1871,6 +1871,55 @@ following the Itanium C++ ABI mangling scheme. This covers all C++ targets supported by Clang other than Windows. +GCOV-based Profiling + + +GCOV is a test coverage program, it helps to know how often a line of code +is executed. When instrumenting the code with ``--coverage`` option, some +counters are added for each edge linking basic blocks. + +At compile time, gcno files are generated containing information about +blocks and edges between them. At runtime the counters are incremented and at +exit the counters are dumped in gcda files. + +The tool ``llvm-cov gcov`` will parse gcno, gcda and source files to generate +a report ``.c.gcov``. + +.. option:: -fprofile-filter-files=[regexes] + + Define a list of regexes separated by a semi-colon. + If a file name matches any of the regexes then the file is instrumented. + + .. code-block:: console + + $ clang --coverage -fprofile-filter-files=".*\.c$" foo.c + + For example, this will only instrument files finishing with ``.c``, skipping ``.h`` files. + +.. option:: -fprofile-exclude-files=[regexes] + + Define a list of regexes separated by a semi-colon. + If a file name doesn't match all the regexes then the file is instrumented. + + .. code-block:: console + + $ clang --coverage -fprofile-exclude-files="^/usr/include/.*$" foo.c + + For example, this will instrument all the files except the ones in ``/usr/include``. + +If both options are used then a file is instrumented if its name matches any +of the regexes from ``-fprofile-filter-list`` and doesn't match all the regexes +from ``-fprofile-exclude-list``. + +.. code-block:: console + + $ clang --coverage -fprofile-exclude-files="^/usr/include/.*$" \ + -fprofile-filter-files="^/usr/.*$" + +In that case ``/usr/foo/oof.h`` is instrumented since it matches the filter regex and +doesn't match the exclude regex, but ``/usr/include/foo.h`` doesn't since it matches +the exclude regex. + Controlling Debug Information - Index: docs/ReleaseNotes.rst === --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -64,6 +64,12 @@ New Compiler Flags -- +- ``-fprofile-filter-files=[regexes]`` and ``-fprofile-exclude-files=[regexes]``. + + Clang has now options to filter or exclude some files when + instrumenting for gcov-based profiling. + See the :doc:`UsersManual` for details. + - ... Deprecated Compiler Flags Index: include/clang/Driver/Options.td === --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -768,6 +768,12 @@ HelpText<"Disable using instrumentation data for profile-guided optimization">; def fno_profile_use : Flag<["-"], "fno-profile-use">, Alias; +def fprofile_filter_files_EQ : Joined<["-"], "fprofile-filter-files=">, +Group, Flags<[CC1Option, CoreOption]>, +HelpText<"Instrument only functions from files where names match any regex separated by a semi-colon">; +def fprofile_exclude_files_EQ : Joined<["-"], "fprofile-exclude-files=">, +Group, Flags<[CC1Option, CoreOption]>, +HelpText<"Instrument only functions from files where names don't match all the regexes separated by a semi-colon">; def faddrsig : Flag<["-"], "faddrsig">, Group, Flags<[CoreOption, CC1Option]>, HelpText<"Emit an address-significance table">; Index: include/clang/Frontend/CodeGenOptions.h === --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -127,6 +127,12 @@ /// The filename with path we use for coverage notes files. std::string CoverageNotesFile; + /// Regexes separated by a semi-colon to filter the files to instrument. + std::string ProfileFilterFiles; + + /// Regexes separated by a semi-colon to filter the files to not instrument. + std::string ProfileExcludeFiles; + /// The version string to put into coverage files. char CoverageVersion[4];
[PATCH] D54416: [GCOV] fix test after patch rL346642
calixte created this revision. calixte added a reviewer: marco-c. Herald added a subscriber: cfe-commits. Test is failing under windows, so fix it Repository: rC Clang https://reviews.llvm.org/D54416 Files: test/CodeGen/code-coverage-filter.c Index: test/CodeGen/code-coverage-filter.c === --- test/CodeGen/code-coverage-filter.c +++ test/CodeGen/code-coverage-filter.c @@ -23,62 +23,62 @@ test2(); } -// ALL: define void @test1() #0 {{.*}} +// ALL: void @test1() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test2() #0 {{.*}} +// ALL: void @test2() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test() #0 {{.*}} +// ALL: void @test() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// NO-HEADER: define void @test1() #0 {{.*}} +// NO-HEADER: void @test1() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test2() #0 {{.*}} +// NO-HEADER: void @test2() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test() #0 {{.*}} +// NO-HEADER: void @test() #0 {{.*}} // NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER2: define void @test1() #0 {{.*}} +// NO-HEADER2: void @test1() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test2() #0 {{.*}} +// NO-HEADER2: void @test2() #0 {{.*}} // NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test() #0 {{.*}} +// NO-HEADER2: void @test() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// JUST-C: define void @test1() #0 {{.*}} +// JUST-C: void @test1() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test2() #0 {{.*}} +// JUST-C: void @test2() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test() #0 {{.*}} +// JUST-C: void @test() #0 {{.*}} // JUST-C: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// HEADER: define void @test1() #0 {{.*}} +// HEADER: void @test1() #0 {{.*}} // HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// HEADER: define void @test2() #0 {{.*}} +// HEADER: void @test2() #0 {{.*}} // HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// HEADER: define void @test() #0 {{.*}} +// HEADER: void @test() #0 {{.*}} // HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// NONE: define void @test1() #0 {{.*}} +// NONE: void @test1() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void -// NONE: define void @test2() #0 {{.*}} +// NONE: void @test2() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void -// NONE: define void @test() #0 {{.*}} +// NONE: void @test() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void Index: test/CodeGen/code-coverage-filter.c === --- test/CodeGen/code-coverage-filter.c +++ test/CodeGen/code-coverage-filter.c @@ -23,62 +23,62 @@ test2(); } -// ALL: define void @test1() #0 {{.*}} +// ALL: void @test1() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test2() #0 {{.*}} +// ALL: void @test2() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test() #0 {{.*}} +// ALL: void @test() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// NO-HEADER: define void @test1() #0 {{.*}} +// NO-HEADER: void @test1() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test2() #0 {{.*}} +// NO-HEADER: void @test2() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test() #0 {{.*}} +// NO-HEADER: void @test() #0 {{.*}} // NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER2: define void @test1() #0 {{.*}} +// NO-HEADER2: void @test1() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test2() #0 {{.*}} +// NO-HEADER2: void @test2() #0 {{.*}} // NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test() #0 {{.*}} +// NO-HEADER2: void @test() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// JUST-C: define void @test1() #0 {{.*}} +// JUST-C: void @test1() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test2() #0 {{.*}} +// JUST-C: void @test2() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test() #0 {{.*}} +// JUST-C: void @test() #0 {{.*}} // JUST-C: {{.*}}__llvm
[PATCH] D54416: [GCOV] fix test after patch rL346642
This revision was automatically updated to reflect the committed changes. Closed by commit rL346644: [GCOV] fix test after patch rL346642 (authored by calixte, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D54416 Files: cfe/trunk/test/CodeGen/code-coverage-filter.c Index: cfe/trunk/test/CodeGen/code-coverage-filter.c === --- cfe/trunk/test/CodeGen/code-coverage-filter.c +++ cfe/trunk/test/CodeGen/code-coverage-filter.c @@ -23,62 +23,62 @@ test2(); } -// ALL: define void @test1() #0 {{.*}} +// ALL: void @test1() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test2() #0 {{.*}} +// ALL: void @test2() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test() #0 {{.*}} +// ALL: void @test() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// NO-HEADER: define void @test1() #0 {{.*}} +// NO-HEADER: void @test1() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test2() #0 {{.*}} +// NO-HEADER: void @test2() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test() #0 {{.*}} +// NO-HEADER: void @test() #0 {{.*}} // NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER2: define void @test1() #0 {{.*}} +// NO-HEADER2: void @test1() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test2() #0 {{.*}} +// NO-HEADER2: void @test2() #0 {{.*}} // NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test() #0 {{.*}} +// NO-HEADER2: void @test() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// JUST-C: define void @test1() #0 {{.*}} +// JUST-C: void @test1() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test2() #0 {{.*}} +// JUST-C: void @test2() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test() #0 {{.*}} +// JUST-C: void @test() #0 {{.*}} // JUST-C: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// HEADER: define void @test1() #0 {{.*}} +// HEADER: void @test1() #0 {{.*}} // HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// HEADER: define void @test2() #0 {{.*}} +// HEADER: void @test2() #0 {{.*}} // HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// HEADER: define void @test() #0 {{.*}} +// HEADER: void @test() #0 {{.*}} // HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // HEADER: ret void -// NONE: define void @test1() #0 {{.*}} +// NONE: void @test1() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void -// NONE: define void @test2() #0 {{.*}} +// NONE: void @test2() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void -// NONE: define void @test() #0 {{.*}} +// NONE: void @test() #0 {{.*}} // NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NONE: ret void Index: cfe/trunk/test/CodeGen/code-coverage-filter.c === --- cfe/trunk/test/CodeGen/code-coverage-filter.c +++ cfe/trunk/test/CodeGen/code-coverage-filter.c @@ -23,62 +23,62 @@ test2(); } -// ALL: define void @test1() #0 {{.*}} +// ALL: void @test1() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test2() #0 {{.*}} +// ALL: void @test2() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// ALL: define void @test() #0 {{.*}} +// ALL: void @test() #0 {{.*}} // ALL: {{.*}}__llvm_gcov_ctr{{.*}} // ALL: ret void -// NO-HEADER: define void @test1() #0 {{.*}} +// NO-HEADER: void @test1() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test2() #0 {{.*}} +// NO-HEADER: void @test2() #0 {{.*}} // NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER: define void @test() #0 {{.*}} +// NO-HEADER: void @test() #0 {{.*}} // NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER: ret void -// NO-HEADER2: define void @test1() #0 {{.*}} +// NO-HEADER2: void @test1() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test2() #0 {{.*}} +// NO-HEADER2: void @test2() #0 {{.*}} // NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// NO-HEADER2: define void @test() #0 {{.*}} +// NO-HEADER2: void @test() #0 {{.*}} // NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} // NO-HEADER2: ret void -// JUST-C: define void @test1() #0 {{.*}} +// JUST-C: void @test1() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} // JUST-C: ret void -// JUST-C: define void @test2() #0 {{.*}} +// JUST-C: void @test2() #0 {{.*}} // JUST-C-NOT: {{.*}}__llvm
[PATCH] D54600: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov (after revert https://reviews.llvm.org/rL346659)
calixte created this revision. calixte added a reviewer: marco-c. Herald added a subscriber: cfe-commits. the previous patch (https://reviews.llvm.org/rC346642) has been reverted because of test failure under windows. So this patch fix the test cfe/trunk/test/CodeGen/code-coverage-filter.c. Repository: rC Clang https://reviews.llvm.org/D54600 Files: docs/ReleaseNotes.rst docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c Index: test/CodeGen/code-coverage-filter.c === --- /dev/null +++ test/CodeGen/code-coverage-filter.c @@ -0,0 +1,84 @@ +// RUN: %clang -S -emit-llvm --coverage %s -o %t +// RUN: FileCheck -check-prefix=ALL < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*\.h$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER2 < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o %t +// RUN: FileCheck -check-prefix=JUST-C < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o %t +// RUN: FileCheck -check-prefix=HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o %t +// RUN: FileCheck -check-prefix=NONE < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.h$" %s -o %t +// RUN: FileCheck -check-prefix=JUST-C < %t %s + +#include "Inputs/code-coverage-filter1.h" +#include "Inputs/code-coverage-filter2.h" + +void test() { + test1(); + test2(); +} + +// ALL: void @test1() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: void @test2() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: void @test() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void + +// NO-HEADER: void @test1() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: void @test2() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: void @test() #0 {{.*}} +// NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void + +// NO-HEADER2: void @test1() #0 {{.*}} +// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void +// NO-HEADER2: void @test2() #0 {{.*}} +// NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void +// NO-HEADER2: void @test() #0 {{.*}} +// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void + +// JUST-C: void @test1() #0 {{.*}} +// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void +// JUST-C: void @test2() #0 {{.*}} +// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void +// JUST-C: void @test() #0 {{.*}} +// JUST-C: {{.*}}__llvm_gcov_ctr{{.*}} +// JUST-C: ret void + +// HEADER: void @test1() #0 {{.*}} +// HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void +// HEADER: void @test2() #0 {{.*}} +// HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void +// HEADER: void @test() #0 {{.*}} +// HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// HEADER: ret void + +// NONE: void @test1() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void +// NONE: void @test2() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void +// NONE: void @test() #0 {{.*}} +// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NONE: ret void Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: lib/Frontend/CompilerInvocation.cpp === --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -828,6 +828,10 @@ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); +Opts.ProfileFilterFiles = +Args.getLastArgValue(OPT_fprofile_filter_files_EQ); +Opts.ProfileExcludeFiles = +Args.getLastArgValue(OPT_fprofile_exclude_files_EQ); Opts.CoverageExitBlockBeforeBody =
[PATCH] D54600: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter the files to instrument with gcov (after revert https://reviews.llvm.org/rL346659)
This revision was automatically updated to reflect the committed changes. Closed by commit rC347144: [Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to… (authored by calixte, committed by ). Changed prior to commit: https://reviews.llvm.org/D54600?vs=174281&id=174512#toc Repository: rC Clang https://reviews.llvm.org/D54600 Files: docs/ReleaseNotes.rst docs/UsersManual.rst include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c Index: include/clang/Frontend/CodeGenOptions.h === --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -129,6 +129,12 @@ /// The filename with path we use for coverage notes files. std::string CoverageNotesFile; + /// Regexes separated by a semi-colon to filter the files to instrument. + std::string ProfileFilterFiles; + + /// Regexes separated by a semi-colon to filter the files to not instrument. + std::string ProfileExcludeFiles; + /// The version string to put into coverage files. char CoverageVersion[4]; Index: include/clang/Driver/Options.td === --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -768,6 +768,12 @@ HelpText<"Disable using instrumentation data for profile-guided optimization">; def fno_profile_use : Flag<["-"], "fno-profile-use">, Alias; +def fprofile_filter_files_EQ : Joined<["-"], "fprofile-filter-files=">, +Group, Flags<[CC1Option, CoreOption]>, +HelpText<"Instrument only functions from files where names match any regex separated by a semi-colon">; +def fprofile_exclude_files_EQ : Joined<["-"], "fprofile-exclude-files=">, +Group, Flags<[CC1Option, CoreOption]>, +HelpText<"Instrument only functions from files where names don't match all the regexes separated by a semi-colon">; def faddrsig : Flag<["-"], "faddrsig">, Group, Flags<[CoreOption, CC1Option]>, HelpText<"Emit an address-significance table">; Index: test/CodeGen/Inputs/code-coverage-filter2.h === --- test/CodeGen/Inputs/code-coverage-filter2.h +++ test/CodeGen/Inputs/code-coverage-filter2.h @@ -0,0 +1 @@ +void test2() {} Index: test/CodeGen/Inputs/code-coverage-filter1.h === --- test/CodeGen/Inputs/code-coverage-filter1.h +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1 @@ +void test1() {} Index: test/CodeGen/code-coverage-filter.c === --- test/CodeGen/code-coverage-filter.c +++ test/CodeGen/code-coverage-filter.c @@ -0,0 +1,84 @@ +// RUN: %clang -S -emit-llvm --coverage %s -o %t +// RUN: FileCheck -check-prefix=ALL < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*\.h$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o %t +// RUN: FileCheck -check-prefix=NO-HEADER2 < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o %t +// RUN: FileCheck -check-prefix=JUST-C < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o %t +// RUN: FileCheck -check-prefix=HEADER < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o %t +// RUN: FileCheck -check-prefix=NONE < %t %s +// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.h$" %s -o %t +// RUN: FileCheck -check-prefix=JUST-C < %t %s + +#include "Inputs/code-coverage-filter1.h" +#include "Inputs/code-coverage-filter2.h" + +void test() { + test1(); + test2(); +} + +// ALL: void @test1() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: void @test2() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void +// ALL: void @test() #0 {{.*}} +// ALL: {{.*}}__llvm_gcov_ctr{{.*}} +// ALL: ret void + +// NO-HEADER: void @test1() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: void @test2() #0 {{.*}} +// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void +// NO-HEADER: void @test() #0 {{.*}} +// NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER: ret void + +// NO-HEADER2: void @test1() #0 {{.*}} +// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}} +// NO-HEADER2: ret void +// NO-HEADER2: void @test2() #0 {
[PATCH] D49916: [CodeGen] Add to emitted DebugLoc information about coverage when it's required
This revision was automatically updated to reflect the committed changes. Closed by commit rC342717: [CodeGen] Add to emitted DebugLoc information about coverage when it's required (authored by calixte, committed by ). Changed prior to commit: https://reviews.llvm.org/D49916?vs=164860&id=166416#toc Repository: rC Clang https://reviews.llvm.org/D49916 Files: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h lib/CodeGen/CGException.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/debug-info-scope-file.c test/CodeGenCXX/debug-info-inheriting-constructor.cpp test/CodeGenCXX/linetable-virtual-variadic.cpp test/CodeGenObjC/arc-linetable.m test/CodeGenObjC/debug-info-blocks.m Index: lib/CodeGen/CGDebugInfo.cpp === --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -76,20 +76,22 @@ } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) + SourceLocation TemporaryLocation, + bool ImplicitCode) : CGF(&CGF) { - init(TemporaryLocation); + init(TemporaryLocation, false /* DefaultToEmpty */, ImplicitCode); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, - SourceLocation TemporaryLocation) + SourceLocation TemporaryLocation, + bool ImplicitCode) : CGF(&CGF) { - init(TemporaryLocation, DefaultToEmpty); + init(TemporaryLocation, DefaultToEmpty, ImplicitCode); } void ApplyDebugLocation::init(SourceLocation TemporaryLocation, - bool DefaultToEmpty) { + bool DefaultToEmpty, bool ImplicitCode) { auto *DI = CGF->getDebugInfo(); if (!DI) { CGF = nullptr; @@ -102,7 +104,7 @@ return; if (TemporaryLocation.isValid()) { -DI->EmitLocation(CGF->Builder, TemporaryLocation); +DI->EmitLocation(CGF->Builder, TemporaryLocation, ImplicitCode); return; } @@ -3484,16 +3486,18 @@ setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt()); } -void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { +void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, + bool ImplicitCode) { // Update our current location setLocation(Loc); if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; llvm::MDNode *Scope = LexicalBlockStack.back(); - Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( - getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt)); + Builder.SetCurrentDebugLocation( + llvm::DebugLoc::get(getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, + CurInlinedAt, ImplicitCode)); } void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { @@ -3540,7 +3544,7 @@ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); // Provide an entry in the line table for the end of the block. - EmitLocation(Builder, Loc); + EmitLocation(Builder, Loc, true /* ImplicitCode */); if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; @@ -3556,7 +3560,7 @@ // Pop all regions for this function. while (LexicalBlockStack.size() != RCount) { // Provide an entry in the line table for the end of the block. -EmitLocation(Builder, CurLoc); +EmitLocation(Builder, CurLoc, true /* ImplicitCode */); LexicalBlockStack.pop_back(); } FnBeginRegionCount.pop_back(); Index: lib/CodeGen/CGDebugInfo.h === --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -377,7 +377,9 @@ /// Emit metadata to indicate a change in line/column information in /// the source file. If the location is invalid, the previous /// location will be reused. - void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + /// \param ImplicitCode True if the Loc must have coverage information + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc, +bool ImplicitCode = false); /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. @@ -664,16 +666,19 @@ /// location or preferred location of the specified Expr. class ApplyDebugLocation { private: - void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false); + void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false, +bool ImplicitCode = false); ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, - SourceLocation TemporaryLocation); + SourceLocation TemporaryLocation, + bool Implic
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte updated this revision to Diff 167101. calixte added a comment. Fix tests Repository: rC Clang https://reviews.llvm.org/D52034 Files: include/clang/Driver/CC1Options.td include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/Inputs/code-coverage-filter1.h test/CodeGen/Inputs/code-coverage-filter2.h test/CodeGen/code-coverage-filter.c 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 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/Inputs/code-coverage-filter1.h === --- /dev/null +++ test/CodeGen/Inputs/code-coverage-filter1.h @@ -0,0 +1,2 @@ +void test1() { +} 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.CoverageExi
[PATCH] D52034: [Clang] Add options -Xclang -coverage-filter and -Xclang -coverage-exclude to filter the files to instrument with gcov
calixte added a comment. I reported a bug for gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87442 @vsk I'd like to add documentation in Docs/UsersManual.rst, but I've no idea on what's a good place for this (I look for option -coverage-no-function-names-in-data, but I didn't get anything). So could you give a me a clue please ? Repository: rC Clang https://reviews.llvm.org/D52034 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D83149: [gcov] Add __gcov_dump/__gcov_reset and delete __gcov_flush
calixte accepted this revision. calixte added a comment. LGTM Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D83149/new/ https://reviews.llvm.org/D83149 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D78477: [profile] Don't crash when forking in several threads
calixte updated this revision to Diff 258686. calixte added a comment. Herald added a project: clang. Herald added a subscriber: cfe-commits. Export symbol for Darwin target Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D78477/new/ https://reviews.llvm.org/D78477 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c compiler-rt/test/profile/Inputs/instrprof-gcov-multithread_fork.cpp compiler-rt/test/profile/instrprof-gcov-multithread_fork.test llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,79 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector Forks; + SmallVector Execs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + Forks.push_back(CI); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + Execs.push_back(CI); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); + for (auto F : Forks) { +IRBuilder<> Builder(F); +BasicBlock *Parent = F->getParent(); +auto NextInst = ++F->getIterator(); + +// We've a fork so just reset the counters in the child process +FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); +FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); +F->setCalledFunction(GCOVFork); +if (NextInst != Parent->end()) { + // We split just after the fork to have a counter for the lines after + // Anyway there's a bug: + // void foo() { fork(); } + // void bar() { foo(); blah(); } + // then "blah();" will be called 2 times but showed as 1 + // because "blah()" belongs to the same block as "foo();" + Parent->splitBasicBlock(NextInst); + + // back() is a br instruction with a debug location + // equals to the one from NextAfterFork + // So to avoid to have two debug locs on two blocks just change it + DebugLoc Loc = F->getDebugLoc(); + Parent->back().setDebugLoc(Loc); +} + } + + for (auto E : Execs) { +IRBuilder<> Builder(E); +BasicBlock *Parent = E->getParent(); +auto NextInst = ++E->getIterator(); + +// Since the process is replaced by a new one we need to write out gcdas +// No need to reset the counters since they'll be lost after the exec** FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); +FunctionCallee WriteoutF = +M->getOrInsertFunction("llvm_writeout_files", FTy); +Builder.CreateCall(WriteoutF); +if (NextInst != Parent->end()) { + DebugLoc Loc = E->getDebugLoc(); + Builder.SetInsertPoint(&*NextInst); + // If the exec** fails we must reset the counters since they've been + // dumped + FunctionCallee ResetF = + M->getOrInsertFunction("llvm_reset_counters", FTy); + Builder.CreateCall(ResetF)->setDebugLoc(Loc); + Parent->splitBasicBlock(NextInst); + Parent->back().setDebugLoc(Loc); +} } } @@ -851,7 +896,8 @@ } Function *WriteoutF = insertCounterWriteout(CountersBySP); -Function *FlushF = insertFlush(CountersBySP); +Function *ResetF = insertReset(CountersBySP); +Function *FlushF = insert
[PATCH] D78477: [profile] Don't crash when forking in several threads
calixte updated this revision to Diff 259854. calixte added a comment. Fix nits. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D78477/new/ https://reviews.llvm.org/D78477 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c compiler-rt/test/profile/Inputs/instrprof-gcov-multithread_fork.cpp compiler-rt/test/profile/instrprof-gcov-multithread_fork.test llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,76 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector Forks; + SmallVector Execs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + Forks.push_back(CI); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + Execs.push_back(CI); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); + for (auto F : Forks) { +IRBuilder<> Builder(F); +BasicBlock *Parent = F->getParent(); +auto NextInst = ++F->getIterator(); + +// We've a fork so just reset the counters in the child process +FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); +FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); +F->setCalledFunction(GCOVFork); + +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } +// void bar() { foo(); blah(); } +// then "blah();" will be called 2 times but showed as 1 +// because "blah()" belongs to the same block as "foo();" +Parent->splitBasicBlock(NextInst); + +// back() is a br instruction with a debug location +// equals to the one from NextAfterFork +// So to avoid to have two debug locs on two blocks just change it +DebugLoc Loc = F->getDebugLoc(); +Parent->back().setDebugLoc(Loc); + } + + for (auto E : Execs) { +IRBuilder<> Builder(E); +BasicBlock *Parent = E->getParent(); +auto NextInst = ++E->getIterator(); + +// Since the process is replaced by a new one we need to write out gcdas +// No need to reset the counters since they'll be lost after the exec** FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); +FunctionCallee WriteoutF = +M->getOrInsertFunction("llvm_writeout_files", FTy); +Builder.CreateCall(WriteoutF); + +DebugLoc Loc = E->getDebugLoc(); +Builder.SetInsertPoint(&*NextInst); +// If the exec** fails we must reset the counters since they've been +// dumped +FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); +Builder.CreateCall(ResetF)->setDebugLoc(Loc); +Parent->splitBasicBlock(NextInst); +Parent->back().setDebugLoc(Loc); } } @@ -851,7 +893,8 @@ } Function *WriteoutF = insertCounterWriteout(CountersBySP); -Function *FlushF = insertFlush(CountersBySP); +Function *ResetF = insertReset(CountersBySP); +Function *FlushF = insertFlush(ResetF); // Create a small bit of code that registers the "__llvm_gcov_writeout" to // be executed at exit and the "__llvm_gcov_flush" function to be executed @@ -869,16 +912,14 @@ IRBuilder<> Builder(BB);
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte created this revision. calixte added a reviewer: marco-c. Herald added subscribers: llvm-commits, Sanitizers, cfe-commits, hiraditya. Herald added projects: clang, Sanitizers, LLVM. There is no need to write out gcdas when forking because we can just reset the counters in the parent process. Let say a counter is N before the fork, then fork and this counter is set to 0 in the child process. In the parent process, the counter is incremented by P and in the child process it's incremented by C. When dump is ran at exit, parent process will dump N+P for the given counter and the child process will dump 0+C, so when the gcdas are merged the resulting counter will be N+P+C. About exec** functions, since the current process is replaced by an another one there is no need to reset the counters but just write out the gcdas since the counters are definitely lost. To avoid to have lists in a bad state, we just lock them during the fork and the flush (if called explicitely) and lock them when an element is added. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74953 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,66 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + ForkAndExecs.push_back({true, CI}); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + ForkAndExecs.push_back({false, CI}); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); -FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); + for (auto F : ForkAndExecs) { +IRBuilder<> Builder(F.second); +BasicBlock *Parent = F.second->getParent(); +auto NextInst = ++F.second->getIterator(); + +if (F.first) { + // We've a fork so just reset the counters in the child process + FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); + FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); + F.second->setCalledFunction(GCOVFork); + if (NextInst != Parent->end()) { +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } +// void bar() { foo(); blah(); } +// then "blah();" will be called 2 times but showed as 1 +// because "blah()" belongs to the same block as "foo();" +Parent->splitBasicBlock(NextInst); + +// back() is a br instruction with a debug location +// equals to the one from NextAfterFork +// So to avoid to have two debug locs on two blocks just change it +DebugLoc Loc = F.second->getDebugLoc(); +Parent->back().setDebugLoc(Loc); + } +} else { + // Since the process is replaced by a new one we need to write out gcdas + // No need to reset the counters since there'll be lost after the exec** + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); + FunctionCallee WriteoutF = + M->getOrInsertFunction("llvm_writeout_files
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte updated this revision to Diff 245837. calixte added a comment. If exec** fails we need to reset the counters since they've have dumped just before to avoid to count them twice. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74953/new/ https://reviews.llvm.org/D74953 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,74 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + ForkAndExecs.push_back({true, CI}); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + ForkAndExecs.push_back({false, CI}); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); -FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); + for (auto F : ForkAndExecs) { +IRBuilder<> Builder(F.second); +BasicBlock *Parent = F.second->getParent(); +auto NextInst = ++F.second->getIterator(); + +if (F.first) { + // We've a fork so just reset the counters in the child process + FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); + FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); + F.second->setCalledFunction(GCOVFork); + if (NextInst != Parent->end()) { +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } +// void bar() { foo(); blah(); } +// then "blah();" will be called 2 times but showed as 1 +// because "blah()" belongs to the same block as "foo();" +Parent->splitBasicBlock(NextInst); + +// back() is a br instruction with a debug location +// equals to the one from NextAfterFork +// So to avoid to have two debug locs on two blocks just change it +DebugLoc Loc = F.second->getDebugLoc(); +Parent->back().setDebugLoc(Loc); + } +} else { + // Since the process is replaced by a new one we need to write out gcdas + // No need to reset the counters since there'll be lost after the exec** + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); + FunctionCallee WriteoutF = + M->getOrInsertFunction("llvm_writeout_files", FTy); + Builder.CreateCall(WriteoutF); + if (NextInst != Parent->end()) { +DebugLoc Loc = F.second->getDebugLoc(); +Builder.SetInsertPoint(&*NextInst); +// If the exec** fails we must reset the counters since they've been +// dumped +FunctionCallee ResetF = +M->getOrInsertFunction("llvm_reset_counters", FTy); +Builder.CreateCall(ResetF)->setDebugLoc(Loc); +Parent->splitBasicBlock(NextInst); +Parent->back().setDebugLoc(Loc); + } +} } } @@ -851,7 +891,8 @@ } Function *WriteoutF = insertCounterWriteout(CountersBySP); -Function *FlushF = insertFlush(CountersBySP); +Function *ResetF = insertReset(CountersBySP); +Function *FlushF = insertFlush(ResetF
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte updated this revision to Diff 245843. calixte marked 4 inline comments as done. calixte added a comment. Add more comments to explain why we need to lock around the fork Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74953/new/ https://reviews.llvm.org/D74953 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,74 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + ForkAndExecs.push_back({true, CI}); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + ForkAndExecs.push_back({false, CI}); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); -FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); + for (auto F : ForkAndExecs) { +IRBuilder<> Builder(F.second); +BasicBlock *Parent = F.second->getParent(); +auto NextInst = ++F.second->getIterator(); + +if (F.first) { + // We've a fork so just reset the counters in the child process + FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); + FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); + F.second->setCalledFunction(GCOVFork); + if (NextInst != Parent->end()) { +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } +// void bar() { foo(); blah(); } +// then "blah();" will be called 2 times but showed as 1 +// because "blah()" belongs to the same block as "foo();" +Parent->splitBasicBlock(NextInst); + +// back() is a br instruction with a debug location +// equals to the one from NextAfterFork +// So to avoid to have two debug locs on two blocks just change it +DebugLoc Loc = F.second->getDebugLoc(); +Parent->back().setDebugLoc(Loc); + } +} else { + // Since the process is replaced by a new one we need to write out gcdas + // No need to reset the counters since there'll be lost after the exec** + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); + FunctionCallee WriteoutF = + M->getOrInsertFunction("llvm_writeout_files", FTy); + Builder.CreateCall(WriteoutF); + if (NextInst != Parent->end()) { +DebugLoc Loc = F.second->getDebugLoc(); +Builder.SetInsertPoint(&*NextInst); +// If the exec** fails we must reset the counters since they've been +// dumped +FunctionCallee ResetF = +M->getOrInsertFunction("llvm_reset_counters", FTy); +Builder.CreateCall(ResetF)->setDebugLoc(Loc); +Parent->splitBasicBlock(NextInst); +Parent->back().setDebugLoc(Loc); + } +} } } @@ -851,7 +891,8 @@ } Function *WriteoutF = insertCounterWriteout(CountersBySP); -Function *FlushF = insertFlush(CountersBySP); +Function *ResetF = insertReset(CountersBySP); +Function *FlushF = insertFlush(ResetF);
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte added inline comments. Comment at: compiler-rt/lib/profile/GCDAProfiling.c:671 +pid_t child_pid = getpid(); +if (child_pid != parent_pid) { + // The pid changed so we've a fork marco-c wrote: > Nit: do we need this check or can we just use the earlier one on pid == 0? I added this check to be sure we had a true fork in case of someone wrote its own fork function. Comment at: compiler-rt/lib/profile/GCDAProfiling.c:675 + // No need to lock here since we just forked and cannot have any other + // threads. + struct fn_node *curr = reset_fn_list.head; marco-c wrote: > What if we have a thread in another process making modifications to the list? When forking, only the thread in the parent process is copied so in the child process we've only one thread. When forking, the parent and the child process share the same memory until some change (Copy-on-Write), so even if in the parent process a list is changed then the memory will be copied before the change and then the child process will have an unchanged list. Comment at: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp:635 void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { marco-c wrote: > Since we are now mostly doing different things on forks and execs, we could > remove this vector and just do the operations directly instead of adding to > the vec. If we make the insertions of new code in the second for loop, we'll invalidate the iterator used in this loop. Comment at: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp:671 +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } marco-c wrote: > Isn't this bug fixed by splitting the block? With the example shew here, the split is in foo but not in bar, blah() should be in another block Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74953/new/ https://reviews.llvm.org/D74953 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte marked an inline comment as done. calixte added inline comments. Comment at: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp:635 void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { marco-c wrote: > calixte wrote: > > marco-c wrote: > > > Since we are now mostly doing different things on forks and execs, we > > > could remove this vector and just do the operations directly instead of > > > adding to the vec. > > If we make the insertions of new code in the second for loop, we'll > > invalidate the iterator used in this loop. > M->getOrInsertFunction is what would invalidate the iterator? > > You could clean things up a bit by having two vectors then, one for forks and > one for execs. Builder.Create** will invalidate the iterator Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74953/new/ https://reviews.llvm.org/D74953 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D74953: [profile] Don't dump counters when forking and don't reset when calling exec** functions
calixte updated this revision to Diff 245848. calixte added a comment. Fix a typo Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74953/new/ https://reviews.llvm.org/D74953 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -115,7 +115,8 @@ // list. Function * insertCounterWriteout(ArrayRef>); - Function *insertFlush(ArrayRef>); + Function *insertReset(ArrayRef>); + Function *insertFlush(Function *ResetF); void AddFlushBeforeForkAndExec(); @@ -631,35 +632,74 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForkAndExecs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { +#if !defined(_WIN32) + ForkAndExecs.push_back({true, CI}); +#endif +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + ForkAndExecs.push_back({false, CI}); +} } } } } } - // We need to split the block after the fork/exec call - // because else the counters for the lines after will be - // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); -FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); -FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); -Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); + for (auto F : ForkAndExecs) { +IRBuilder<> Builder(F.second); +BasicBlock *Parent = F.second->getParent(); +auto NextInst = ++F.second->getIterator(); + +if (F.first) { + // We've a fork so just reset the counters in the child process + FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); + FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); + F.second->setCalledFunction(GCOVFork); + if (NextInst != Parent->end()) { +// We split just after the fork to have a counter for the lines after +// Anyway there's a bug: +// void foo() { fork(); } +// void bar() { foo(); blah(); } +// then "blah();" will be called 2 times but showed as 1 +// because "blah()" belongs to the same block as "foo();" +Parent->splitBasicBlock(NextInst); + +// back() is a br instruction with a debug location +// equals to the one from NextAfterFork +// So to avoid to have two debug locs on two blocks just change it +DebugLoc Loc = F.second->getDebugLoc(); +Parent->back().setDebugLoc(Loc); + } +} else { + // Since the process is replaced by a new one we need to write out gcdas + // No need to reset the counters since they'll be lost after the exec** + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); + FunctionCallee WriteoutF = + M->getOrInsertFunction("llvm_writeout_files", FTy); + Builder.CreateCall(WriteoutF); + if (NextInst != Parent->end()) { +DebugLoc Loc = F.second->getDebugLoc(); +Builder.SetInsertPoint(&*NextInst); +// If the exec** fails we must reset the counters since they've been +// dumped +FunctionCallee ResetF = +M->getOrInsertFunction("llvm_reset_counters", FTy); +Builder.CreateCall(ResetF)->setDebugLoc(Loc); +Parent->splitBasicBlock(NextInst); +Parent->back().setDebugLoc(Loc); + } +} } } @@ -851,7 +891,8 @@ } Function *WriteoutF = insertCounterWriteout(CountersBySP); -Function *FlushF = insertFlush(CountersBySP); +Function *ResetF = insertReset(CountersBySP); +Function *FlushF = insertFlush(ResetF); // Create a small bit of code that registers the "__llvm_gcov_writeout" to // be executed
[PATCH] D74071: [Profile] Avoid deadlock in multithreaded context when forking with coverage enabled
calixte created this revision. calixte added a reviewer: marco-c. Herald added subscribers: llvm-commits, Sanitizers, cfe-commits, jfb, hiraditya. Herald added projects: clang, Sanitizers, LLVM. When a program is forked with code coverage enabled, all the counters are flushed. To avoid data race, a critical section has been added around `__gcov_flush` (https://reviews.llvm.org/D70910) but when forking the mutex is just duplicated and if it was in a locked state (in the parent process) then it's locked in the child process which leads to a deadlock when the child is trying to flush counters. This patch aims to initialize the mutex in the child process when forking. So a custom fork (`__gcov_fork`) is called from instrumented code and the mutex is then initialized in the child process. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74071 Files: clang/lib/Driver/ToolChains/Darwin.cpp compiler-rt/lib/profile/GCDAProfiling.c llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp === --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -631,20 +631,22 @@ } void GCOVProfiler::AddFlushBeforeForkAndExec() { - SmallVector ForkAndExecs; + SmallVector, 2> ForksAndExecs; for (auto &F : M->functions()) { auto *TLI = &GetTLI(F); for (auto &I : instructions(F)) { if (CallInst *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { LibFunc LF; - if (TLI->getLibFunc(*Callee, LF) && - (LF == LibFunc_fork || LF == LibFunc_execl || - LF == LibFunc_execle || LF == LibFunc_execlp || - LF == LibFunc_execv || LF == LibFunc_execvp || - LF == LibFunc_execve || LF == LibFunc_execvpe || - LF == LibFunc_execvP)) { -ForkAndExecs.push_back(&I); + if (TLI->getLibFunc(*Callee, LF)) { +if (LF == LibFunc_fork) { + ForksAndExecs.push_back({true, CI}); +} else if (LF == LibFunc_execl || LF == LibFunc_execle || + LF == LibFunc_execlp || LF == LibFunc_execv || + LF == LibFunc_execvp || LF == LibFunc_execve || + LF == LibFunc_execvpe || LF == LibFunc_execvP) { + ForksAndExecs.push_back({false, CI}); +} } } } @@ -654,12 +656,21 @@ // We need to split the block after the fork/exec call // because else the counters for the lines after will be // the same as before the call. - for (auto I : ForkAndExecs) { -IRBuilder<> Builder(I); + for (auto F : ForksAndExecs) { +IRBuilder<> Builder(F.second); FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); Builder.CreateCall(GCOVFlush); -I->getParent()->splitBasicBlock(I); + +if (F.first) { + // We've a fork, so we call a custom fork which will initialize the mutex + // used when flushing + FTy = FunctionType::get(Builder.getInt32Ty(), {}, false); + FunctionCallee GCOVFork = M->getOrInsertFunction("__gcov_fork", FTy); + F.second->setCalledFunction(GCOVFork); +} + +F.second->getParent()->splitBasicBlock(F.second); } } Index: compiler-rt/lib/profile/GCDAProfiling.c === --- compiler-rt/lib/profile/GCDAProfiling.c +++ compiler-rt/lib/profile/GCDAProfiling.c @@ -71,6 +71,9 @@ static __inline void gcov_flush_unlock() { pthread_mutex_unlock(&gcov_flush_mutex); } +static __inline void gcov_flush_init_mutex() { + pthread_mutex_init(&gcov_flush_mutex, NULL); +} #else #include static SRWLOCK gcov_flush_mutex = SRWLOCK_INIT; @@ -80,6 +83,9 @@ static __inline void gcov_flush_unlock() { ReleaseSRWLockExclusive(&gcov_flush_mutex); } +static __inline void gcov_flush_init_mutex() { + InitializeSRWLock(&gcov_flush_mutex); +} #endif /* #define DEBUG_GCDAPROFILING */ @@ -638,6 +644,16 @@ fn_list_insert(&flush_fn_list, fn); } +pid_t __gcov_fork() { + pid_t pid = fork(); + + if (pid == 0) { +gcov_flush_init_mutex(); + } + + return pid; +} + void __gcov_flush() { gcov_flush_lock(); Index: clang/lib/Driver/ToolChains/Darwin.cpp === --- clang/lib/Driver/ToolChains/Darwin.cpp +++ clang/lib/Driver/ToolChains/Darwin.cpp @@ -1143,6 +1143,7 @@ // runtime's functionality. if (hasExportSymbolDirective(Args)) { if (ForGCOV) { + addExportedSymbol(CmdArgs, "___gcov_fork"); addExportedSymbol(CmdArgs, "___gcov_flush"); addExportedSymbol(CmdArgs, "_flush_fn_list"); addExportedSymbol(CmdArgs, "_writeout_fn_list"); ___