{"id":2229953,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2229953/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260428232820.1954013-1-dmalcolm@redhat.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20260428232820.1954013-1-dmalcolm@redhat.com>","date":"2026-04-28T23:28:20","name":"[pushed:,r17-185] analyzer: split out exploded_path into its own files","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"ec30cf53eb5ec3f966d99d879c2c2a8c3e4c6566","submitter":{"id":24465,"url":"http://patchwork.ozlabs.org/api/1.1/people/24465/?format=json","name":"David Malcolm","email":"dmalcolm@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260428232820.1954013-1-dmalcolm@redhat.com/mbox/","series":[{"id":501962,"url":"http://patchwork.ozlabs.org/api/1.1/series/501962/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=501962","date":"2026-04-28T23:28:20","name":"[pushed:,r17-185] analyzer: split out exploded_path into its own files","version":1,"mbox":"http://patchwork.ozlabs.org/series/501962/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2229953/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2229953/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=azl95pV2;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=azl95pV2","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4xYP1nbZz1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 09:32:25 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 4151B4BA23C1\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:32:23 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id F09274BB8F6A\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:24 +0000 (GMT)","from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-156-bh1JJmS_PT2thLOxGskyPA-1; Tue,\n 28 Apr 2026 19:28:23 -0400","from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 421E51800352\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:22 +0000 (UTC)","from t14s.localdomain.com (unknown [10.22.65.168])\n by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id B9CC3180047F; Tue, 28 Apr 2026 23:28:21 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 4151B4BA23C1","OpenDKIM Filter v2.11.0 sourceware.org F09274BB8F6A"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org F09274BB8F6A","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org F09274BB8F6A","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777418905; cv=none;\n b=RJ0Gv1xj3Y8Jm2cRjuvetCkiNII6WL68/Rh2xIKRJkHgmp3E/1BZIdyO5lQQzjYxV6GMrvXDIRSqQwyvS6G+u39yyptB/QsXGcxWzpWtP2/mBGQIsxIJEr/Hk5+uKOnRXVu6pm/+fD2eVJcID/C4gb7me0uBPRJAkuB/HR5Lzxg=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777418905; c=relaxed/simple;\n bh=s0osUKHthbK6YxabFzWJuAPRQuYCOLSwED3M9Q8QyeU=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=kF/3yFjIzEkUhrsKvB3TTkoUod411l4yeol3S0CHY1tkALqNXbbo1Nqs3KhIVTi7rtZ9IoMOvPIAWp5VSNO/ekKzXDf1UOLPmo5weOgO+WLKWOUQLm0e7ZTw7t1YFcrfp2F0L5uhZXnnNuIAuu9mRBwKDf8WVDnYeFIKx8ExotQ=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777418904;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=IMiWk+2NmFKUa1ZLrcqzCRrcugDoukxpT/T9Hw1Pr8A=;\n b=azl95pV2fjgozuWTa9lqMeVtkOa9zKD5dLqFQLyuBW+ecoySsqVuD2zyZRrvXGaKkVBr16\n a0lTE3dQqE1U49kU2JXXcL0wmrv3aF8zNGTyHnmhHm9XdzOiU3IZy/M8QycrPSBctYA5xW\n q4Q90jjzuKPv84oSWTR0EUECLAwELa8=","X-MC-Unique":"bh1JJmS_PT2thLOxGskyPA-1","X-Mimecast-MFC-AGG-ID":"bh1JJmS_PT2thLOxGskyPA_1777418902","From":"David Malcolm <dmalcolm@redhat.com>","To":"gcc-patches@gcc.gnu.org","Cc":"David Malcolm <dmalcolm@redhat.com>","Subject":"[pushed: r17-185] analyzer: split out exploded_path into its own\n files","Date":"Tue, 28 Apr 2026 19:28:20 -0400","Message-ID":"<20260428232820.1954013-1-dmalcolm@redhat.com>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 3.4.1 on 10.30.177.111","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"D4jr24kFn9aKp7XlSwWFcBN-xLqm5L5SujAYIGfU7f8_1777418902","X-Mimecast-Originator":"redhat.com","Content-Transfer-Encoding":"8bit","content-type":"text/plain; charset=\"US-ASCII\"; x-default=true","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"No functional change intended.\n\nSuccessfully bootstrapped & regrtested on powerpc64le-unknown-linux-gnu\n(albeit without ada,cobol,d, and possibly missing some optional test dependencies)\nPushed to trunk as r17-185-geb67d9885bdf46.\n\ngcc/ChangeLog:\n\t* Makefile.in (ANALYZER_OBJS): Add analyzer/exploded-path.o.\n\ngcc/analyzer/ChangeLog:\n\t* diagnostic-manager.cc: Include \"analyzer/exploded-path.h\".\n\t* engine.cc: Likewise.\n\t(exploded_path::exploded_path): Move to exploded-path.cc.\n\t(exploded_path::find_stmt_backwards): Likewise.\n\t(exploded_path::get_final_enode): Likewise.\n\t(exploded_path::feasible_p): Likewise.\n\t(exploded_path::dump_to_pp): Likewise.\n\t(exploded_path::dump): Likewise.\n\t(exploded_path::dump_to_file): Likewise.\n\t* exploded-graph.h (class exploded_path): Move to exploded-path.h.\n\t(shortest_exploded_paths): Likewise.\n\t* exploded-path.cc: New file, taken from the above.\n\t* exploded-path.h: Likewise.\n\t* feasible-graph.cc: Include \"analyzer/exploded-path.h\".\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/Makefile.in                    |   1 +\n gcc/analyzer/diagnostic-manager.cc |   1 +\n gcc/analyzer/engine.cc             | 163 +-----------------------\n gcc/analyzer/exploded-graph.h      |  32 -----\n gcc/analyzer/exploded-path.cc      | 193 +++++++++++++++++++++++++++++\n gcc/analyzer/exploded-path.h       |  62 +++++++++\n gcc/analyzer/feasible-graph.cc     |   1 +\n 7 files changed, 259 insertions(+), 194 deletions(-)\n create mode 100644 gcc/analyzer/exploded-path.cc\n create mode 100644 gcc/analyzer/exploded-path.h","diff":"diff --git a/gcc/Makefile.in b/gcc/Makefile.in\nindex c9888c38cef..0fd619140d2 100644\n--- a/gcc/Makefile.in\n+++ b/gcc/Makefile.in\n@@ -1353,6 +1353,7 @@ ANALYZER_OBJS = \\\n \tanalyzer/constraint-manager.o \\\n \tanalyzer/diagnostic-manager.o \\\n \tanalyzer/engine.o \\\n+\tanalyzer/exploded-path.o \\\n \tanalyzer/feasible-graph.o \\\n \tanalyzer/function-set.o \\\n \tanalyzer/infinite-loop.o \\\ndiff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc\nindex d8a7f43331c..a0f149e9c52 100644\n--- a/gcc/analyzer/diagnostic-manager.cc\n+++ b/gcc/analyzer/diagnostic-manager.cc\n@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see\n #include \"analyzer/supergraph.h\"\n #include \"analyzer/program-state.h\"\n #include \"analyzer/exploded-graph.h\"\n+#include \"analyzer/exploded-path.h\"\n #include \"analyzer/trimmed-graph.h\"\n #include \"analyzer/feasible-graph.h\"\n #include \"analyzer/checker-path.h\"\ndiff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc\nindex b506cdbe848..3e559b47a5d 100644\n--- a/gcc/analyzer/engine.cc\n+++ b/gcc/analyzer/engine.cc\n@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see\n #include \"analyzer/supergraph.h\"\n #include \"analyzer/program-state.h\"\n #include \"analyzer/exploded-graph.h\"\n+#include \"analyzer/exploded-path.h\"\n #include \"analyzer/analysis-plan.h\"\n #include \"analyzer/checker-path.h\"\n #include \"analyzer/state-purge.h\"\n@@ -3680,168 +3681,6 @@ exploded_graph::to_json () const\n   return egraph_obj;\n }\n \n-/* class exploded_path.  */\n-\n-/* Copy ctor.  */\n-\n-exploded_path::exploded_path (const exploded_path &other)\n-: m_edges (other.m_edges.length ())\n-{\n-  int i;\n-  const exploded_edge *eedge;\n-  FOR_EACH_VEC_ELT (other.m_edges, i, eedge)\n-    m_edges.quick_push (eedge);\n-}\n-\n-/* Look for the last use of SEARCH_STMT within this path.\n-   If found write the edge's index to *OUT_IDX and return true, otherwise\n-   return false.  */\n-\n-bool\n-exploded_path::find_stmt_backwards (const gimple *search_stmt,\n-\t\t\t\t    int *out_idx) const\n-{\n-  int i;\n-  const exploded_edge *eedge;\n-  FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge)\n-    if (search_stmt->code == GIMPLE_PHI)\n-      {\n-\t/* Each phis_for_edge_op instance handles multiple phi stmts\n-\t   at once, so we have to special-case the search for a phi stmt.  */\n-\tif (auto op = eedge->maybe_get_op ())\n-\t  if (auto phis_op = op->dyn_cast_phis_for_edge_op ())\n-\t    if (phis_op->defines_ssa_name_p (gimple_phi_result (search_stmt)))\n-\t      {\n-\t\t*out_idx = i;\n-\t\treturn true;\n-\t      }\n-      }\n-    else\n-      {\n-\t/* Non-phi stmt.  */\n-\tif (const gimple *stmt = eedge->maybe_get_stmt ())\n-\t  if (stmt == search_stmt)\n-\t    {\n-\t      *out_idx = i;\n-\t      return true;\n-\t    }\n-      }\n-  return false;\n-}\n-\n-/* Get the final exploded_node in this path, which must be non-empty.  */\n-\n-exploded_node *\n-exploded_path::get_final_enode () const\n-{\n-  gcc_assert (m_edges.length () > 0);\n-  return m_edges[m_edges.length () - 1]->m_dest;\n-}\n-\n-/* Check state along this path, returning true if it is feasible.\n-   If OUT is non-NULL, and the path is infeasible, write a new\n-   feasibility_problem to *OUT.  */\n-\n-bool\n-exploded_path::feasible_p (logger *logger,\n-\t\t\t   std::unique_ptr<feasibility_problem> *out,\n-\t\t\t   engine *eng, const exploded_graph *eg) const\n-{\n-  LOG_SCOPE (logger);\n-\n-  feasibility_state state (eng->get_model_manager (),\n-\t\t\t   eg->get_supergraph ());\n-\n-  /* Traverse the path, updating this state.  */\n-  for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)\n-    {\n-      const exploded_edge *eedge = m_edges[edge_idx];\n-      if (logger)\n-\tlogger->log (\"considering edge %i: EN:%i -> EN:%i\",\n-\t\t     edge_idx,\n-\t\t     eedge->m_src->m_index,\n-\t\t     eedge->m_dest->m_index);\n-\n-      std::unique_ptr <rejected_constraint> rc;\n-      if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc))\n-\t{\n-\t  gcc_assert (rc);\n-\t  if (out)\n-\t    *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,\n-\t\t\t\t\t\t\t  std::move (rc));\n-\t  return false;\n-\t}\n-\n-      if (logger)\n-\t{\n-\t  logger->log (\"state after edge %i: EN:%i -> EN:%i\",\n-\t\t       edge_idx,\n-\t\t       eedge->m_src->m_index,\n-\t\t       eedge->m_dest->m_index);\n-\t  logger->start_log_line ();\n-\t  state.get_model ().dump_to_pp (logger->get_printer (), true, false);\n-\t  logger->end_log_line ();\n-\t}\n-    }\n-\n-  return true;\n-}\n-\n-/* Dump this path in multiline form to PP.\n-   If EXT_STATE is non-NULL, then show the nodes.  */\n-\n-void\n-exploded_path::dump_to_pp (pretty_printer *pp,\n-\t\t\t   const extrinsic_state *ext_state) const\n-{\n-  for (unsigned i = 0; i < m_edges.length (); i++)\n-    {\n-      const exploded_edge *eedge = m_edges[i];\n-      pp_printf (pp, \"m_edges[%i]: EN %i -> EN %i\",\n-\t\t i,\n-\t\t eedge->m_src->m_index,\n-\t\t eedge->m_dest->m_index);\n-      pp_newline (pp);\n-\n-      if (ext_state)\n-\teedge->m_dest->dump_to_pp (pp, *ext_state);\n-    }\n-}\n-\n-/* Dump this path in multiline form to FP.  */\n-\n-void\n-exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const\n-{\n-  tree_dump_pretty_printer pp (fp);\n-  dump_to_pp (&pp, ext_state);\n-}\n-\n-/* Dump this path in multiline form to stderr.  */\n-\n-DEBUG_FUNCTION void\n-exploded_path::dump (const extrinsic_state *ext_state) const\n-{\n-  dump (stderr, ext_state);\n-}\n-\n-/* Dump this path verbosely to FILENAME.  */\n-\n-void\n-exploded_path::dump_to_file (const char *filename,\n-\t\t\t     const extrinsic_state &ext_state) const\n-{\n-  FILE *fp = fopen (filename, \"w\");\n-  if (!fp)\n-    return;\n-  pretty_printer pp;\n-  pp_format_decoder (&pp) = default_tree_printer;\n-  pp.set_output_stream (fp);\n-  dump_to_pp (&pp, &ext_state);\n-  pp_flush (&pp);\n-  fclose (fp);\n-}\n-\n /* class feasibility_problem.  */\n \n void\ndiff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h\nindex c1ceb4a985f..0972e217baf 100644\n--- a/gcc/analyzer/exploded-graph.h\n+++ b/gcc/analyzer/exploded-graph.h\n@@ -926,34 +926,6 @@ private:\n   hash_set<function *> m_functions_with_enodes;\n };\n \n-/* A path within an exploded_graph: a sequence of edges.  */\n-\n-class exploded_path\n-{\n-public:\n-  exploded_path () : m_edges () {}\n-  exploded_path (const exploded_path &other);\n-\n-  unsigned length () const { return m_edges.length (); }\n-\n-  bool find_stmt_backwards (const gimple *search_stmt,\n-\t\t\t    int *out_idx) const;\n-\n-  exploded_node *get_final_enode () const;\n-\n-  void dump_to_pp (pretty_printer *pp,\n-\t\t   const extrinsic_state *ext_state) const;\n-  void dump (FILE *fp, const extrinsic_state *ext_state) const;\n-  void dump (const extrinsic_state *ext_state = nullptr) const;\n-  void dump_to_file (const char *filename,\n-\t\t     const extrinsic_state &ext_state) const;\n-\n-  bool feasible_p (logger *logger, std::unique_ptr<feasibility_problem> *out,\n-\t\t    engine *eng, const exploded_graph *eg) const;\n-\n-  auto_vec<const exploded_edge *> m_edges;\n-};\n-\n /* A reason why a particular exploded_path is infeasible.  */\n \n class feasibility_problem\n@@ -1004,10 +976,6 @@ private:\n   auto_sbitmap m_snodes_visited;\n };\n \n-/* Finding the shortest exploded_path within an exploded_graph.  */\n-\n-typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;\n-\n // TODO: split the above up?\n \n } // namespace ana\ndiff --git a/gcc/analyzer/exploded-path.cc b/gcc/analyzer/exploded-path.cc\nnew file mode 100644\nindex 00000000000..b10761a9388\n--- /dev/null\n+++ b/gcc/analyzer/exploded-path.cc\n@@ -0,0 +1,193 @@\n+/* Paths within an exploded_graph.\n+   Copyright (C) 2019-2026 Free Software Foundation, Inc.\n+   Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it\n+under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful, but\n+WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3.  If not see\n+<http://www.gnu.org/licenses/>.  */\n+\n+#include \"analyzer/common.h\"\n+\n+#include \"analyzer/exploded-path.h\"\n+\n+#if ENABLE_ANALYZER\n+\n+namespace ana {\n+\n+/* class exploded_path.  */\n+\n+/* Copy ctor.  */\n+\n+exploded_path::exploded_path (const exploded_path &other)\n+: m_edges (other.m_edges.length ())\n+{\n+  int i;\n+  const exploded_edge *eedge;\n+  FOR_EACH_VEC_ELT (other.m_edges, i, eedge)\n+    m_edges.quick_push (eedge);\n+}\n+\n+/* Look for the last use of SEARCH_STMT within this path.\n+   If found write the edge's index to *OUT_IDX and return true, otherwise\n+   return false.  */\n+\n+bool\n+exploded_path::find_stmt_backwards (const gimple *search_stmt,\n+\t\t\t\t    int *out_idx) const\n+{\n+  int i;\n+  const exploded_edge *eedge;\n+  FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge)\n+    if (search_stmt->code == GIMPLE_PHI)\n+      {\n+\t/* Each phis_for_edge_op instance handles multiple phi stmts\n+\t   at once, so we have to special-case the search for a phi stmt.  */\n+\tif (auto op = eedge->maybe_get_op ())\n+\t  if (auto phis_op = op->dyn_cast_phis_for_edge_op ())\n+\t    if (phis_op->defines_ssa_name_p (gimple_phi_result (search_stmt)))\n+\t      {\n+\t\t*out_idx = i;\n+\t\treturn true;\n+\t      }\n+      }\n+    else\n+      {\n+\t/* Non-phi stmt.  */\n+\tif (const gimple *stmt = eedge->maybe_get_stmt ())\n+\t  if (stmt == search_stmt)\n+\t    {\n+\t      *out_idx = i;\n+\t      return true;\n+\t    }\n+      }\n+  return false;\n+}\n+\n+/* Get the final exploded_node in this path, which must be non-empty.  */\n+\n+exploded_node *\n+exploded_path::get_final_enode () const\n+{\n+  gcc_assert (m_edges.length () > 0);\n+  return m_edges[m_edges.length () - 1]->m_dest;\n+}\n+\n+/* Check state along this path, returning true if it is feasible.\n+   If OUT is non-NULL, and the path is infeasible, write a new\n+   feasibility_problem to *OUT.  */\n+\n+bool\n+exploded_path::feasible_p (logger *logger,\n+\t\t\t   std::unique_ptr<feasibility_problem> *out,\n+\t\t\t   engine *eng, const exploded_graph *eg) const\n+{\n+  LOG_SCOPE (logger);\n+\n+  feasibility_state state (eng->get_model_manager (),\n+\t\t\t   eg->get_supergraph ());\n+\n+  /* Traverse the path, updating this state.  */\n+  for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)\n+    {\n+      const exploded_edge *eedge = m_edges[edge_idx];\n+      if (logger)\n+\tlogger->log (\"considering edge %i: EN:%i -> EN:%i\",\n+\t\t     edge_idx,\n+\t\t     eedge->m_src->m_index,\n+\t\t     eedge->m_dest->m_index);\n+\n+      std::unique_ptr <rejected_constraint> rc;\n+      if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc))\n+\t{\n+\t  gcc_assert (rc);\n+\t  if (out)\n+\t    *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,\n+\t\t\t\t\t\t\t  std::move (rc));\n+\t  return false;\n+\t}\n+\n+      if (logger)\n+\t{\n+\t  logger->log (\"state after edge %i: EN:%i -> EN:%i\",\n+\t\t       edge_idx,\n+\t\t       eedge->m_src->m_index,\n+\t\t       eedge->m_dest->m_index);\n+\t  logger->start_log_line ();\n+\t  state.get_model ().dump_to_pp (logger->get_printer (), true, false);\n+\t  logger->end_log_line ();\n+\t}\n+    }\n+\n+  return true;\n+}\n+\n+/* Dump this path in multiline form to PP.\n+   If EXT_STATE is non-NULL, then show the nodes.  */\n+\n+void\n+exploded_path::dump_to_pp (pretty_printer *pp,\n+\t\t\t   const extrinsic_state *ext_state) const\n+{\n+  for (unsigned i = 0; i < m_edges.length (); i++)\n+    {\n+      const exploded_edge *eedge = m_edges[i];\n+      pp_printf (pp, \"m_edges[%i]: EN %i -> EN %i\",\n+\t\t i,\n+\t\t eedge->m_src->m_index,\n+\t\t eedge->m_dest->m_index);\n+      pp_newline (pp);\n+\n+      if (ext_state)\n+\teedge->m_dest->dump_to_pp (pp, *ext_state);\n+    }\n+}\n+\n+/* Dump this path in multiline form to FP.  */\n+\n+void\n+exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const\n+{\n+  tree_dump_pretty_printer pp (fp);\n+  dump_to_pp (&pp, ext_state);\n+}\n+\n+/* Dump this path in multiline form to stderr.  */\n+\n+DEBUG_FUNCTION void\n+exploded_path::dump (const extrinsic_state *ext_state) const\n+{\n+  dump (stderr, ext_state);\n+}\n+\n+/* Dump this path verbosely to FILENAME.  */\n+\n+void\n+exploded_path::dump_to_file (const char *filename,\n+\t\t\t     const extrinsic_state &ext_state) const\n+{\n+  FILE *fp = fopen (filename, \"w\");\n+  if (!fp)\n+    return;\n+  pretty_printer pp;\n+  pp_format_decoder (&pp) = default_tree_printer;\n+  pp.set_output_stream (fp);\n+  dump_to_pp (&pp, &ext_state);\n+  pp_flush (&pp);\n+  fclose (fp);\n+}\n+\n+} // namespace ana\n+\n+#endif /* #if ENABLE_ANALYZER */\ndiff --git a/gcc/analyzer/exploded-path.h b/gcc/analyzer/exploded-path.h\nnew file mode 100644\nindex 00000000000..8c5ce9766a1\n--- /dev/null\n+++ b/gcc/analyzer/exploded-path.h\n@@ -0,0 +1,62 @@\n+/* Paths within an exploded_graph.\n+   Copyright (C) 2019-2026 Free Software Foundation, Inc.\n+   Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it\n+under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful, but\n+WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3.  If not see\n+<http://www.gnu.org/licenses/>.  */\n+\n+#ifndef GCC_ANALYZER_EXPLODED_PATH_H\n+#define GCC_ANALYZER_EXPLODED_PATH_H\n+\n+#include \"analyzer/exploded-graph.h\"\n+\n+namespace ana {\n+\n+/* A path within an exploded_graph: a sequence of edges.  */\n+\n+class exploded_path\n+{\n+public:\n+  exploded_path () : m_edges () {}\n+  exploded_path (const exploded_path &other);\n+\n+  unsigned length () const { return m_edges.length (); }\n+\n+  bool find_stmt_backwards (const gimple *search_stmt,\n+\t\t\t    int *out_idx) const;\n+\n+  exploded_node *get_final_enode () const;\n+\n+  void dump_to_pp (pretty_printer *pp,\n+\t\t   const extrinsic_state *ext_state) const;\n+  void dump (FILE *fp, const extrinsic_state *ext_state) const;\n+  void dump (const extrinsic_state *ext_state = nullptr) const;\n+  void dump_to_file (const char *filename,\n+\t\t     const extrinsic_state &ext_state) const;\n+\n+  bool feasible_p (logger *logger, std::unique_ptr<feasibility_problem> *out,\n+\t\t    engine *eng, const exploded_graph *eg) const;\n+\n+  auto_vec<const exploded_edge *> m_edges;\n+};\n+\n+/* Finding the shortest exploded_path within an exploded_graph.  */\n+\n+typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;\n+\n+} // namespace ana\n+\n+#endif /* GCC_ANALYZER_EXPLODED_PATH_H */\ndiff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc\nindex b40fba0c574..b3097f189a1 100644\n--- a/gcc/analyzer/feasible-graph.cc\n+++ b/gcc/analyzer/feasible-graph.cc\n@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see\n #include \"analyzer/supergraph.h\"\n #include \"analyzer/program-state.h\"\n #include \"analyzer/exploded-graph.h\"\n+#include \"analyzer/exploded-path.h\"\n #include \"analyzer/feasible-graph.h\"\n \n #if ENABLE_ANALYZER\n","prefixes":["pushed:","r17-185"]}