From b244fe9cb967819548ad7dee6f797cb6a831df08 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 25 Mar 2026 13:46:51 -0400 Subject: [PATCH 27/98] analyzer: split out exploded_path into its own files No functional change intended. gcc/ChangeLog: * Makefile.in (ANALYZER_OBJS): Add analyzer/exploded-path.o. gcc/analyzer/ChangeLog: * diagnostic-manager.cc: Include "analyzer/exploded-path.h". * engine.cc: Likewise. (exploded_path::exploded_path): Move to exploded-path.cc. (exploded_path::find_stmt_backwards): Likewise. (exploded_path::get_final_enode): Likewise. (exploded_path::feasible_p): Likewise. (exploded_path::dump_to_pp): Likewise. (exploded_path::dump): Likewise. (exploded_path::dump_to_file): Likewise. * exploded-graph.h (class exploded_path): Move to exploded-path.h. (shortest_exploded_paths): Likewise. * exploded-path.cc: New file, taken from the above. * exploded-path.h: Likewise. * feasible-graph.cc: Include "analyzer/exploded-path.h". Signed-off-by: David Malcolm --- gcc/Makefile.in | 1 + gcc/analyzer/diagnostic-manager.cc | 1 + gcc/analyzer/engine.cc | 163 +----------------------- gcc/analyzer/exploded-graph.h | 32 ----- gcc/analyzer/exploded-path.cc | 193 +++++++++++++++++++++++++++++ gcc/analyzer/exploded-path.h | 62 +++++++++ gcc/analyzer/feasible-graph.cc | 1 + 7 files changed, 259 insertions(+), 194 deletions(-) create mode 100644 gcc/analyzer/exploded-path.cc create mode 100644 gcc/analyzer/exploded-path.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 8ff8dde2ab06..ea2d43ce87b5 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1353,6 +1353,7 @@ ANALYZER_OBJS = \ analyzer/constraint-manager.o \ analyzer/diagnostic-manager.o \ analyzer/engine.o \ + analyzer/exploded-path.o \ analyzer/feasible-graph.o \ analyzer/function-set.o \ analyzer/infinite-loop.o \ diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index d8a7f43331c6..a0f149e9c522 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" +#include "analyzer/exploded-path.h" #include "analyzer/trimmed-graph.h" #include "analyzer/feasible-graph.h" #include "analyzer/checker-path.h" diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 2a03a0b2e729..1a7022edd724 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" +#include "analyzer/exploded-path.h" #include "analyzer/analysis-plan.h" #include "analyzer/checker-path.h" #include "analyzer/state-purge.h" @@ -3676,168 +3677,6 @@ exploded_graph::to_json () const return egraph_obj; } -/* class exploded_path. */ - -/* Copy ctor. */ - -exploded_path::exploded_path (const exploded_path &other) -: m_edges (other.m_edges.length ()) -{ - int i; - const exploded_edge *eedge; - FOR_EACH_VEC_ELT (other.m_edges, i, eedge) - m_edges.quick_push (eedge); -} - -/* Look for the last use of SEARCH_STMT within this path. - If found write the edge's index to *OUT_IDX and return true, otherwise - return false. */ - -bool -exploded_path::find_stmt_backwards (const gimple *search_stmt, - int *out_idx) const -{ - int i; - const exploded_edge *eedge; - FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge) - if (search_stmt->code == GIMPLE_PHI) - { - /* Each phis_for_edge_op instance handles multiple phi stmts - at once, so we have to special-case the search for a phi stmt. */ - if (auto op = eedge->maybe_get_op ()) - if (auto phis_op = op->dyn_cast_phis_for_edge_op ()) - if (phis_op->defines_ssa_name_p (gimple_phi_result (search_stmt))) - { - *out_idx = i; - return true; - } - } - else - { - /* Non-phi stmt. */ - if (const gimple *stmt = eedge->maybe_get_stmt ()) - if (stmt == search_stmt) - { - *out_idx = i; - return true; - } - } - return false; -} - -/* Get the final exploded_node in this path, which must be non-empty. */ - -exploded_node * -exploded_path::get_final_enode () const -{ - gcc_assert (m_edges.length () > 0); - return m_edges[m_edges.length () - 1]->m_dest; -} - -/* Check state along this path, returning true if it is feasible. - If OUT is non-NULL, and the path is infeasible, write a new - feasibility_problem to *OUT. */ - -bool -exploded_path::feasible_p (logger *logger, - std::unique_ptr *out, - engine *eng, const exploded_graph *eg) const -{ - LOG_SCOPE (logger); - - feasibility_state state (eng->get_model_manager (), - eg->get_supergraph ()); - - /* Traverse the path, updating this state. */ - for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++) - { - const exploded_edge *eedge = m_edges[edge_idx]; - if (logger) - logger->log ("considering edge %i: EN:%i -> EN:%i", - edge_idx, - eedge->m_src->m_index, - eedge->m_dest->m_index); - - std::unique_ptr rc; - if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc)) - { - gcc_assert (rc); - if (out) - *out = std::make_unique (edge_idx, *eedge, - std::move (rc)); - return false; - } - - if (logger) - { - logger->log ("state after edge %i: EN:%i -> EN:%i", - edge_idx, - eedge->m_src->m_index, - eedge->m_dest->m_index); - logger->start_log_line (); - state.get_model ().dump_to_pp (logger->get_printer (), true, false); - logger->end_log_line (); - } - } - - return true; -} - -/* Dump this path in multiline form to PP. - If EXT_STATE is non-NULL, then show the nodes. */ - -void -exploded_path::dump_to_pp (pretty_printer *pp, - const extrinsic_state *ext_state) const -{ - for (unsigned i = 0; i < m_edges.length (); i++) - { - const exploded_edge *eedge = m_edges[i]; - pp_printf (pp, "m_edges[%i]: EN %i -> EN %i", - i, - eedge->m_src->m_index, - eedge->m_dest->m_index); - pp_newline (pp); - - if (ext_state) - eedge->m_dest->dump_to_pp (pp, *ext_state); - } -} - -/* Dump this path in multiline form to FP. */ - -void -exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const -{ - tree_dump_pretty_printer pp (fp); - dump_to_pp (&pp, ext_state); -} - -/* Dump this path in multiline form to stderr. */ - -DEBUG_FUNCTION void -exploded_path::dump (const extrinsic_state *ext_state) const -{ - dump (stderr, ext_state); -} - -/* Dump this path verbosely to FILENAME. */ - -void -exploded_path::dump_to_file (const char *filename, - const extrinsic_state &ext_state) const -{ - FILE *fp = fopen (filename, "w"); - if (!fp) - return; - pretty_printer pp; - pp_format_decoder (&pp) = default_tree_printer; - pp.set_output_stream (fp); - dump_to_pp (&pp, &ext_state); - pp_flush (&pp); - fclose (fp); -} - /* class feasibility_problem. */ void diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index c1ceb4a985ff..0972e217baf5 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -926,34 +926,6 @@ private: hash_set m_functions_with_enodes; }; -/* A path within an exploded_graph: a sequence of edges. */ - -class exploded_path -{ -public: - exploded_path () : m_edges () {} - exploded_path (const exploded_path &other); - - unsigned length () const { return m_edges.length (); } - - bool find_stmt_backwards (const gimple *search_stmt, - int *out_idx) const; - - exploded_node *get_final_enode () const; - - void dump_to_pp (pretty_printer *pp, - const extrinsic_state *ext_state) const; - void dump (FILE *fp, const extrinsic_state *ext_state) const; - void dump (const extrinsic_state *ext_state = nullptr) const; - void dump_to_file (const char *filename, - const extrinsic_state &ext_state) const; - - bool feasible_p (logger *logger, std::unique_ptr *out, - engine *eng, const exploded_graph *eg) const; - - auto_vec m_edges; -}; - /* A reason why a particular exploded_path is infeasible. */ class feasibility_problem @@ -1004,10 +976,6 @@ private: auto_sbitmap m_snodes_visited; }; -/* Finding the shortest exploded_path within an exploded_graph. */ - -typedef shortest_paths shortest_exploded_paths; - // TODO: split the above up? } // namespace ana diff --git a/gcc/analyzer/exploded-path.cc b/gcc/analyzer/exploded-path.cc new file mode 100644 index 000000000000..b10761a9388a --- /dev/null +++ b/gcc/analyzer/exploded-path.cc @@ -0,0 +1,193 @@ +/* Paths within an exploded_graph. + Copyright (C) 2019-2026 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#include "analyzer/common.h" + +#include "analyzer/exploded-path.h" + +#if ENABLE_ANALYZER + +namespace ana { + +/* class exploded_path. */ + +/* Copy ctor. */ + +exploded_path::exploded_path (const exploded_path &other) +: m_edges (other.m_edges.length ()) +{ + int i; + const exploded_edge *eedge; + FOR_EACH_VEC_ELT (other.m_edges, i, eedge) + m_edges.quick_push (eedge); +} + +/* Look for the last use of SEARCH_STMT within this path. + If found write the edge's index to *OUT_IDX and return true, otherwise + return false. */ + +bool +exploded_path::find_stmt_backwards (const gimple *search_stmt, + int *out_idx) const +{ + int i; + const exploded_edge *eedge; + FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge) + if (search_stmt->code == GIMPLE_PHI) + { + /* Each phis_for_edge_op instance handles multiple phi stmts + at once, so we have to special-case the search for a phi stmt. */ + if (auto op = eedge->maybe_get_op ()) + if (auto phis_op = op->dyn_cast_phis_for_edge_op ()) + if (phis_op->defines_ssa_name_p (gimple_phi_result (search_stmt))) + { + *out_idx = i; + return true; + } + } + else + { + /* Non-phi stmt. */ + if (const gimple *stmt = eedge->maybe_get_stmt ()) + if (stmt == search_stmt) + { + *out_idx = i; + return true; + } + } + return false; +} + +/* Get the final exploded_node in this path, which must be non-empty. */ + +exploded_node * +exploded_path::get_final_enode () const +{ + gcc_assert (m_edges.length () > 0); + return m_edges[m_edges.length () - 1]->m_dest; +} + +/* Check state along this path, returning true if it is feasible. + If OUT is non-NULL, and the path is infeasible, write a new + feasibility_problem to *OUT. */ + +bool +exploded_path::feasible_p (logger *logger, + std::unique_ptr *out, + engine *eng, const exploded_graph *eg) const +{ + LOG_SCOPE (logger); + + feasibility_state state (eng->get_model_manager (), + eg->get_supergraph ()); + + /* Traverse the path, updating this state. */ + for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++) + { + const exploded_edge *eedge = m_edges[edge_idx]; + if (logger) + logger->log ("considering edge %i: EN:%i -> EN:%i", + edge_idx, + eedge->m_src->m_index, + eedge->m_dest->m_index); + + std::unique_ptr rc; + if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc)) + { + gcc_assert (rc); + if (out) + *out = std::make_unique (edge_idx, *eedge, + std::move (rc)); + return false; + } + + if (logger) + { + logger->log ("state after edge %i: EN:%i -> EN:%i", + edge_idx, + eedge->m_src->m_index, + eedge->m_dest->m_index); + logger->start_log_line (); + state.get_model ().dump_to_pp (logger->get_printer (), true, false); + logger->end_log_line (); + } + } + + return true; +} + +/* Dump this path in multiline form to PP. + If EXT_STATE is non-NULL, then show the nodes. */ + +void +exploded_path::dump_to_pp (pretty_printer *pp, + const extrinsic_state *ext_state) const +{ + for (unsigned i = 0; i < m_edges.length (); i++) + { + const exploded_edge *eedge = m_edges[i]; + pp_printf (pp, "m_edges[%i]: EN %i -> EN %i", + i, + eedge->m_src->m_index, + eedge->m_dest->m_index); + pp_newline (pp); + + if (ext_state) + eedge->m_dest->dump_to_pp (pp, *ext_state); + } +} + +/* Dump this path in multiline form to FP. */ + +void +exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const +{ + tree_dump_pretty_printer pp (fp); + dump_to_pp (&pp, ext_state); +} + +/* Dump this path in multiline form to stderr. */ + +DEBUG_FUNCTION void +exploded_path::dump (const extrinsic_state *ext_state) const +{ + dump (stderr, ext_state); +} + +/* Dump this path verbosely to FILENAME. */ + +void +exploded_path::dump_to_file (const char *filename, + const extrinsic_state &ext_state) const +{ + FILE *fp = fopen (filename, "w"); + if (!fp) + return; + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp.set_output_stream (fp); + dump_to_pp (&pp, &ext_state); + pp_flush (&pp); + fclose (fp); +} + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/exploded-path.h b/gcc/analyzer/exploded-path.h new file mode 100644 index 000000000000..8c5ce9766a1b --- /dev/null +++ b/gcc/analyzer/exploded-path.h @@ -0,0 +1,62 @@ +/* Paths within an exploded_graph. + Copyright (C) 2019-2026 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#ifndef GCC_ANALYZER_EXPLODED_PATH_H +#define GCC_ANALYZER_EXPLODED_PATH_H + +#include "analyzer/exploded-graph.h" + +namespace ana { + +/* A path within an exploded_graph: a sequence of edges. */ + +class exploded_path +{ +public: + exploded_path () : m_edges () {} + exploded_path (const exploded_path &other); + + unsigned length () const { return m_edges.length (); } + + bool find_stmt_backwards (const gimple *search_stmt, + int *out_idx) const; + + exploded_node *get_final_enode () const; + + void dump_to_pp (pretty_printer *pp, + const extrinsic_state *ext_state) const; + void dump (FILE *fp, const extrinsic_state *ext_state) const; + void dump (const extrinsic_state *ext_state = nullptr) const; + void dump_to_file (const char *filename, + const extrinsic_state &ext_state) const; + + bool feasible_p (logger *logger, std::unique_ptr *out, + engine *eng, const exploded_graph *eg) const; + + auto_vec m_edges; +}; + +/* Finding the shortest exploded_path within an exploded_graph. */ + +typedef shortest_paths shortest_exploded_paths; + +} // namespace ana + +#endif /* GCC_ANALYZER_EXPLODED_PATH_H */ diff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc index b40fba0c5741..b3097f189a1b 100644 --- a/gcc/analyzer/feasible-graph.cc +++ b/gcc/analyzer/feasible-graph.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" +#include "analyzer/exploded-path.h" #include "analyzer/feasible-graph.h" #if ENABLE_ANALYZER -- 2.49.0