GCC Middle and Back End API Reference
path-coverage.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic-core.h"
#include "memmodel.h"
#include "target.h"
#include "function.h"
#include "basic-block.h"
#include "tree.h"
#include "tree-cfg.h"
#include "tree-nested.h"
#include "cfg.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "gimplify.h"
#include "coverage.h"
#include "ssa.h"
#include "vec.h"
#include "sbitmap.h"
#include "graphds.h"
#include "hash-map.h"
#include "bitmap.h"
#include "cfganal.h"
Include dependency graph for path-coverage.cc:

Functions

bool mark_dfs_back_edges (struct function *)
 
vec< vec< int > > prime_paths (struct graph *, size_t)
 
unsigned instrument_prime_paths (struct function *fn)
 

Function Documentation

◆ instrument_prime_paths()

unsigned instrument_prime_paths ( struct function * fn)
Instrument FN for prime path coverage, enabled by -fpath-coverage. The number of paths grows very fast with the complexity (control flow) which explodes compile times and object file size. Giving up is controlled by the -fpath-coverage-limit flag. The paths are sorted lexicographically by basic block id, and each path is identified by its index in the sorted set of paths, which in turn corresponds to a bit in a large bitset associated with FN. The monitoring code is a few bitwise operations added to edges and basic blocks to maintain a set of live paths (note that many paths may overlap and that many paths may be covered by the same input). When reaching the final vertex of a path the global counters are updated. This is made more complicated by the gcov type having very limited size. To support functions with more than 32/64 paths the bitmap is implemented on top of a sequence of gcov integers, "buckets", where path N is recorded as bit N%64 in bucket N/64. For large functions, an individual basic block will only be part of a small subset of paths, and by extension buckets and local counters. Only the necessary counters are read and written.

References add_phi_arg(), BASIC_BLOCK_FOR_FN, bb_has_abnormal_pred(), build_all_ones_cst(), build_int_cst(), builtin_decl_explicit(), coverage_counter_alloc(), create_phi_node(), find_prime_paths(), function::function_start_locus, gcc_assert, gcc_checking_assert, gcov_type_node, hash_map< KeyId, Value, Traits >::get(), get_gcov_type(), hash_map< KeyId, Value, Traits >::get_or_insert(), gimple_build_assign(), gsi_after_labels(), gsi_insert_on_edge(), i, last, make_ssa_name(), mark_dfs_back_edges(), path, basic_block_def::preds, PROFILE_UPDATE_ATOMIC, hash_map< KeyId, Value, Traits >::put(), release_vec_vec(), single_pred(), single_pred_p(), single_succ_p(), todo, tree_to_uhwi(), TYPE_PRECISION, UNKNOWN_LOCATION, and warning_at().

Referenced by branch_prob().

◆ mark_dfs_back_edges()

bool mark_dfs_back_edges ( struct function * fun)
Calculate prime path coverage. Copyright (C) 2024-2025 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>.
Mark the back edges in DFS traversal. Return nonzero if a loop (natural or otherwise) is present. Inspired by Depth_First_Search_PP described in: Advanced Compiler Design and Implementation Steven Muchnick Morgan Kaufmann, 1997 and heavily borrowed from pre_and_rev_post_order_compute.

References bitmap_bit_p, bitmap_clear(), bitmap_set_bit, EDGE_COUNT, ei_edge(), ei_next(), ei_one_before_end_p(), ei_start, ENTRY_BLOCK_PTR_FOR_FN, EXIT_BLOCK_PTR_FOR_FN, basic_block_def::flags, free(), basic_block_def::index, last_basic_block_for_fn, n_basic_blocks_for_fn, basic_block_def::succs, and visited.

Referenced by execute_split_paths(), and finite_function_p().

◆ prime_paths()

vec< vec< int > > prime_paths ( struct graph * cfg,
size_t pathlimit )
Find the prime paths for CFG. The search gives up after approximate PATHLIMIT probable paths have been generated to address path explosions. The PATHLIMIT flag is typically controlled by -fpath-coverage-limit. This function is a part of -fpath-coverage and will also be called from gcov. The paths are returned in lexicographical order based on node (basic block) ID. If the path limit was exceeded, an empty vector is returned. A simple path is a path where all vertices are unique, except possibly the first and last. A prime path is a maximal-length simple path which is not a part of any other simple path. Prime paths strike a good balance between coverage thoroughness, loops (requiring them to be taken and skipped), and number of paths. The algorithm is based on Fazli & Afsharchi's "A Time and Space-Efficient Compositional Method for Prime and Test Paths Generation" (2019), combined with a suffix trie for removing duplicate or redundant paths. An auxillary graph of the strongly connected components (SCCs) is built. Then, the prime paths of the SCCs composes the prime paths of each SCC with the prime paths of this auxillary graph. This can drastically cut the number of redundant paths generated compared to a naive algorithm. This does not work for all graphs. Some structures, e.g. when most of the graph is inside a single SCC, cause the algorithm to degenerate to a naive one. The same happens for functions with many SCCs that are either singletons or very small. Those cases will be slower with respect to the number of paths, but still fast enough if the path limit is kept reasonably low (a few hundred thousand).

References vertex::component, graphds_scc(), i, graph::n_vertices, NULL, and graph::vertices.

Referenced by find_prime_paths().