Add some GCOV functions that register all of the __llvm_gcov_flush() functions.

The __llvm_gcov_flush() functions only work for the local compile unit. However,
when __gcov_flush() is called, the user expects all of the counters to be
flushed, not just the ones in the current compile unit.

This adds some library functions that register the flush functions. It also
defined __gcov_flush() so that loops through that list and calls the functions.

PR15191 & <rdar://problem/13167507>

llvm-svn: 177337
This commit is contained in:
Bill Wendling 2013-03-18 22:59:47 +00:00
parent c00f43a33f
commit 2428f167f7
1 changed files with 48 additions and 0 deletions

View File

@ -42,8 +42,24 @@ typedef unsigned int uint64_t;
* --- GCOV file format I/O primitives ---
*/
/*
* The current file we're outputting.
*/
static FILE *output_file = NULL;
/*
* A list of flush functions that our __gcov_flush() function should call.
*/
typedef void (*flush_fn)();
struct flush_fn_node {
flush_fn fn;
struct flush_fn_node *next;
};
struct flush_fn_node *flush_fn_head = NULL;
struct flush_fn_node *flush_fn_tail = NULL;
static void write_int32(uint32_t i) {
fwrite(&i, 4, 1, output_file);
}
@ -288,3 +304,35 @@ void llvm_gcda_end_file() {
fprintf(stderr, "llvmgcda: -----\n");
#endif
}
void llvm_register_flush_function(flush_fn fn) {
struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node));
new_node->fn = fn;
new_node->next = NULL;
if (!flush_fn_head) {
flush_fn_head = flush_fn_tail = new_node;
} else {
flush_fn_tail->next = new_node;
flush_fn_tail = new_node;
}
}
void __gcov_flush() {
struct flush_fn_node *curr = flush_fn_head;
while (curr) {
curr->fn();
curr = curr->next;
}
}
void llvm_delete_flush_function_list() {
while (flush_fn_head) {
struct flush_fn_node *node = flush_fn_head;
flush_fn_head = flush_fn_head->next;
free(node);
}
flush_fn_head = flush_fn_tail = NULL;
}