diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1196,7 +1196,8 @@ // runtime's functionality. if (hasExportSymbolDirective(Args)) { if (ForGCOV) { - addExportedSymbol(CmdArgs, "___gcov_flush"); + addExportedSymbol(CmdArgs, "___gcov_dump"); + addExportedSymbol(CmdArgs, "___gcov_reset"); addExportedSymbol(CmdArgs, "_flush_fn_list"); addExportedSymbol(CmdArgs, "_writeout_fn_list"); addExportedSymbol(CmdArgs, "_reset_fn_list"); diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c --- a/clang/test/CodeGen/code-coverage.c +++ b/clang/test/CodeGen/code-coverage.c @@ -51,7 +51,6 @@ // Check that the noredzone flag is set on the generated functions. // 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]] // CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} } diff --git a/clang/test/Driver/darwin-ld.c b/clang/test/Driver/darwin-ld.c --- a/clang/test/Driver/darwin-ld.c +++ b/clang/test/Driver/darwin-ld.c @@ -351,7 +351,8 @@ // RUN: FileCheck -check-prefix=GCOV_EXPORT %s < %t.log // RUN: %clang -target x86_64-apple-darwin12 -fprofile-arcs -Xlinker -exported_symbols_list -Xlinker /dev/null -### %t.o 2> %t.log // RUN: FileCheck -check-prefix=GCOV_EXPORT %s < %t.log -// GCOV_EXPORT: "-exported_symbol" "___gcov_flush" +// GCOV_EXPORT: "-exported_symbol" "___gcov_dump" +// GCOV_EXPORT: "-exported_symbol" "___gcov_reset" // // Check that we can pass the outliner down to the linker. // RUN: env IPHONEOS_DEPLOYMENT_TARGET=7.0 \ diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c --- a/compiler-rt/lib/profile/GCDAProfiling.c +++ b/compiler-rt/lib/profile/GCDAProfiling.c @@ -639,25 +639,6 @@ fn_list_remove(&writeout_fn_list); } -COMPILER_RT_VISIBILITY -void llvm_register_flush_function(fn_ptr fn) { - fn_list_insert(&flush_fn_list, fn); -} - -void __gcov_flush() { - struct fn_node* curr = flush_fn_list.head; - - while (curr) { - curr->fn(); - curr = curr->next; - } -} - -COMPILER_RT_VISIBILITY -void llvm_delete_flush_function_list(void) { - fn_list_remove(&flush_fn_list); -} - COMPILER_RT_VISIBILITY void llvm_register_reset_function(fn_ptr fn) { fn_list_insert(&reset_fn_list, fn); @@ -698,15 +679,12 @@ #endif COMPILER_RT_VISIBILITY -void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn, fn_ptr rfn) { +void llvm_gcov_init(fn_ptr wfn, fn_ptr rfn) { static int atexit_ran = 0; if (wfn) llvm_register_writeout_function(wfn); - if (ffn) - llvm_register_flush_function(ffn); - if (rfn) llvm_register_reset_function(rfn); @@ -715,11 +693,20 @@ /* Make sure we write out the data and delete the data structures. */ atexit(llvm_delete_reset_function_list); - atexit(llvm_delete_flush_function_list); #ifdef _WIN32 atexit(llvm_writeout_and_clear); #endif } } +void __gcov_dump(void) { + for (struct fn_node *f = writeout_fn_list.head; f; f = f->next) + f->fn(); +} + +void __gcov_reset(void) { + for (struct fn_node *f = reset_fn_list.head; f; f = f->next) + f->fn(); +} + #endif diff --git a/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c b/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c --- a/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c +++ b/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c @@ -46,21 +46,21 @@ #endif dlerror(); - void (*gcov_flush1)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); - if (gcov_flush1 == NULL) { - fprintf(stderr, "unable to find __gcov_flush in func.shared': %s\n", dlerror()); + void (*gcov_reset1)() = (void (*)())dlsym(f1_handle, "__gcov_reset"); + if (gcov_reset1 == NULL) { + fprintf(stderr, "unable to find __gcov_reset in func.shared': %s\n", dlerror()); return EXIT_FAILURE; } dlerror(); - void (*gcov_flush2)() = (void (*)())dlsym(f2_handle, "__gcov_flush"); - if (gcov_flush2 == NULL) { - fprintf(stderr, "unable to find __gcov_flush in func2.shared': %s\n", dlerror()); + void (*gcov_reset2)() = (void (*)())dlsym(f2_handle, "__gcov_reset"); + if (gcov_reset2 == NULL) { + fprintf(stderr, "unable to find __gcov_reset in func2.shared': %s\n", dlerror()); return EXIT_FAILURE; } - if (gcov_flush1 == gcov_flush2) { - fprintf(stderr, "Same __gcov_flush found in func.shared and func2.shared\n"); + if (gcov_reset1 == gcov_reset2) { + fprintf(stderr, "Same __gcov_reset found in func.shared and func2.shared\n"); return EXIT_FAILURE; } diff --git a/compiler-rt/test/profile/Posix/gcov-dlopen.c b/compiler-rt/test/profile/Posix/gcov-dlopen.c --- a/compiler-rt/test/profile/Posix/gcov-dlopen.c +++ b/compiler-rt/test/profile/Posix/gcov-dlopen.c @@ -64,14 +64,19 @@ func3(); #endif - void (*gcov_flush1)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); - if (gcov_flush1 == NULL) - return fprintf(stderr, "unable to find __gcov_flush in func1.so': %s\n", dlerror()); - void (*gcov_flush2)() = (void (*)())dlsym(f2_handle, "__gcov_flush"); - if (gcov_flush2 == NULL) - return fprintf(stderr, "unable to find __gcov_flush in func2.so': %s\n", dlerror()); - if (gcov_flush1 == gcov_flush2) - return fprintf(stderr, "same __gcov_flush found in func1.so and func2.so\n"); + void (*gcov_reset1)() = (void (*)())dlsym(f1_handle, "__gcov_reset"); + if (gcov_reset1 == NULL) + return fprintf(stderr, "unable to find __gcov_reset in func1.so': %s\n", dlerror()); + void (*gcov_reset2)() = (void (*)())dlsym(f2_handle, "__gcov_reset"); + if (gcov_reset2 == NULL) + return fprintf(stderr, "unable to find __gcov_reset in func2.so': %s\n", dlerror()); + if (gcov_reset1 == gcov_reset2) + return fprintf(stderr, "same __gcov_reset found in func1.so and func2.so\n"); + + /// Test that __gcov_dump is in the dynamic symbol table. + void (*gcov_dump1)() = (void (*)())dlsym(f1_handle, "__gcov_dump"); + if (gcov_dump1 == NULL) + return fprintf(stderr, "unable to find __gcov_dump in func1.so': %s\n", dlerror()); if (dlclose(f2_handle) != 0) return fprintf(stderr, "unable to close 'func2.so': %s\n", dlerror()); diff --git a/compiler-rt/test/profile/Posix/gcov-shared-flush.c b/compiler-rt/test/profile/Posix/gcov-shared-flush.c --- a/compiler-rt/test/profile/Posix/gcov-shared-flush.c +++ b/compiler-rt/test/profile/Posix/gcov-shared-flush.c @@ -7,7 +7,7 @@ // RUN: %clang --coverage -fPIC -shared shared.c -o libfunc.so // RUN: test -f shared.gcno -/// Test the case where we exit abruptly after calling __gcov_flush, which means we don't write out the counters at exit. +/// Test the case where we exit abruptly after calling __gcov_dump, which means we don't write out the counters at exit. // RUN: %clang -DEXIT_ABRUPTLY -DSHARED_CALL_BEFORE_FLUSH -DSHARED_CALL_AFTER_FLUSH --coverage %s -L%t.d -rpath %t.d -lfunc -o %t // RUN: test -f gcov-shared-flush.gcno @@ -21,7 +21,7 @@ // SHARED: 1: {{[[0-9]+}}:void foo(int n) -/// Test the case where we exit normally and we have a call to the shared library function before __gcov_flush. +/// Test the case where we exit normally and we have a call to the shared library function before __gcov_dump. // RUN: %clang -DSHARED_CALL_BEFORE_FLUSH --coverage %s -L%t.d -rpath %t.d -lfunc -o %t // RUN: test -f gcov-shared-flush.gcno @@ -32,14 +32,15 @@ // BEFORE: -: {{[0-9]+}}:#ifdef SHARED_CALL_BEFORE_FLUSH // BEFORE-NEXT: 1: {{[0-9]+}}: foo(1); -// BEFORE: 1: {{[0-9]+}}: __gcov_flush(); +// BEFORE: 1: {{[0-9]+}}: __gcov_dump(); +// BEFORE-NEXT: 1: {{[0-9]+}}: __gcov_reset(); // BEFORE: -: {{[0-9]+}}:#ifdef SHARED_CALL_AFTER_FLUSH // BEFORE-NEXT: -: {{[0-9]+}}: foo(1); // BEFORE: 1: {{[0-9]+}}: bar(5); // SHARED_ONCE: 1: {{[0-9]+}}:void foo(int n) -// # Test the case where we exit normally and we have a call to the shared library function after __gcov_flush. +// # Test the case where we exit normally and we have a call to the shared library function after __gcov_dump. // RUN: %clang -DSHARED_CALL_AFTER_FLUSH --coverage %s -L%t.d -rpath %t.d -lfunc -o %t // RUN: test -f gcov-shared-flush.gcno @@ -50,12 +51,13 @@ // AFTER: -: {{[0-9]+}}:#ifdef SHARED_CALL_BEFORE_FLUSH // AFTER-NEXT: -: {{[0-9]+}}: foo(1); -// AFTER: 1: {{[0-9]+}}: __gcov_flush(); +// AFTER: 1: {{[0-9]+}}: __gcov_dump(); +// AFTER-NEXT: 1: {{[0-9]+}}: __gcov_reset(); // AFTER: -: {{[0-9]+}}:#ifdef SHARED_CALL_AFTER_FLUSH // AFTER-NEXT: 1: {{[0-9]+}}: foo(1); // AFTER: 1: {{[0-9]+}}: bar(5); -// # Test the case where we exit normally and we have calls to the shared library function before and after __gcov_flush. +// # Test the case where we exit normally and we have calls to the shared library function before and after __gcov_dump. // RUN: %clang -DSHARED_CALL_BEFORE_FLUSH -DSHARED_CALL_AFTER_FLUSH --coverage %s -L%t.d -rpath %t.d -lfunc -o %t // RUN: test -f gcov-shared-flush.gcno @@ -66,7 +68,8 @@ // BEFORE_AFTER: -: {{[0-9]+}}:#ifdef SHARED_CALL_BEFORE_FLUSH // BEFORE_AFTER-NEXT: 1: {{[0-9]+}}: foo(1); -// BEFORE_AFTER: 1: {{[0-9]+}}: __gcov_flush(); +// BEFORE_AFTER: 1: {{[0-9]+}}: __gcov_dump(); +// BEFORE_AFTER-NEXT: 1: {{[0-9]+}}: __gcov_reset(); // BEFORE_AFTER: -: {{[0-9]+}}:#ifdef SHARED_CALL_AFTER_FLUSH // BEFORE_AFTER-NEXT: 1: {{[0-9]+}}: foo(1); // BEFORE_AFTER: 1: {{[0-9]+}}: bar(5); @@ -78,7 +81,8 @@ } #else extern void foo(int n); -extern void __gcov_flush(void); +extern void __gcov_dump(void); +extern void __gcov_reset(void); int bar1 = 0; int bar2 = 1; @@ -96,7 +100,8 @@ #endif bar(5); - __gcov_flush(); + __gcov_dump(); + __gcov_reset(); bar(5); #ifdef SHARED_CALL_AFTER_FLUSH diff --git a/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c b/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c --- a/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c +++ b/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c @@ -10,11 +10,13 @@ // CHECK: -: 0:Runs:1 // CHECK-NEXT: -: 0:Programs:1 -void __gcov_flush(void); +void __gcov_dump(void); +void __gcov_reset(void); int main(void) { // CHECK: 1: [[#@LINE]]:int main(void) int i = 22; // CHECK-NEXT: 1: [[#@LINE]]: - __gcov_flush(); // CHECK-NEXT: 1: [[#@LINE]]: + __gcov_dump(); // CHECK-NEXT: 1: [[#@LINE]]: + __gcov_reset(); // CHECK-NEXT: 1: [[#@LINE]]: i = 42; // CHECK-NEXT: 1: [[#@LINE]]: __builtin_trap(); // CHECK-NEXT: 1: [[#@LINE]]: i = 84; // CHECK-NEXT: 1: [[#@LINE]]: diff --git a/compiler-rt/test/profile/gcov-dump-and-remove.c b/compiler-rt/test/profile/gcov-dump-and-remove.c --- a/compiler-rt/test/profile/gcov-dump-and-remove.c +++ b/compiler-rt/test/profile/gcov-dump-and-remove.c @@ -8,16 +8,19 @@ // RUN: rm -f gcov-dump-and-remove.gcda && %run %t // RUN: llvm-cov gcov -t gcov-dump-and-remove.gcda | FileCheck %s -extern void __gcov_flush(void); +extern void __gcov_dump(void); +extern void __gcov_reset(void); extern int remove(const char *); // CHECK: -: [[#@LINE]]:extern int remove int main(void) { // CHECK-NEXT: #####: [[#@LINE]]: - __gcov_flush(); // CHECK-NEXT: #####: [[#@LINE]]: + __gcov_dump(); // CHECK-NEXT: #####: [[#@LINE]]: + __gcov_reset(); // CHECK-NEXT: #####: [[#@LINE]]: if (remove("gcov-dump-and-remove.gcda") != 0) // CHECK-NEXT: #####: [[#@LINE]]: return 1; // CHECK-NEXT: #####: [[#@LINE]]: return 1; // CHECK-NEXT: -: [[#@LINE]]: - __gcov_flush(); // CHECK-NEXT: #####: [[#@LINE]]: - __gcov_flush(); // CHECK-NEXT: #####: [[#@LINE]]: - if (remove("gcov-dump-and-remove.gcda") != 0) // CHECK-NEXT: #####: [[#@LINE]]: + __gcov_dump(); // CHECK-NEXT: 1: [[#@LINE]]: + __gcov_reset(); // CHECK-NEXT: 1: [[#@LINE]]: + __gcov_dump(); // CHECK-NEXT: 1: [[#@LINE]]: + if (remove("gcov-dump-and-remove.gcda") != 0) // CHECK-NEXT: 1: [[#@LINE]]: return 1; // CHECK-NEXT: #####: [[#@LINE]]: return 1; return 0; diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -130,7 +130,6 @@ Function * insertCounterWriteout(ArrayRef>); Function *insertReset(ArrayRef>); - Function *insertFlush(Function *ResetF); bool AddFlushBeforeForkAndExec(); @@ -909,7 +908,6 @@ Function *WriteoutF = insertCounterWriteout(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 @@ -927,14 +925,13 @@ IRBuilder<> Builder(BB); FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Type *Params[] = {PointerType::get(FTy, 0), PointerType::get(FTy, 0), - PointerType::get(FTy, 0)}; - FTy = FunctionType::get(Builder.getVoidTy(), Params, false); + auto *PFTy = PointerType::get(FTy, 0); + FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); // Initialize the environment and register the local writeout, flush and // reset functions. FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); - Builder.CreateCall(GCOVInit, {WriteoutF, FlushF, ResetF}); + Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); Builder.CreateRetVoid(); appendToGlobalCtors(*M, F, 0); @@ -1266,36 +1263,3 @@ return ResetF; } - -Function *GCOVProfiler::insertFlush(Function *ResetF) { - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *FlushF = M->getFunction("__llvm_gcov_flush"); - if (!FlushF) - FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, - "__llvm_gcov_flush", M); - FlushF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - FlushF->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - FlushF->addFnAttr(Attribute::NoRedZone); - - BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); - - // Write out the current counters. - Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); - assert(WriteoutF && "Need to create the writeout function first!"); - - IRBuilder<> Builder(Entry); - Builder.CreateCall(WriteoutF, {}); - Builder.CreateCall(ResetF, {}); - - Type *RetTy = FlushF->getReturnType(); - if (RetTy->isVoidTy()) - Builder.CreateRetVoid(); - else if (RetTy->isIntegerTy()) - // Used if __llvm_gcov_flush was implicitly declared. - Builder.CreateRet(ConstantInt::get(RetTy, 0)); - else - report_fatal_error("invalid return type for __llvm_gcov_flush"); - - return FlushF; -}