/* Gcov.c: prepend line execution counts and branch probabilities to a
source file.
- Copyright (C) 1990-2019 Free Software Foundation, Inc.
+ Copyright (C) 1990-2020 Free Software Foundation, Inc.
Contributed by James E. Wilson of Cygnus Support.
Mangled by Bob Manson of Cygnus Support.
Mangled further by Nathan Sidwell <nathan@codesourcery.com>
/* This is the size of the buffer used to read in source file lines. */
-struct function_info;
-struct block_info;
-struct source_info;
+class function_info;
+class block_info;
+class source_info;
/* Describes an arc between two basic blocks. */
struct arc_info
{
/* source and destination blocks. */
- struct block_info *src;
- struct block_info *dst;
+ class block_info *src;
+ class block_info *dst;
/* transition counts. */
gcov_type count;
/* Describes which locations (lines and files) are associated with
a basic block. */
-struct block_location_info
+class block_location_info
{
+public:
block_location_info (unsigned _source_file_idx):
source_file_idx (_source_file_idx)
{}
/* Describes a basic block. Contains lists of arcs to successor and
predecessor blocks. */
-struct block_info
+class block_info
{
+public:
/* Constructor. */
block_info ();
/* Temporary chain for solving graph, and for chaining blocks on one
line. */
- struct block_info *chain;
+ class block_info *chain;
};
/* Describes a single line of source. Contains a chain of basic blocks
with code on it. */
-struct line_info
+class line_info
{
+public:
/* Default constructor. */
line_info ();
/* Describes a single function. Contains an array of basic blocks. */
-struct function_info
+class function_info
{
+public:
function_info ();
~function_info ();
vector<line_info> lines;
/* Next function. */
- struct function_info *next;
+ class function_info *next;
/* Get demangled name of a function. The demangled name
is converted when it is used for the first time. */
/* Describes a file mentioned in the block graph. Contains an array
of line info. */
-struct source_info
+class source_info
{
+public:
/* Default constructor. */
source_info ();
typedef vector<arc_info *> arc_vector_t;
typedef vector<const block_info *> block_vector_t;
-/* Enum with types of loop in CFG. */
-
-enum loop_type
-{
- NO_LOOP = 0,
- LOOP = 1,
- NEGATIVE_LOOP = 3
-};
-
-/* Loop_type operator that merges two values: A and B. */
-
-inline loop_type& operator |= (loop_type& a, loop_type b)
-{
- return a = static_cast<loop_type> (a | b);
-}
-
/* Handle cycle identified by EDGES, where the function finds minimum cs_count
and subtract the value from all counts. The subtracted value is added
to COUNT. Returns type of loop. */
-static loop_type
+static void
handle_cycle (const arc_vector_t &edges, int64_t &count)
{
/* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
for (unsigned i = 0; i < edges.size (); i++)
edges[i]->cs_count -= cycle_count;
- return cycle_count < 0 ? NEGATIVE_LOOP : LOOP;
+ gcc_assert (cycle_count > 0);
}
/* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
unblock (*it, blocked, block_lists);
}
+/* Return true when PATH contains a zero cycle arc count. */
+
+static bool
+path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
+{
+ for (unsigned i = 0; i < path.size (); i++)
+ if (path[i]->cs_count <= 0)
+ return true;
+ return false;
+}
+
/* Find circuit going to block V, PATH is provisional seen cycle.
BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
blocked by a block. COUNT is accumulated count of the current LINE.
Returns what type of loop it contains. */
-static loop_type
+static bool
circuit (block_info *v, arc_vector_t &path, block_info *start,
block_vector_t &blocked, vector<block_vector_t> &block_lists,
line_info &linfo, int64_t &count)
{
- loop_type result = NO_LOOP;
+ bool loop_found = false;
/* Add v to the block list. */
gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
{
block_info *w = arc->dst;
- if (w < start || !linfo.has_block (w))
+ if (w < start
+ || arc->cs_count <= 0
+ || !linfo.has_block (w))
continue;
path.push_back (arc);
if (w == start)
- /* Cycle has been found. */
- result |= handle_cycle (path, count);
- else if (find (blocked.begin (), blocked.end (), w) == blocked.end ())
- result |= circuit (w, path, start, blocked, block_lists, linfo, count);
+ {
+ /* Cycle has been found. */
+ handle_cycle (path, count);
+ loop_found = true;
+ }
+ else if (!path_contains_zero_or_negative_cycle_arc (path)
+ && find (blocked.begin (), blocked.end (), w) == blocked.end ())
+ loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
+ count);
path.pop_back ();
}
- if (result != NO_LOOP)
+ if (loop_found)
unblock (v, blocked, block_lists);
else
for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
{
block_info *w = arc->dst;
- if (w < start || !linfo.has_block (w))
+ if (w < start
+ || arc->cs_count <= 0
+ || !linfo.has_block (w))
continue;
size_t index
list.push_back (v);
}
- return result;
+ return loop_found;
}
-/* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
- contains a negative loop, then perform the same function once again. */
+/* Find cycles for a LINFO. */
static gcov_type
-get_cycles_count (line_info &linfo, bool handle_negative_cycles = true)
+get_cycles_count (line_info &linfo)
{
/* Note that this algorithm works even if blocks aren't in sorted order.
Each iteration of the circuit detection is completely independent
Therefore, operating on a permuted order (i.e., non-sorted) only
has the effect of permuting the output cycles. */
- loop_type result = NO_LOOP;
+ bool loop_found = false;
gcov_type count = 0;
for (vector<block_info *>::iterator it = linfo.blocks.begin ();
it != linfo.blocks.end (); it++)
arc_vector_t path;
block_vector_t blocked;
vector<block_vector_t > block_lists;
- result |= circuit (*it, path, *it, blocked, block_lists, linfo,
- count);
+ loop_found |= circuit (*it, path, *it, blocked, block_lists, linfo,
+ count);
}
- /* If we have a negative cycle, repeat the find_cycles routine. */
- if (result == NEGATIVE_LOOP && handle_negative_cycles)
- count += get_cycles_count (linfo, false);
-
return count;
}
print_version (void)
{
fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
- fprintf (stdout, "Copyright %s 2019 Free Software Foundation, Inc.\n",
+ fprintf (stdout, "Copyright %s 2020 Free Software Foundation, Inc.\n",
_("(C)"));
fnotice (stdout,
_("This is free software; see the source for copying conditions.\n"
return;
json::object *lineo = new json::object ();
- lineo->set ("line_number", new json::number (line_num));
+ lineo->set ("line_number", new json::integer_number (line_num));
if (function_name != NULL)
lineo->set ("function_name", new json::string (function_name));
- lineo->set ("count", new json::number (line->count));
+ lineo->set ("count", new json::integer_number (line->count));
lineo->set ("unexecuted_block",
new json::literal (line->has_unexecuted_block));
if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
{
json::object *branch = new json::object ();
- branch->set ("count", new json::number ((*it)->count));
+ branch->set ("count", new json::integer_number ((*it)->count));
branch->set ("throw", new json::literal ((*it)->is_throw));
branch->set ("fallthrough",
new json::literal ((*it)->fall_through));
function->set ("name", new json::string ((*it)->m_name));
function->set ("demangled_name",
new json::string ((*it)->get_demangled_name ()));
- function->set ("start_line", new json::number ((*it)->start_line));
- function->set ("start_column", new json::number ((*it)->start_column));
- function->set ("end_line", new json::number ((*it)->end_line));
- function->set ("end_column", new json::number ((*it)->end_column));
+ function->set ("start_line",
+ new json::integer_number ((*it)->start_line));
+ function->set ("start_column",
+ new json::integer_number ((*it)->start_column));
+ function->set ("end_line", new json::integer_number ((*it)->end_line));
+ function->set ("end_column",
+ new json::integer_number ((*it)->end_column));
function->set ("blocks",
- new json::number ((*it)->get_block_count ()));
+ new json::integer_number ((*it)->get_block_count ()));
function->set ("blocks_executed",
- new json::number ((*it)->blocks_executed));
+ new json::integer_number ((*it)->blocks_executed));
function->set ("execution_count",
- new json::number ((*it)->blocks[0].count));
+ new json::integer_number ((*it)->blocks[0].count));
functions->append (function);
}
if (bbg_cwd != NULL)
root->set ("current_working_directory", new json::string (bbg_cwd));
+ root->set ("data_file", new json::string (file_name));
json::array *json_files = new json::array ();
root->set ("files", json_files);