aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/ChangeLog5
-rw-r--r--gcc/ChangeLog343
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/analyzer/ChangeLog38
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.cc659
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.h87
-rw-r--r--gcc/analyzer/checker-event.cc12
-rw-r--r--gcc/analyzer/checker-event.h7
-rw-r--r--gcc/analyzer/engine.cc4
-rw-r--r--gcc/analyzer/program-state.cc12
-rw-r--r--gcc/analyzer/program-state.h15
-rw-r--r--gcc/analyzer/sm-malloc.cc52
-rw-r--r--gcc/analyzer/sm.cc10
-rw-r--r--gcc/analyzer/sm.h12
-rw-r--r--gcc/auto-profile.cc228
-rw-r--r--gcc/c-family/ChangeLog10
-rw-r--r--gcc/cobol/ChangeLog9
-rw-r--r--gcc/config/i386/mmx.md11
-rw-r--r--gcc/cp/ChangeLog38
-rw-r--r--gcc/diagnostic-digraphs.cc484
-rw-r--r--gcc/diagnostic-digraphs.h411
-rw-r--r--gcc/diagnostic-format-html.cc91
-rw-r--r--gcc/diagnostic-format-html.h6
-rw-r--r--gcc/diagnostic-format-sarif.cc221
-rw-r--r--gcc/diagnostic-format-sarif.h49
-rw-r--r--gcc/diagnostic-format-text.h6
-rw-r--r--gcc/diagnostic-format.h3
-rw-r--r--gcc/diagnostic-metadata.h29
-rw-r--r--gcc/diagnostic-output-spec.cc34
-rw-r--r--gcc/diagnostic-path.cc10
-rw-r--r--gcc/diagnostic-path.h12
-rw-r--r--gcc/diagnostic-state-graphs.cc158
-rw-r--r--gcc/diagnostic-state-graphs.h156
-rw-r--r--gcc/diagnostic-state-to-dot.cc605
-rw-r--r--gcc/diagnostic-state.h37
-rw-r--r--gcc/diagnostic.cc8
-rw-r--r--gcc/diagnostic.h11
-rw-r--r--gcc/doc/analyzer.texi12
-rw-r--r--gcc/doc/invoke.texi12
-rw-r--r--gcc/doc/libgdiagnostics/topics/compatibility.rst31
-rw-r--r--gcc/doc/libgdiagnostics/topics/graphs.rst197
-rw-r--r--gcc/doc/libgdiagnostics/topics/index.rst1
-rw-r--r--gcc/fortran/ChangeLog27
-rw-r--r--gcc/fortran/invoke.texi4
-rw-r--r--gcc/fortran/openmp.cc30
-rw-r--r--gcc/fortran/trans-openmp.cc13
-rw-r--r--gcc/graphviz.h10
-rw-r--r--gcc/json.h5
-rw-r--r--gcc/libgdiagnostics++.h163
-rw-r--r--gcc/libgdiagnostics-private.h62
-rw-r--r--gcc/libgdiagnostics.cc340
-rw-r--r--gcc/libgdiagnostics.h134
-rw-r--r--gcc/libgdiagnostics.map23
-rw-r--r--gcc/libsarifreplay.cc435
-rw-r--r--gcc/lra-constraints.cc19
-rw-r--r--gcc/selftest-run-tests.cc2
-rw-r--r--gcc/selftest.h2
-rw-r--r--gcc/testsuite/ChangeLog111
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py53
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py86
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c13
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py48
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c16
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py55
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c8
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc283
-rw-r--r--gcc/testsuite/gcc.dg/plugin/plugin.exp4
-rw-r--r--gcc/testsuite/gcc.dg/pr87600-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr87600-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr87600.h3
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/parameter-3.f9016
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/parameter-4.f9026
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/parameter.f9527
-rw-r--r--gcc/testsuite/lib/sarif.py26
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.40.2-duplicate-node-id.sarif23
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.41.4-unrecognized-node-id.sarif16
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py46
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-sarif-roundtrip.py55
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs.sarif2445
-rw-r--r--libstdc++-v3/ChangeLog53
83 files changed, 7759 insertions, 1071 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index a4f8bb3..d883133 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,8 @@
+2025-07-11 Richard Biener <rguenther@suse.de>
+
+ * gcc-changelog/git_update_version.py: Stop updating gcc-12
+ branch.
+
2025-07-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
* prepare-commit-msg: Force default git prefixes.
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9f241a2..76fd227 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,346 @@
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-html.cc: Include "diagnostic-format-sarif.h",
+ Replace include of "diagnostic-state.h" with includes of
+ "diagnostic-digraphs.h" and "diagnostic-state-graphs.h".
+ (html_generation_options::html_generation_options): Update for
+ field renaming.
+ (html_builder::m_body_element): New field.
+ (html_builder::html_builder): Initialize m_body_element.
+ (html_builder::maybe_make_state_diagram): Port from XML
+ implementation to state graph implementation.
+ (html_builder::make_element_for_diagnostic): Add any
+ per-diagnostic graphs.
+ (html_builder::add_graph): New.
+ (html_builder::emit_global_graph): New.
+ (html_output_format::report_global_digraph): New.
+ * diagnostic-format-html.h
+ (html_generation_options::m_show_state_diagram_xml): Replace
+ with...
+ (html_generation_options::m_show_state_diagrams_sarif): ...this.
+ (html_generation_options::m_show_state_diagram_dot_src): Rename
+ to...
+ (html_generation_options::m_show_state_diagrams_dot_src): ...this.
+ * diagnostic-format-sarif.cc: Include "diagnostic-digraphs.h" and
+ "diagnostic-state-graphs.h".
+ (sarif_builder::m_run_graphs): New field.
+ (sarif_result::on_nested_diagnostic): Update call to
+ make_location_object to pass arg by pointer.
+ (sarif_builder::sarif_builder): Initialize m_run_graphs.
+ (sarif_builder::report_global_digraph): New.
+ (sarif_builder::make_result_object): Add any graphs to
+ the result object.
+ (sarif_builder::make_locations_arr): Update call to
+ make_location_object to pass arg by pointer.
+ (sarif_builder::make_location_object): Pass param "loc_mgr" by
+ pointer rather than by reference so that it can be null, and
+ handle this case.
+ (copy_any_property_bag): New.
+ (make_sarif_graph): New.
+ (make_sarif_node): New.
+ (make_sarif_edge): New.
+ (sarif_property_bag::set_graph): New.
+ (populate_thread_flow_location_object): Port from XML
+ implementation to state graph implementation.
+ (make_run_object): Store any graphs.
+ (sarif_output_format::report_global_digraph): New.
+ (sarif_generation_options::sarif_generation_options): Rename
+ m_xml_state to m_state_graph.
+ (selftest::test_make_location_object): Update for change to
+ make_location_object.
+ * diagnostic-format-sarif.h:
+ (sarif_generation_options::m_xml_state): Replace with...
+ (sarif_generation_options::m_state_graph): ...this.
+ (class sarif_location_manager): Add forward decl.
+ (diagnostics::digraphs::digraph): New forward decl.
+ (diagnostics::digraphs::node): New forward decl.
+ (diagnostics::digraphs::edge): New forward decl.
+ (sarif_property_bag::set_graph): New decl.
+ (class sarif_graph): New.
+ (class sarif_node): New.
+ (class sarif_edge): New.
+ (make_sarif_graph): New decl.
+ (make_sarif_node): New decl.
+ (make_sarif_edge): New decl.
+ * diagnostic-format-text.h
+ (diagnostic_text_output_format::report_global_digraph): New.
+ * diagnostic-format.h
+ (diagnostic_output_format::report_global_digraph): New vfunc.
+ * diagnostic-digraphs.cc: New file.
+ * diagnostic-digraphs.h: New file.
+ * diagnostic-metadata.h (diagnostics::digraphs::lazy_digraphs):
+ New forward decl.
+ (diagnostic_metadata::diagnostic_metadata): Initialize
+ m_lazy_digraphs.
+ (diagnostic_metadata::set_lazy_digraphs): New.
+ (diagnostic_metadata::get_lazy_digraphs): New.
+ (diagnostic_metadata::m_lazy_digraphs): New field.
+ * diagnostic-output-spec.cc (sarif_scheme_handler::make_sink):
+ Update for XML to state graph changes.
+ (sarif_scheme_handler::make_sarif_gen_opts): Likewise.
+ (html_scheme_handler::make_sink): Rename "show-state-diagram-xml"
+ to "show-state-diagrams-sarif" and use pluralization consistently.
+ * diagnostic-path.cc: Replace include of "xml.h" with
+ "diagnostic-state-graphs.h".
+ (diagnostic_event::maybe_make_xml_state): Replace with...
+ (diagnostic_event::maybe_make_diagnostic_state_graph): ...this.
+ * diagnostic-path.h (diagnostics::digraphs::digraph): New forward
+ decl.
+ (diagnostic_event::maybe_make_xml_state): Replace with...
+ (diagnostic_event::maybe_make_diagnostic_state_graph): ...this.
+ * diagnostic-state-graphs.cc: New file.
+ * diagnostic-state-graphs.h: New file.
+ * diagnostic-state-to-dot.cc: Port implementation from XML to
+ state graphs.
+ * diagnostic-state.h: Deleted file.
+ * diagnostic.cc (diagnostic_context::report_global_digraph): New.
+ * diagnostic.h (diagnostics::digraphs::lazy_digraph): New forward
+ decl.
+ (diagnostic_context::report_global_digraph): New decl.
+ * doc/analyzer.texi (Debugging the Analyzer): Update to reflect
+ change from XML to state graphs.
+ * doc/invoke.texi ("sarif" diagnostics sink): Replace "xml-state"
+ with "state-graphs".
+ ("experimental-html" diagnostics sink): Replace
+ "show-state-diagrams-xml" with "show-state-diagrams-sarif"
+ * doc/libgdiagnostics/topics/compatibility.rst
+ (LIBGDIAGNOSTICS_ABI_3): New.
+ * doc/libgdiagnostics/topics/graphs.rst: New file.
+ * doc/libgdiagnostics/topics/index.rst: Add graphs.rst.
+ * graphviz.h (node_id::operator=): New.
+ * json.h (json::value::dyn_cast_string): New.
+ (json::object::get_num_keys): New accessor.
+ (json::object::get_key): New accessor.
+ (json::string::dyn_cast_string): New.
+ * libgdiagnostics++.h (class libgdiagnostics::graph): New.
+ (class libgdiagnostics::node): New.
+ (class libgdiagnostics::edge): New.
+ (class libgdiagnostics::diagnostic::take_graph): New.
+ (class libgdiagnostics::manager::take_global_graph): New.
+ (class libgdiagnostics::graph::set_description): New.
+ (class libgdiagnostics::graph::get_node_by_id): New.
+ (class libgdiagnostics::graph::get_edge_by_id): New.
+ (class libgdiagnostics::graph::add_edge): New.
+ (class libgdiagnostics::node::set_label): New.
+ (class libgdiagnostics::node::set_location): New.
+ (class libgdiagnostics::node::set_logical_location): New.
+ * libgdiagnostics-private.h: New file.
+ * libgdiagnostics.cc: Define INCLUDE_STRING. Include
+ "diagnostic-digraphs.h", "diagnostic-state-graphs.h", and
+ "libgdiagnostics-private.h".
+ (struct diagnostic_graph): New.
+ (struct diagnostic_node): New.
+ (struct diagnostic_edge): New.
+ (libgdiagnostics_path_event::libgdiagnostics_path_event): Add
+ state_graph param.
+ (libgdiagnostics_path_event::maybe_make_diagnostic_state_graph):
+ New.
+ (libgdiagnostics_path_event::m_state_graph): New field.
+ (diagnostic_execution_path::add_event_va): Add state_graph param.
+ (class prebuilt_digraphs): New.
+ (diagnostic::diagnostic): Use m_graphs in m_metadata.
+ (diagnostic::take_graph): New.
+ (diagnostic::get_graphs): New accessor.
+ (diagnostic::m_graphs): New field.
+ (diagnostic_manager::take_global_graph): New.
+ (diagnostic_execution_path_add_event): Update for new param to
+ add_event_va.
+ (diagnostic_execution_path_add_event_va): Likewise.
+ (diagnostic_graph::add_node_with_id): New public entrypoint.
+ (diagnostic_graph::add_edge_with_label): New public entrypoint.
+ (diagnostic_manager_new_graph): New public entrypoint.
+ (diagnostic_manager_take_global_graph): New public entrypoint.
+ (diagnostic_take_graph): New public entrypoint.
+ (diagnostic_graph_release): New public entrypoint.
+ (diagnostic_graph_set_description): New public entrypoint.
+ (diagnostic_graph_add_node): New public entrypoint.
+ (diagnostic_graph_add_edge): New public entrypoint.
+ (diagnostic_graph_get_node_by_id): New public entrypoint.
+ (diagnostic_graph_get_edge_by_id): New public entrypoint.
+ (diagnostic_node_set_location): New public entrypoint.
+ (diagnostic_node_set_label): New public entrypoint.
+ (diagnostic_node_set_logical_location): New public entrypoint.
+ (private_diagnostic_execution_path_add_event_2): New private
+ entrypoint.
+ (private_diagnostic_graph_set_property_bag): New private
+ entrypoint.
+ (private_diagnostic_node_set_property_bag): New private
+ entrypoint.
+ (private_diagnostic_edge_set_property_bag): New private
+ entrypoint.
+ * libgdiagnostics.h (diagnostic_graph): New typedef.
+ (diagnostic_node): New typedef.
+ (diagnostic_edge): New typedef.
+ (diagnostic_manager_new_graph): New decl.
+ (diagnostic_manager_take_global_graph): New decl.
+ (diagnostic_take_graph): New decl.
+ (diagnostic_graph_release): New decl.
+ (diagnostic_graph_set_description): New decl.
+ (diagnostic_graph_add_node): New decl.
+ (diagnostic_graph_add_edge): New decl.
+ (diagnostic_graph_get_node_by_id): New decl.
+ (diagnostic_graph_get_edge_by_id): New decl.
+ (diagnostic_node_set_label): New decl.
+ (diagnostic_node_set_location): New decl.
+ (diagnostic_node_set_logical_location): New decl.
+ * libgdiagnostics.map (LIBGDIAGNOSTICS_ABI_3): New.
+ * libsarifreplay.cc: Include "libgdiagnostics-private.h".
+ (id_map): New "using".
+ (sarif_replayer::report_invalid_sarif): Update for change to
+ report_problem params.
+ (sarif_replayer::report_unhandled_sarif): Likewise.
+ (sarif_replayer::report_note): New.
+ (sarif_replayer::report_problem): Pass param "ref" by
+ pointer rather than reference and handle it being null.
+ (sarif_replayer::maybe_get_property_bag): New.
+ (sarif_replayer::maybe_get_property_bag_value): New.
+ (sarif_replayer::handle_run_obj): Handle run-level "graphs" as per
+ §3.14.20.
+ (sarif_replayer::handle_result_obj): Handle result-level "graphs"
+ as per §3.27.19.
+ (handle_thread_flow_location_object): Optionally handle graphs
+ stored in property "gcc/diagnostic_event/state_graph" as state
+ graphs.
+ (sarif_replayer::handle_graph_object): New.
+ (sarif_replayer::handle_node_object): New.
+ (sarif_replayer::handle_edge_object): New.
+ (sarif_replayer::get_graph_node_by_id_property): New.
+ * selftest-run-tests.cc (selftest::run_tests): Call
+ selftest::diagnostic_graph_cc_tests and
+ selftest::diagnostic_state_graph_cc_tests.
+ * selftest.h (selftest::diagnostic_graph_cc_tests): New decl.
+ (selftest::diagnostic_state_graph_cc_tests): New decl.
+
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Add diagnostic-digraphs.o and
+ diagnostic-state-graphs.o.
+
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * json.cc (json::object::clone): New.
+ (json::object::clone_as_object): New.
+ (json::array::clone): New.
+ (json::float_number::clone): New.
+ (json::integer_number::clone): New.
+ (json::string::clone): New.
+ (json::literal::clone): New.
+ (selftest::test_cloning): New test.
+ (selftest::json_cc_tests): Call it.
+ * json.h (json::value::clone): New vfunc.
+ (json::object::clone): New decl.
+ (json::object::clone_as_object): New decl.
+ (json::array::clone): New decl.
+ (json::float_number::clone): New decl.
+ (json::integer_number::clone): New decl.
+ (json::string::clone): New decl.
+ (json::literal::clone): New decl.
+
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * json.cc (string::string): When constructing from pointer and
+ length, ensure the new buffer is null-terminated.
+ (selftest::test_strcmp): New.
+ (selftest::json_cc_tests): Likewise.
+
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/libgdiagnostics/topics/compatibility.rst
+ (_LIBGDIAGNOSTICS_ABI_2): Add missing anchor.
+ * doc/libgdiagnostics/topics/diagnostic-manager.rst
+ (diagnostic_manager_add_sink_from_spec): Add links to GCC's
+ documentation of "-fdiagnostics-add-output=". Fix parameter
+ markup.
+ (diagnostic_manager_set_analysis_target): Fix parameter markup.
+ Add link to SARIF spec.
+ * doc/libgdiagnostics/topics/logical-locations.rst: Markup fix.
+ * doc/libgdiagnostics/tutorial/02-physical-locations.rst: Clarify
+ wording of what "the source file" means, and that a range can't
+ have multiple files.
+
+2025-07-11 Vladimir N. Makarov <vmakarov@redhat.com>
+
+ * lra-constraints.cc (process_address_1): When changing base reg
+ on a reg of the base class, fall back to reload of whole inner address.
+ (process_address): Constrain the iteration number.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119064
+ * doc/invoke.texi (Wc++26-compat): Document.
+
+2025-07-11 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR target/121027
+ * config/aarch64/aarch64.cc (aarch64_evpc_sve_tbl): Punt on 2-input
+ operations that can be handled by vec_perm.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64-simd.md (*eor3qdi4): New
+ define_insn_and_split.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64-simd.md (*bcaxqdi4): New
+ define_insn_and_split.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64-simd.md (eor3q<mode>4): Use VDQ_I mode
+ iterator.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64-simd.md (bcaxq<mode>4): Use VDQ_I mode
+ iterator.
+
+2025-07-11 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121034
+ * tree-vect-loop.cc (vectorizable_reduction): Cleanup
+ reduction chain following code.
+
+2025-07-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * opts.cc (finish_options): Enable debug_nonbind_markers_p for
+ auto-profile.
+ * tree-cfg.cc (struct locus_discrim_map): Remove.
+ (struct locus_discrim_hasher): Remove.
+ (locus_discrim_hasher::hash): Remove.
+ (locus_discrim_hasher::equal): Remove.
+ (first_non_label_nondebug_stmt): Remove.
+ (build_gimple_cfg): Do not allocate discriminator tables.
+ (next_discriminator_for_locus): Remove.
+ (same_line_p): Remove.
+ (struct discrim_entry): New structure.
+ (assign_discriminator): Rewrite.
+ (assign_discriminators): Rewrite.
+
+2025-07-11 Jan Hubicka <hubicka@ucw.cz>
+
+ PR ipa/114790
+ * cgraph.cc (cgraph_update_edges_for_call_stmt_node): Resolve devirtualization
+ if call statement was optimized out or turned to direct call.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+ Martin Jambor <mjambor@suse.cz>
+
+ PR ipa/121023
+ * ipa-fnsummary.cc (compute_fn_summary): Disallow signature changes
+ on cfun->has_musttail functions.
+
+2025-07-11 Hu, Lin1 <lin1.hu@intel.com>
+
+ PR target/91384
+ * config/i386/i386.md: Add new peeophole2 for optimize *negsi_1
+ followed by *cmpsi_ccno_1 with APX_F.
+
+2025-07-11 Richard Biener <rguenther@suse.de>
+
+ * config/i386/i386.cc (ix86_vector_costs::add_stmt_cost): Use
+ the LHS of a scalar stmt to determine mode and whether it is FP.
+
2025-07-10 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.cc (aarch64_vector_costs::add_stmt_cost):
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index 26b40b2..e177aad 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20250711
+20250712
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index d5ceccc..bdb5292 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1856,11 +1856,13 @@ OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
diagnostic-format-sarif.o \
diagnostic-format-text.o \
diagnostic-global-context.o \
+ diagnostic-digraphs.o \
diagnostic-macro-unwinding.o \
diagnostic-output-spec.o \
diagnostic-path.o \
diagnostic-path-output.o \
diagnostic-show-locus.o \
+ diagnostic-state-graphs.o \
diagnostic-state-to-dot.o \
edit-context.o \
graphviz.o pex.o \
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index d31cbbc..a34fa13 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,41 @@
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Reimplement, replacing
+ XML-based implementation with one based on state graphs.
+ * ana-state-to-diagnostic-state.h: Likewise.
+ * checker-event.cc: Replace include of "xml.h" with include of
+ "diagnostic-state-graphs.h".
+ (checker_event::maybe_make_xml_state): Replace with...
+ (checker_event::maybe_make_diagnostic_state_graph): ...this.
+ * checker-event.h: Add include of "diagnostic-digraphs.h".
+ (checker_event::maybe_make_xml_state): Replace decl with...
+ (checker_event::maybe_make_diagnostic_state_graph): ...this.
+ * engine.cc (exploded_node::on_stmt_pre): Replace
+ "_analyzer_dump_xml" with "__analyzer_dump_sarif".
+ * program-state.cc: Replace include of "diagnostic-state.h" with
+ "diagnostic-state-graphs.h".
+ (program_state::dump_dot): Port from XML to state graphs.
+ * program-state.h: Drop reduntant forward decl of xml::document.
+ (program_state::make_xml): Replace decl with...
+ (program_state::make_diagnostic_state_graph): ...this.
+ (program_state::dump_xml_to_pp): Drop decl.
+ (program_state::dump_xml_to_file): Drop decl.
+ (program_state::dump_xml): Drop decl.
+ (program_state::dump_dump_sarif): New decl.
+ * sm-malloc.cc (get_dynalloc_state_for_state): New.
+ (malloc_state_machine::add_state_to_xml): Replace with...
+ (malloc_state_machine::add_state_to_state_graph): ...this.
+ * sm.cc (state_machine::add_state_to_xml): Replace with...
+ (state_machine::add_state_to_state_graph): ...this.
+ (state_machine::add_global_state_to_xml): Replace with...
+ (state_machine::add_global_state_to_state_graph): ...this.
+ * sm.h (class xml_state): Drop forward decl.
+ (class analyzer_state_graph): New forward decl.
+ (state_machine::add_state_to_xml): Replace decl with...
+ (state_machine::add_state_to_state_graph): ...this.
+ (state_machine::add_global_state_to_xml): Replace decl with...
+ (state_machine::add_global_state_to_state_graph): ...this.
+
2025-06-30 David Malcolm <dmalcolm@redhat.com>
* access-diagram.cc: Use nullptr rather than NULL where
diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.cc b/gcc/analyzer/ana-state-to-diagnostic-state.cc
index b85a2f1..2701259 100644
--- a/gcc/analyzer/ana-state-to-diagnostic-state.cc
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.cc
@@ -1,4 +1,4 @@
-/* Converting ana::program_state to XML state documents.
+/* Creating diagnostic state graphs from ana::program_state.
Copyright (C) 2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -23,8 +23,8 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_SET
#include "analyzer/common.h"
-#include "xml.h"
-#include "xml-printer.h"
+#include "diagnostic-state-graphs.h"
+#include "diagnostic-format-sarif.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
@@ -39,57 +39,47 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
+using namespace ::diagnostics::state_graphs;
+
static void
-set_wi_attr (xml::element &e,
+set_wi_attr (state_node_ref state_node,
const char *attr_name,
const wide_int_ref &w,
signop sgn)
{
pretty_printer pp;
pp_wide_int (&pp, w, sgn);
- e.set_attr (attr_name, pp_formatted_text (&pp));
+ state_node.set_attr (attr_name, pp_formatted_text (&pp));
}
static void
-set_type_attr (xml::element &e, const_tree type)
+set_type_attr (state_node_ref state_node, const_tree type)
{
gcc_assert (type);
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_printf (&pp, "%T", type);
- e.set_attr ("type", pp_formatted_text (&pp));
+ state_node.set_type (pp_formatted_text (&pp));
}
static void
-set_bits_attr (xml::element &e,
+set_bits_attr (state_node_ref state_node,
bit_range bits)
{
pretty_printer pp;
bits.dump_to_pp (&pp);
- e.set_attr ("bits", pp_formatted_text (&pp));
+ state_node.set_attr ("bits", pp_formatted_text (&pp));
}
-static void
-set_region_id_attr (xml::element &e,
- const region &reg)
-{
- e.set_attr ("region_id", std::to_string (reg.get_id ()));
-}
+// class analyzer_state_graph : public diagnostics::digraphs::digraph
-// class xml_state : public xml::document
-
-xml_state::xml_state (const program_state &state,
- const extrinsic_state &ext_state)
-: xml::document (),
- m_state (state),
+analyzer_state_graph::analyzer_state_graph (const program_state &state,
+ const extrinsic_state &ext_state)
+: m_state (state),
m_ext_state (ext_state),
m_mgr (*ext_state.get_engine ()->get_model_manager ()),
- m_root (nullptr)
+ m_next_id (0)
{
- auto root = std::make_unique<xml::element> ("state-diagram", false);
- m_root = root.get ();
- add_child (std::move (root));
-
/* Find pointers to heap-allocated regions, and record their types,
so that we have a user-friendly way of showing the memory
(by field, rather than by byte offset). */
@@ -117,14 +107,14 @@ xml_state::xml_state (const program_state &state,
for (int i = state.m_region_model->get_stack_depth () - 1; i >= 0; --i)
{
const frame_region *reg = state.m_region_model->get_frame_at_index (i);
- get_or_create_element (*reg);
+ get_or_create_state_node (*reg);
}
/* Create bound memory. */
for (auto iter : *state.m_region_model->get_store ())
{
const bool create_all = false; // "true" for verbose, for debugging
- create_elements_for_binding_cluster (*iter.second, create_all);
+ create_state_nodes_for_binding_cluster (*iter.second, create_all);
}
/* TODO: Constraints. */
@@ -137,52 +127,165 @@ xml_state::xml_state (const program_state &state,
{
auto &sm = ext_state.get_sm (i);
for (const auto &iter : *smap)
- sm.add_state_to_xml (*this, *iter.first, iter.second.m_state);
+ sm.add_state_to_state_graph (*this, *iter.first, iter.second.m_state);
if (auto s = smap->get_global_state ())
- sm.add_global_state_to_xml (*this, s);
+ sm.add_global_state_to_state_graph (*this, s);
}
}
+
+ /* Process pending edges. */
+ while (m_pending_edges.size () > 0)
+ {
+ pending_edge item = m_pending_edges.back ();
+ m_pending_edges.pop_back ();
+
+ /* Ensure we have a node for the dst region. This
+ could lead to additional pending edges. */
+ auto dst_node = get_or_create_state_node (item.m_dst_reg);
+ add_edge (nullptr, item.m_src_node.m_node, dst_node.m_node);
+ }
}
-xml::element &
-xml_state::get_or_create_element (const region &reg)
+state_node_ref
+analyzer_state_graph::get_or_create_state_node (const region &reg)
{
- auto existing = m_region_to_element_map.find (&reg);
- if (existing != m_region_to_element_map.end ())
+ auto existing = m_region_to_state_node_map.find (&reg);
+ if (existing != m_region_to_state_node_map.end ())
return *existing->second;
- auto &e = create_and_add_element (reg);
- m_region_to_element_map[&reg] = &e;
- return e;
+ auto ref = create_and_add_state_node (reg);
+ m_region_to_state_node_map[&reg] = &ref.m_node;
+ return ref;
}
-xml::element&
-xml_state::create_and_add_element (const region &reg)
+state_node_ref
+analyzer_state_graph::create_and_add_state_node (const region &reg)
{
- auto e = create_element (reg);
- xml::element &result = *e;
+ auto node = create_state_node (reg);
+
+ state_node_ref result = *node;
if (auto parent_reg = reg.get_parent_region ())
+ if (parent_reg->get_kind () != RK_ROOT)
+ {
+ auto parent_state_node = get_or_create_state_node (*parent_reg);
+ parent_state_node.m_node.add_child (std::move (node));
+ return result;
+ }
+ add_node (std::move (node));
+ return result;
+}
+
+std::string
+analyzer_state_graph::make_node_id (const char *prefix)
+{
+ return std::string (prefix) + "-" + std::to_string (m_next_id++);
+}
+
+std::string
+analyzer_state_graph::make_node_id (const region &reg)
+{
+ const char *prefix = nullptr;
+ switch (reg.get_kind ())
{
- auto parent_element = &get_or_create_element (*parent_reg);
- parent_element->add_child (std::move (e));
+ case RK_ROOT:
+ default:
+ gcc_unreachable ();
+ break;
+
+ case RK_GLOBALS:
+ return "globals";
+ case RK_CODE:
+ return "code";
+ case RK_STACK:
+ return "stack";
+ case RK_HEAP:
+ return "heap";
+
+ case RK_FRAME:
+ prefix = "frame-region";
+ break;
+ case RK_FUNCTION:
+ prefix = "function-region";
+ break;
+ case RK_LABEL:
+ prefix = "label-region";
+ break;
+ case RK_THREAD_LOCAL:
+ prefix = "thread-local-region";
+ break;
+ case RK_SYMBOLIC:
+ prefix = "symbolic-region";
+ break;
+ case RK_DECL:
+ prefix = "decl-region";
+ break;
+ case RK_FIELD:
+ prefix = "field-region";
+ break;
+ case RK_ELEMENT:
+ prefix = "element-region";
+ break;
+ case RK_OFFSET:
+ prefix = "offset-region";
+ break;
+ case RK_SIZED:
+ prefix = "sized-region";
+ break;
+ case RK_CAST:
+ prefix = "cast-region";
+ break;
+ case RK_HEAP_ALLOCATED:
+ prefix = "heap-allocated-region";
+ break;
+ case RK_ALLOCA:
+ prefix = "alloca-region";
+ break;
+ case RK_STRING:
+ prefix = "string-region";
+ break;
+ case RK_BIT_RANGE:
+ prefix = "bit-range-region";
+ break;
+ case RK_VAR_ARG:
+ prefix = "var-arg-region";
+ break;
+ case RK_ERRNO:
+ prefix = "errno-region";
+ break;
+ case RK_PRIVATE:
+ prefix = "private-region";
+ break;
+ case RK_UNKNOWN:
+ prefix = "unknown-region";
+ break;
}
- else
- m_root->add_child (std::move (e));
- return result;
+ return std::string (prefix) + "-" + std::to_string (reg.get_id ());
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::
+make_state_node (diagnostics::state_graphs::node_kind kind,
+ std::string id)
+{
+ auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
+ state_node_ref node_ref (*node);
+ node_ref.set_node_kind (kind);
+ return node;
}
-std::unique_ptr<xml::element>
-xml_state::make_memory_space_element (const char *label)
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::
+make_memspace_state_node (const region &reg,
+ diagnostics::state_graphs::node_kind kind)
{
- auto e = std::make_unique<xml::element> ("memory-space", false);
- e->set_attr ("label", label);
- return e;
+ return make_state_node (kind, make_node_id (reg));
}
-std::unique_ptr<xml::element>
-xml_state::create_element (const region &reg)
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::create_state_node (const region &reg)
{
- std::unique_ptr<xml::element> e;
+ std::unique_ptr<diagnostics::digraphs::node> node;
+
switch (reg.get_kind ())
{
default:
@@ -190,110 +293,102 @@ xml_state::create_element (const region &reg)
case RK_FRAME:
{
- e = std::make_unique<xml::element> ("stack-frame", false);
const frame_region &frame_reg
= static_cast<const frame_region &> (reg);
+
+ node = make_state_node (diagnostics::state_graphs::node_kind::stack_frame,
+ make_node_id (reg));
+ node->set_logical_loc
+ (m_logical_loc_mgr.key_from_tree (frame_reg.get_fndecl ()));
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_printf (&pp, "%E", frame_reg.get_fndecl ());
- e->set_attr ("function", pp_formatted_text (&pp));
+ node->set_attr (STATE_NODE_PREFIX, "function",
+ pp_formatted_text (&pp));
}
}
break;
+
case RK_GLOBALS:
- e = make_memory_space_element ("Globals");
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::globals);
break;
case RK_CODE:
- e = make_memory_space_element ("Code");
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::code);
break;
case RK_FUNCTION:
- e = std::make_unique<xml::element> ("function", false);
- // TODO
- break;
- case RK_LABEL:
- e = std::make_unique<xml::element> ("label", false);
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::function);
// TODO
break;
+
case RK_STACK:
- e = std::make_unique<xml::element> ("stack", false);
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::stack);
break;
case RK_HEAP:
- e = make_memory_space_element ("Heap");
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::heap_);
break;
case RK_THREAD_LOCAL:
- e = make_memory_space_element ("Thread-local");
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::thread_local_);
break;
case RK_ROOT:
- e = std::make_unique<xml::element> ("memory-regions", false);
+ gcc_unreachable ();
break;
case RK_SYMBOLIC:
- e = std::make_unique<xml::element> ("symbolic-region", false);
- // TODO
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::other);
break;
+
case RK_DECL:
{
- e = std::make_unique<xml::element> ("variable", false);
+ node = make_state_node (diagnostics::state_graphs::node_kind::variable,
+ make_node_id (reg));
const decl_region &decl_reg
= static_cast<const decl_region &> (reg);
+ state_node_ref node_ref (*node);
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_printf (&pp, "%E", decl_reg.get_decl ());
- e->set_attr ("name", pp_formatted_text (&pp));
+ node_ref.set_name (pp_formatted_text (&pp));
}
- set_type_attr (*e, TREE_TYPE (decl_reg.get_decl ()));
+ set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
}
break;
+
case RK_FIELD:
- e = std::make_unique<xml::element> ("field", false);
- break;
case RK_ELEMENT:
- e = std::make_unique<xml::element> ("element", false);
+ /* These should be handled in populate_state_node_for_typed_region. */
+ gcc_unreachable ();
break;
+
+ case RK_LABEL:
case RK_OFFSET:
- e = std::make_unique<xml::element> ("offset-region", false);
- // TODO
- break;
case RK_SIZED:
- e = std::make_unique<xml::element> ("sized-region", false);
- // TODO
- break;
case RK_CAST:
- e = std::make_unique<xml::element> ("cast-region", false);
- // TODO
- break;
- case RK_HEAP_ALLOCATED:
- e = std::make_unique<xml::element> ("heap-buffer", false);
- set_attr_for_dynamic_extents (reg, *e);
- break;
- case RK_ALLOCA:
- e = std::make_unique<xml::element> ("alloca-buffer", false);
- set_attr_for_dynamic_extents (reg, *e);
- break;
case RK_STRING:
- e = std::make_unique<xml::element> ("string-region", false);
- // TODO
- break;
case RK_BIT_RANGE:
- e = std::make_unique<xml::element> ("RK_BIT_RANGE", false); // TODO
- break;
case RK_VAR_ARG:
- e = std::make_unique<xml::element> ("RK_VAR_ARG", false); // TODO
- break;
case RK_ERRNO:
- e = std::make_unique<xml::element> ("errno", false);
- break;
case RK_PRIVATE:
- e = std::make_unique<xml::element> ("RK_PRIVATE", false); // TODO
- break;
case RK_UNKNOWN:
- e = std::make_unique<xml::element> ("RK_UNKNOWN", false); // TODO
+ node = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id (reg));
break;
- }
- gcc_assert (e);
- set_region_id_attr (*e, reg);
+ case RK_HEAP_ALLOCATED:
+ case RK_ALLOCA:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::dynalloc_buffer);
+ set_attr_for_dynamic_extents (reg, *node);
+ break;
+ }
+ gcc_assert (node);
if (reg.get_base_region () == &reg)
if (!reg.get_type ())
@@ -303,16 +398,17 @@ xml_state::create_element (const region &reg)
if (search != m_types_for_untyped_regions.end ())
{
tree type_to_use = search->second;
- set_type_attr (*e, type_to_use);
+ set_type_attr (*node, type_to_use);
}
}
- return e;
+ return node;
}
void
-xml_state::create_elements_for_binding_cluster (const binding_cluster &cluster,
- bool create_all)
+analyzer_state_graph::
+create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
+ bool create_all)
{
/* TODO:
- symbolic bindings
@@ -326,12 +422,12 @@ xml_state::create_elements_for_binding_cluster (const binding_cluster &cluster,
if (auto conc_key = key->dyn_cast_concrete_binding ())
conc_bindings[conc_key->get_bit_range ()] = svalue;
if (const region *reg = svalue->maybe_get_region ())
- get_or_create_element (*reg);
+ get_or_create_state_node (*reg);
}
- auto &e = get_or_create_element (*cluster.get_base_region ());
+ auto ref = get_or_create_state_node (*cluster.get_base_region ());
- e.add_child (create_element_for_conc_bindings (conc_bindings));
+ ref.m_node.add_child (create_state_node_for_conc_bindings (conc_bindings));
const region *typed_reg = cluster.get_base_region ();
if (!typed_reg->get_type ())
@@ -346,44 +442,45 @@ xml_state::create_elements_for_binding_cluster (const binding_cluster &cluster,
}
if (typed_reg->get_type ())
- populate_element_for_typed_region (e,
- *typed_reg,
- conc_bindings,
- create_all);
+ populate_state_node_for_typed_region (ref,
+ *typed_reg,
+ conc_bindings,
+ create_all);
else
{
// TODO
}
}
-std::unique_ptr<xml::element>
-xml_state::create_element_for_conc_bindings (const concrete_bindings_t &conc_bindings)
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
{
- auto e = std::make_unique<xml::element> ("concrete-bindings", false);
+ auto node = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id ("concrete-bindings"));
for (auto iter : conc_bindings)
{
const bit_range bits = iter.first;
const svalue *sval = iter.second;
- auto binding_element
- = std::make_unique<xml::element> ("binding", false);
- set_bits_attr (*binding_element, bits);
+ auto binding_state_node
+ = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id ("binding"));
+ set_bits_attr (*binding_state_node, bits);
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
sval->dump_to_pp (&pp, true);
- binding_element->set_attr ("value", pp_formatted_text (&pp));
- if (auto svalue_element = create_element_for_svalue (sval))
- binding_element->add_child (std::move (svalue_element));
+ binding_state_node->set_attr (STATE_NODE_PREFIX, "value",
+ pp_formatted_text (&pp));
}
- e->add_child (std::move (binding_element));
+ node->add_child (std::move (binding_state_node));
}
- return e;
+ return node;
}
// Try to get the bit_range of REG within its base region
bool
-xml_state::get_bit_range_within_base_region (const region &reg,
- bit_range &out)
+analyzer_state_graph::get_bit_range_within_base_region (const region &reg,
+ bit_range &out)
{
region_offset start_offset = reg.get_offset (&m_mgr);
if (!start_offset.concrete_p ())
@@ -398,30 +495,28 @@ xml_state::get_bit_range_within_base_region (const region &reg,
}
void
-xml_state::populate_element_for_typed_region (xml::element &e,
- const region &reg,
- const concrete_bindings_t &conc_bindings,
- bool create_all)
+analyzer_state_graph::
+populate_state_node_for_typed_region (state_node_ref node,
+ const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all)
{
const_tree reg_type = reg.get_type ();
gcc_assert (reg_type);
- set_type_attr (e, reg_type);
+ set_type_attr (node, reg_type);
bit_range bits (0, 0);
if (get_bit_range_within_base_region (reg, bits))
{
- set_bits_attr (e, bits);
+ set_bits_attr (node, bits);
auto search = conc_bindings.find (bits);
if (search != conc_bindings.end ())
{
const svalue *bound_sval = search->second;
- if (auto svalue_element = create_element_for_svalue (bound_sval))
- {
- xml::printer xp (e);
- xp.push_tag ("value-of-region");
- xp.append (std::move (svalue_element));
- }
+ node.set_json_attr ("value", bound_sval->to_json ());
+ if (const region *dst_reg = bound_sval->maybe_get_region ())
+ m_pending_edges.push_back ({node, *dst_reg});
}
}
@@ -454,22 +549,23 @@ xml_state::populate_element_for_typed_region (xml::element &e,
= m_mgr.get_element_region (&reg,
const_cast<tree> (element_type),
sval_index);
- if (show_child_element_for_child_region_p (*child_reg,
+ if (show_child_state_node_for_child_region_p (*child_reg,
conc_bindings,
create_all))
{
- // Here "element" is in the xml sense
- auto child_element
- = std::make_unique<xml::element> ("element", false);
- set_wi_attr (*child_element, "index", idx, UNSIGNED);
- set_region_id_attr (*child_element, *child_reg);
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::element,
+ make_node_id (*child_reg));
+ set_wi_attr (*child_state_node, "index", idx, UNSIGNED);
+
// Recurse:
gcc_assert (element_type);
- populate_element_for_typed_region (*child_element,
- *child_reg,
- conc_bindings,
- create_all);
- e.add_child (std::move (child_element));
+ populate_state_node_for_typed_region (*child_state_node,
+ *child_reg,
+ conc_bindings,
+ create_all);
+ node.m_node.add_child (std::move (child_state_node));
}
}
}
@@ -485,15 +581,17 @@ xml_state::populate_element_for_typed_region (xml::element &e,
const bit_range bits (0, item.m_bit_range.m_size_in_bits);
const region *child_reg
= m_mgr.get_bit_range (&reg, NULL_TREE, bits);
- if (show_child_element_for_child_region_p (*child_reg,
- conc_bindings,
- create_all))
+ if (show_child_state_node_for_child_region_p (*child_reg,
+ conc_bindings,
+ create_all))
{
- auto child_element
- = std::make_unique<xml::element> ("padding", false);
- set_wi_attr (*child_element, "num_bits",
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::padding,
+ make_node_id (*child_reg));
+ set_wi_attr (*child_state_node, "num_bits",
item.m_bit_range.m_size_in_bits, SIGNED);
- e.add_child (std::move (child_element));
+ node.m_node.add_child (std::move (child_state_node));
}
}
else
@@ -501,26 +599,28 @@ xml_state::populate_element_for_typed_region (xml::element &e,
const region *child_reg
= m_mgr.get_field_region (&reg,
const_cast<tree> (item.m_field));
- if (show_child_element_for_child_region_p (*child_reg,
+ if (show_child_state_node_for_child_region_p (*child_reg,
conc_bindings,
create_all))
{
- auto child_element
- = std::make_unique<xml::element> ("field", false);
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::field,
+ make_node_id (*child_reg));
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_printf (&pp, "%D", item.m_field);
- child_element->set_attr ("name",
- pp_formatted_text (&pp));
+ child_state_node->set_attr (STATE_NODE_PREFIX, "name",
+ pp_formatted_text (&pp));
}
- set_region_id_attr (*child_element, *child_reg);
+
// Recurse:
- populate_element_for_typed_region (*child_element,
+ populate_state_node_for_typed_region (*child_state_node,
*child_reg,
conc_bindings,
create_all);
- e.add_child (std::move (child_element));
+ node.m_node.add_child (std::move (child_state_node));
}
}
}
@@ -530,7 +630,8 @@ xml_state::populate_element_for_typed_region (xml::element &e,
}
void
-xml_state::set_attr_for_dynamic_extents (const region &reg, xml::element &e)
+analyzer_state_graph::set_attr_for_dynamic_extents (const region &reg,
+ state_node_ref node_ref)
{
const svalue *sval = m_state.m_region_model->get_dynamic_extents (&reg);
if (sval)
@@ -541,13 +642,13 @@ xml_state::set_attr_for_dynamic_extents (const region &reg, xml::element &e)
pp_wide_int (&pp, wi::to_wide (cst), UNSIGNED);
else
sval->dump_to_pp (&pp, true);
- e.set_attr ("dynamic-extents", pp_formatted_text (&pp));
+ node_ref.set_attr ("dynamic-extents", pp_formatted_text (&pp));
}
}
bool
-xml_state::
-show_child_element_for_child_region_p (const region &reg,
+analyzer_state_graph::
+show_child_state_node_for_child_region_p (const region &reg,
const concrete_bindings_t &conc_bindings,
bool create_all)
{
@@ -569,216 +670,18 @@ show_child_element_for_child_region_p (const region &reg,
return false;
}
-std::unique_ptr<xml::element>
-xml_state::create_element_for_svalue (const svalue *sval)
+std::unique_ptr<diagnostics::digraphs::digraph>
+program_state::
+make_diagnostic_state_graph (const extrinsic_state &ext_state) const
{
- if (!sval)
- return nullptr;
-
- std::unique_ptr<xml::element> result;
- switch (sval->get_kind ())
- {
- default:
- gcc_unreachable ();
- case SK_REGION:
- {
- const region_svalue *region_sval = (const region_svalue *)sval;
- result
- = std::make_unique<xml::element> ("pointer-to-region", false);
- set_region_id_attr (*result, *region_sval->get_pointee ());
- }
- break;
- case SK_CONSTANT:
- {
- const constant_svalue *constant_sval = (const constant_svalue *)sval;
- result = std::make_unique<xml::element> ("constant", false);
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_printf (&pp, "%E", constant_sval->get_constant ());
- result->set_attr ("value", pp_formatted_text (&pp));
- }
- break;
- case SK_UNKNOWN:
- result = std::make_unique<xml::element> ("unknown", false);
- break;
- case SK_POISONED:
- {
- const poisoned_svalue *poisoned_sval = (const poisoned_svalue *)sval;
- switch (poisoned_sval->get_poison_kind ())
- {
- default:
- gcc_unreachable ();
- case poison_kind::uninit:
- result = std::make_unique<xml::element> ("uninitialized", false);
- break;
- case poison_kind::freed:
- result = std::make_unique<xml::element> ("freed", false);
- break;
- case poison_kind::deleted:
- result = std::make_unique<xml::element> ("deleted", false);
- break;
- case poison_kind::popped_stack:
- result = std::make_unique<xml::element> ("popped-stack", false);
- break;
- }
- }
- break;
- case SK_SETJMP:
- {
- //const setjmp_svalue *setjmp_sval = (const setjmp_svalue *)sval;
- result = std::make_unique<xml::element> ("setjmp-buffer", false);
- // TODO
- }
- break;
- case SK_INITIAL:
- {
- const initial_svalue *initial_sval = (const initial_svalue *)sval;
- result = std::make_unique<xml::element> ("initial-value-of", false);
- set_region_id_attr (*result, *initial_sval->get_region ());
- }
- break;
- case SK_UNARYOP:
- {
- const unaryop_svalue *unaryop_sval = (const unaryop_svalue *)sval;
- result = std::make_unique<xml::element> ("unary-op", false);
- result->set_attr ("op", get_tree_code_name (unaryop_sval->get_op ()));
- result->add_child
- (create_element_for_svalue (unaryop_sval->get_arg ()));
- }
- break;
- case SK_BINOP:
- {
- const binop_svalue *binop_sval = (const binop_svalue *)sval;
- result = std::make_unique<xml::element> ("binary-op", false);
- result->set_attr ("op", get_tree_code_name (binop_sval->get_op ()));
- result->add_child (create_element_for_svalue (binop_sval->get_arg0 ()));
- result->add_child (create_element_for_svalue (binop_sval->get_arg1 ()));
- }
- break;
- case SK_SUB:
- {
- //const sub_svalue *sub_sval = (const sub_svalue *)sval;
- result = std::make_unique<xml::element> ("subregion-value", false);
- // TODO
- }
- break;
- case SK_REPEATED:
- {
- const repeated_svalue *repeated_sval = (const repeated_svalue *)sval;
- result = std::make_unique<xml::element> ("repeated-value", false);
- result->add_child
- (create_element_for_svalue (repeated_sval->get_outer_size ()));
- result->add_child
- (create_element_for_svalue (repeated_sval->get_inner_svalue ()));
- }
- break;
- case SK_BITS_WITHIN:
- {
- const bits_within_svalue *bits_within_sval
- = (const bits_within_svalue *)sval;
- result = std::make_unique<xml::element> ("bits-within", false);
- set_bits_attr (*result, bits_within_sval->get_bits ());
- result->add_child
- (create_element_for_svalue (bits_within_sval->get_inner_svalue ()));
- }
- break;
- case SK_UNMERGEABLE:
- {
- const unmergeable_svalue *unmergeable_sval
- = (const unmergeable_svalue *)sval;
- result = std::make_unique<xml::element> ("unmergeable", false);
- result->add_child
- (create_element_for_svalue (unmergeable_sval->get_arg ()));
- }
- break;
- case SK_PLACEHOLDER:
- {
- const placeholder_svalue *placeholder_sval
- = (const placeholder_svalue *)sval;
- result = std::make_unique<xml::element> ("placeholder", false);
- result->set_attr ("name", placeholder_sval->get_name ());
- }
- break;
- case SK_WIDENING:
- {
- //const widening_svalue *widening_sval = (const widening_svalue *)sval;
- result = std::make_unique<xml::element> ("iterating-value", false);
- // TODO
- }
- break;
- case SK_COMPOUND:
- {
- //const compound_svalue *compound_sval = (const compound_svalue *)sval;
- result = std::make_unique<xml::element> ("compound-value", false);
- // TODO
- }
- break;
- case SK_CONJURED:
- {
- //const conjured_svalue *conjured_sval = (const conjured_svalue *)sval;
- result = std::make_unique<xml::element> ("conjured-value", false);
- // TODO
- }
- break;
- case SK_ASM_OUTPUT:
- {
- /* const asm_output_svalue *asm_output_sval
- = (const asm_output_svalue *)sval; */
- result = std::make_unique<xml::element> ("asm-output", false);
- // TODO
- }
- break;
- case SK_CONST_FN_RESULT:
- {
- /* const const_fn_result_svalue *const_fn_result_sval
- = (const const_fn_result_svalue *)sval; */
- result = std::make_unique<xml::element> ("const-fn-result", false);
- // TODO
- }
- }
-
- if (result)
- {
- if (sval->get_type ())
- set_type_attr (*result, sval->get_type ());
-
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- sval->dump_to_pp (&pp, true);
- result->set_attr ("dump-text", pp_formatted_text (&pp));
- }
-
- return result;
-}
-
-std::unique_ptr<xml::document>
-program_state::make_xml (const extrinsic_state &ext_state) const
-{
- return std::make_unique<xml_state> (*this, ext_state);
-}
-
-void
-program_state::dump_xml_to_pp (const extrinsic_state &ext_state,
- pretty_printer *pp) const
-{
- auto doc = make_xml (ext_state);
- doc->write_as_xml (pp, 0, true);
-}
-
-void
-program_state::dump_xml_to_file (const extrinsic_state &ext_state,
- FILE *outf) const
-{
- pretty_printer pp;
- pp.set_output_stream (outf);
- dump_xml_to_pp (ext_state, &pp);
- pp_flush (&pp);
+ return std::make_unique<analyzer_state_graph> (*this, ext_state);
}
void
-program_state::dump_xml (const extrinsic_state &ext_state) const
+program_state::dump_sarif (const extrinsic_state &ext_state) const
{
- dump_xml_to_file (ext_state, stderr);
+ auto g = make_diagnostic_state_graph (ext_state);
+ g->dump ();
}
} // namespace ana
diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.h b/gcc/analyzer/ana-state-to-diagnostic-state.h
index bd6aa46..186e19d 100644
--- a/gcc/analyzer/ana-state-to-diagnostic-state.h
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.h
@@ -1,4 +1,4 @@
-/* XML documents for dumping state in an easier-to-read form.
+/* Creating diagnostic state graphs from ana::program_state.
Copyright (C) 2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,41 +18,52 @@ 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/>. */
-#ifndef GCC_ANALYZER_ANA_STATE_TO_XML_STATE_H
-#define GCC_ANALYZER_ANA_STATE_TO_XML_STATE_H
+#ifndef GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H
+#define GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H
-#include "xml.h"
+#include "diagnostic-state-graphs.h"
+#include "tree-logical-location.h"
namespace ana {
-class xml_state : public xml::document
+class analyzer_state_graph : public diagnostics::digraphs::digraph
{
public:
- xml_state (const program_state &state,
- const extrinsic_state &ext_state);
-
- xml::element &
- get_or_create_element (const region &reg);
+ analyzer_state_graph (const program_state &state,
+ const extrinsic_state &ext_state);
+ diagnostics::state_graphs::state_node_ref
+ get_or_create_state_node (const region &reg);
private:
- xml::element&
- create_and_add_element (const region &reg);
-
- static std::unique_ptr<xml::element>
- make_memory_space_element (const char *label);
-
- std::unique_ptr<xml::element>
- create_element (const region &reg);
+ struct pending_edge
+ {
+ diagnostics::state_graphs::state_node_ref m_src_node;
+ const region &m_dst_reg;
+ };
+
+ diagnostics::state_graphs::state_node_ref
+ create_and_add_state_node (const region &reg);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ make_state_node (diagnostics::state_graphs::node_kind kind,
+ std::string id);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ make_memspace_state_node (const region &reg,
+ enum diagnostics::state_graphs::node_kind kind);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node (const region &reg);
/* Spatially sorted concrete bindings. */
typedef std::map<bit_range, const svalue *> concrete_bindings_t;
void
- create_elements_for_binding_cluster (const binding_cluster &cluster,
- bool create_all);
+ create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
+ bool create_all);
- std::unique_ptr<xml::element>
- create_element_for_conc_bindings (const concrete_bindings_t &conc_bindings);
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings);
// Try to get the bit_range of REG within its base region
bool
@@ -60,30 +71,36 @@ private:
bit_range &out);
void
- populate_element_for_typed_region (xml::element &e,
- const region &reg,
- const concrete_bindings_t &conc_bindings,
- bool create_all);
+ populate_state_node_for_typed_region (diagnostics::state_graphs::state_node_ref,
+ const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all);
void
- set_attr_for_dynamic_extents (const region &reg, xml::element &e);
+ set_attr_for_dynamic_extents (const region &reg,
+ diagnostics::state_graphs::state_node_ref);
bool
- show_child_element_for_child_region_p (const region &reg,
- const concrete_bindings_t &conc_bindings,
- bool create_all);
+ show_child_state_node_for_child_region_p (const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node_for_svalue (const svalue *sval);
- std::unique_ptr<xml::element>
- create_element_for_svalue (const svalue *sval);
+ std::string make_node_id (const region &reg);
+ std::string make_node_id (const char *prefix);
+ tree_logical_location_manager m_logical_loc_mgr;
const program_state &m_state;
const extrinsic_state &m_ext_state;
region_model_manager &m_mgr;
- xml::element *m_root;
- std::map<const region *, xml::element *> m_region_to_element_map;
+ std::map<const region *, diagnostics::digraphs::node *> m_region_to_state_node_map;
std::map<const region *, tree> m_types_for_untyped_regions;
+ unsigned m_next_id;
+ std::vector<pending_edge> m_pending_edges;
};
} // namespace ana
-#endif /* GCC_ANALYZER_ANA_STATE_TO_XML_STATE_H */
+#endif /* GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H */
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index af336df..8cc5ac2 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "inlining-iterator.h"
#include "tree-logical-location.h"
#include "diagnostic-format-sarif.h"
-#include "xml.h"
+#include "diagnostic-state-graphs.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
@@ -225,8 +225,8 @@ checker_event::prepare_for_emission (checker_path *path,
print_desc (*pp.get ());
}
-std::unique_ptr<xml::document>
-checker_event::maybe_make_xml_state (bool debug) const
+std::unique_ptr<diagnostics::digraphs::digraph>
+checker_event::maybe_make_diagnostic_state_graph (bool debug) const
{
const program_state *state = get_program_state ();
if (!state)
@@ -235,14 +235,16 @@ checker_event::maybe_make_xml_state (bool debug) const
gcc_assert (m_path);
const extrinsic_state &ext_state = m_path->get_ext_state ();
- auto result = state->make_xml (ext_state);
+ auto result = state->make_diagnostic_state_graph (ext_state);
if (debug)
{
pretty_printer pp;
text_art::theme *theme = global_dc->get_diagram_theme ();
text_art::dump_to_pp (*state, theme, &pp);
- result->add_comment (pp_formatted_text (&pp));
+ result->set_attr (STATE_GRAPH_PREFIX,
+ "analyzer/program_state/",
+ pp_formatted_text (&pp));
}
return result;
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index 7c44f1e..cf24e77 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-logical-location.h"
#include "analyzer/program-state.h"
#include "analyzer/event-loc-info.h"
+#include "diagnostic-digraphs.h"
namespace ana {
@@ -128,12 +129,12 @@ public:
virtual bool is_function_entry_p () const { return false; }
virtual bool is_return_p () const { return false; }
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ maybe_make_diagnostic_state_graph (bool debug) const final override;
+
virtual const program_state *
get_program_state () const { return nullptr; }
- std::unique_ptr<xml::document>
- maybe_make_xml_state (bool debug) const final override;
-
/* For use with %@. */
const diagnostic_event_id_t *get_id_ptr () const
{
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 67024e9..745ef7e 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1580,9 +1580,9 @@ exploded_node::on_stmt_pre (exploded_graph &eg,
state->dump (eg.get_ext_state (), true);
return;
}
- else if (is_special_named_call_p (call, "__analyzer_dump_xml", 0))
+ else if (is_special_named_call_p (call, "__analyzer_dump_sarif", 0))
{
- state->dump_xml (eg.get_ext_state ());
+ state->dump_sarif (eg.get_ext_state ());
return;
}
else if (is_special_named_call_p (call, "__analyzer_dump_dot", 0))
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index c0befac..85cbe75 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "digraph.h"
#include "diagnostic-event-id.h"
-#include "diagnostic-state.h"
+#include "diagnostic-state-graphs.h"
#include "graphviz.h"
#include "text-art/tree-widget.h"
@@ -1230,8 +1230,14 @@ program_state::make_dump_widget (const text_art::dump_widget_info &dwi) const
void
program_state::dump_dot (const extrinsic_state &ext_state) const
{
- auto doc = make_xml (ext_state);
- auto graph = make_dot_graph_from_xml_state (*doc);
+ auto state_graph = make_diagnostic_state_graph (ext_state);
+
+ gcc_assert (global_dc);
+ auto logical_loc_mgr = global_dc->get_logical_location_manager ();
+ gcc_assert (logical_loc_mgr);
+
+ auto graph = diagnostics::state_graphs::make_dot_graph (*state_graph,
+ *logical_loc_mgr);
pretty_printer pp;
dot::writer w (pp);
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index e2076c1..4278237 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -26,8 +26,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
-namespace xml { class document; }
-
namespace ana {
/* Data shared by all program_state instances. */
@@ -248,11 +246,14 @@ public:
void dump (const extrinsic_state &ext_state, bool simple) const;
void dump () const;
- std::unique_ptr<xml::document> make_xml (const extrinsic_state &ext_state) const;
- void dump_xml_to_pp (const extrinsic_state &ext_state, pretty_printer *pp) const;
- void dump_xml_to_file (const extrinsic_state &ext_state, FILE *outf) const;
- void dump_xml (const extrinsic_state &ext_state) const;
- void dump_dot (const extrinsic_state &ext_state) const;
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ make_diagnostic_state_graph (const extrinsic_state &ext_state) const;
+
+ void
+ dump_sarif (const extrinsic_state &ext_state) const;
+
+ void
+ dump_dot (const extrinsic_state &ext_state) const;
std::unique_ptr<json::object>
to_json (const extrinsic_state &ext_state) const;
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 3581dbb..2a218d0 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -436,9 +436,9 @@ public:
const extrinsic_state &ext_state) const;
void
- add_state_to_xml (xml_state &out_xml,
- const svalue &sval,
- state_machine::state_t state) const final override;
+ add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const final override;
standard_deallocator_set m_free;
standard_deallocator_set m_scalar_delete;
@@ -2735,27 +2735,57 @@ malloc_state_machine::transition_ptr_sval_non_null (region_model *model,
smap->set_state (model, new_ptr_sval, m_free.m_nonnull, nullptr, ext_state);
}
+static enum diagnostics::state_graphs::node_dynalloc_state
+get_dynalloc_state_for_state (enum resource_state rs)
+{
+ switch (rs)
+ {
+ default:
+ gcc_unreachable ();
+ case RS_START:
+ case RS_NULL:
+ case RS_NON_HEAP:
+ case RS_STOP:
+ return diagnostics::state_graphs::node_dynalloc_state::unknown;
+
+ case RS_ASSUMED_NON_NULL:
+ return diagnostics::state_graphs::node_dynalloc_state::nonnull;
+
+ case RS_UNCHECKED:
+ return diagnostics::state_graphs::node_dynalloc_state::unchecked;
+ case RS_NONNULL:
+ return diagnostics::state_graphs::node_dynalloc_state::nonnull;
+ case RS_FREED:
+ return diagnostics::state_graphs::node_dynalloc_state::freed;
+ }
+}
+
void
-malloc_state_machine::add_state_to_xml (xml_state &out_xml,
- const svalue &sval,
- state_machine::state_t state) const
+malloc_state_machine::
+add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const
{
if (const region *reg = sval.maybe_get_region ())
{
- auto &reg_element = out_xml.get_or_create_element (*reg);
+ auto reg_node = out_state_graph.get_or_create_state_node (*reg);
auto alloc_state = as_a_allocation_state (state);
gcc_assert (alloc_state);
- reg_element.set_attr ("dynamic-alloc-state", state->get_name ());
+ reg_node.set_dynalloc_state
+ (get_dynalloc_state_for_state (alloc_state->m_rs));
if (alloc_state->m_deallocators)
{
pretty_printer pp;
alloc_state->m_deallocators->dump_to_pp (&pp);
- reg_element.set_attr ("expected-deallocators", pp_formatted_text (&pp));
+ reg_node.m_node.set_attr (STATE_NODE_PREFIX,
+ "expected-deallocators",
+ pp_formatted_text (&pp));
}
if (alloc_state->m_deallocator)
- reg_element.set_attr ("deallocator",
- alloc_state->m_deallocator->m_name);
+ reg_node.m_node.set_attr (STATE_NODE_PREFIX,
+ "deallocator",
+ alloc_state->m_deallocator->m_name);
}
}
diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc
index 840806a..c93e9c2 100644
--- a/gcc/analyzer/sm.cc
+++ b/gcc/analyzer/sm.cc
@@ -161,16 +161,16 @@ state_machine::to_json () const
}
void
-state_machine::add_state_to_xml (xml_state &out_xml,
- const svalue &sval,
- state_machine::state_t state) const
+state_machine::add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const
{
// no-op
}
void
-state_machine::add_global_state_to_xml (xml_state &out_xml,
- state_machine::state_t state) const
+state_machine::add_global_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ state_machine::state_t state) const
{
// no-op
}
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
index 6298fb6..4633fac 100644
--- a/gcc/analyzer/sm.h
+++ b/gcc/analyzer/sm.h
@@ -28,7 +28,7 @@ namespace ana {
class state_machine;
class sm_context;
class pending_diagnostic;
-class xml_state;
+class analyzer_state_graph;
extern bool any_pointer_p (tree expr);
extern bool any_pointer_p (const svalue *sval);
@@ -188,13 +188,13 @@ public:
state_t get_start_state () const { return m_start; }
virtual void
- add_state_to_xml (xml_state &out_xml,
- const svalue &sval,
- state_machine::state_t state) const;
+ add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const;
virtual void
- add_global_state_to_xml (xml_state &out_xml,
- state_machine::state_t state) const;
+ add_global_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ state_machine::state_t state) const;
protected:
state_t add_state (const char *name);
diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc
index 5226e455..d1954b4 100644
--- a/gcc/auto-profile.cc
+++ b/gcc/auto-profile.cc
@@ -240,6 +240,8 @@ public:
/* Add new name and return its index. */
int add_name (char *);
+ /* Return cgraph node corresponding to given name index. */
+ cgraph_node *get_cgraph_node (int);
private:
typedef std::map<const char *, unsigned, string_compare> string_index_map;
string_vector vector_;
@@ -445,7 +447,6 @@ public:
/* Lookup count and warn about duplicates. */
count_info *lookup_count (location_t loc, inline_stack &stack,
cgraph_node *node);
-
private:
/* Callsite, represented as (decl_lineno, callee_function_name_index). */
typedef std::pair<unsigned, unsigned> callsite;
@@ -888,21 +889,13 @@ string_table::read ()
return true;
}
-/* Member functions for function_instance. */
-
-function_instance::~function_instance ()
-{
- gcc_assert (!in_worklist_p ());
- for (callsite_map::iterator iter = callsites.begin ();
- iter != callsites.end (); ++iter)
- delete iter->second;
-}
-
-/* Return corresponding cgraph node, NULL if unavailable. */
+/* Return cgraph node corresponding to given NAME_INDEX,
+ NULL if unavailable. */
cgraph_node *
-function_instance::get_cgraph_node ()
+string_table::get_cgraph_node (int name_index)
{
- const char *sname = afdo_string_table->get_name (name ());
+ const char *sname = get_name (name_index);
+
symtab_node *n = cgraph_node::get_for_asmname (get_identifier (sname));
for (;n; n = n->next_sharing_asm_name)
if (cgraph_node *cn = dyn_cast <cgraph_node *> (n))
@@ -911,6 +904,24 @@ function_instance::get_cgraph_node ()
return NULL;
}
+/* Return corresponding cgraph node. */
+
+cgraph_node *
+function_instance::get_cgraph_node ()
+{
+ return afdo_string_table->get_cgraph_node (name ());
+}
+
+/* Member functions for function_instance. */
+
+function_instance::~function_instance ()
+{
+ gcc_assert (!in_worklist_p ());
+ for (callsite_map::iterator iter = callsites.begin ();
+ iter != callsites.end (); ++iter)
+ delete iter->second;
+}
+
/* Traverse callsites of the current function_instance to find one at the
location of LINENO and callee name represented in DECL. */
@@ -1169,7 +1180,7 @@ match_with_target (cgraph_node *n,
}
/* Accept dwarf names and stripped suffixes. */
if (!strcmp (lang_hooks.dwarf_name (callee->decl, 0),
- afdo_string_table->get_name (inlined_fn->name ()))
+ afdo_string_table->get_name (inlined_fn->name ()))
|| (!name[i] && symbol_name[i] == '.')
|| in_suffix)
{
@@ -1183,8 +1194,8 @@ match_with_target (cgraph_node *n,
inlined_fn->set_name (index);
return 2;
}
- /* Only warn about declarations. It is possible that the function is
- declared as alias in other module and we inlined cross-module. */
+ /* Only warn about declarations. It is possible that the function
+ is declared as alias in other module and we inlined cross-module. */
if (callee->definition
&& warning (OPT_Wauto_profile,
"auto-profile of %q+F contains inlined "
@@ -1491,8 +1502,8 @@ function_instance::match (cgraph_node *node,
== inlined_fn);
callsite key2 = {stack[0].afdo_loc,
inlined_fn->name ()};
- callsites[key2] = inlined_fn;
callsites.erase (iter);
+ callsites[key2] = inlined_fn;
}
if (r)
functions.add (inlined_fn);
@@ -1554,10 +1565,10 @@ function_instance::match (cgraph_node *node,
callsite key2 = {stack[0].afdo_loc,
newn ? *newn
: inlined_fn->name ()};
+ callsites.erase (iter);
callsites[key2] = inlined_fn;
inlined_fn->set_name (newn ? *newn
: inlined_fn->name ());
- callsites.erase (iter);
}
functions.add (inlined_fn);
}
@@ -1690,7 +1701,6 @@ function_instance::match (cgraph_node *node,
f->dump_inline_stack (dump_file);
fprintf (dump_file, "\n");
}
- warned = true;
callsites.erase (iter);
offline (f, new_functions);
iter = callsites.begin ();
@@ -1752,9 +1762,9 @@ function_instance::remove_external_functions
auto iter = callsites.find (key);
callsite key2 = key;
key2.second = *to_symbol_name.get (key.second);
- callsites[key2] = iter->second;
iter->second->set_name (key2.second);
callsites.erase (iter);
+ callsites[key2] = iter->second;
}
auto_vec <int, 20> target_to_rename;
for (auto &iter : pos_counts)
@@ -1951,6 +1961,7 @@ autofdo_source_profile::offline_external_functions ()
cgraph_node *node;
name_index_set seen;
name_index_map to_symbol_name;
+ size_t last_name;
/* Add renames erasing suffixes produced by late clones, such as
.isra, .ipcp. */
@@ -1986,10 +1997,10 @@ autofdo_source_profile::offline_external_functions ()
index = afdo_string_table->add_name (n2);
to_symbol_name.put (i, index);
}
+ last_name = afdo_string_table->num_entries ();
FOR_EACH_DEFINED_FUNCTION (node)
{
- const char *name
- = raw_symbol_name (node->decl);
+ const char *name = raw_symbol_name (node->decl);
const char *dwarf_name = lang_hooks.dwarf_name (node->decl, 0);
int index = afdo_string_table->get_index (name);
@@ -2026,11 +2037,17 @@ autofdo_source_profile::offline_external_functions ()
{
if (dump_file)
{
- fprintf (dump_file,
- "Node %s not in auto profile (%s neither %s)\n",
- node->dump_name (),
- name,
- dwarf_name);
+ if (dwarf_name && strcmp (dwarf_name, name))
+ fprintf (dump_file,
+ "Node %s not in auto profile (%s neither %s)\n",
+ node->dump_name (),
+ name,
+ dwarf_name);
+ else
+ fprintf (dump_file,
+ "Node %s (symbol %s) not in auto profile\n",
+ node->dump_name (),
+ name);
}
}
}
@@ -2074,72 +2091,87 @@ autofdo_source_profile::offline_external_functions ()
should be done on unmodified profile and merging works better if
mismatches are already resolved both in source and destination. */
while (fns.length () || fns2.length ())
- if (fns.length ())
- {
- function_instance *f = fns.pop ();
- if (f->get_location () == UNKNOWN_LOCATION)
- {
- int index = f->name ();
- int *newn = to_symbol_name.get (index);
- if (newn)
- {
- f->set_name (*newn);
- if (map_.count (index)
- && map_[index] == f)
- map_.erase (index);
- if (!map_.count (*newn))
- map_[*newn] = f;
- }
- if (cgraph_node *n = f->get_cgraph_node ())
- {
- gcc_checking_assert (seen.contains (f->name ()));
- f->match (n, fns, to_symbol_name);
- }
- }
- fns2.safe_push (f);
- }
- else
- {
- function_instance *f = fns2.pop ();
- int index = f->name ();
- gcc_checking_assert (f->in_worklist_p ());
+ {
+ /* In case renaming introduced new name, keep seen up to date. */
+ for (; last_name < afdo_string_table->num_entries (); last_name++)
+ {
+ const char *name = afdo_string_table->get_name (last_name);
+ symtab_node *n
+ = afdo_string_table->get_cgraph_node (last_name);
+ if (dump_file)
+ fprintf (dump_file, "New name %s %s\n", name,
+ n ? "wth corresponding definition"
+ : "with no corresponding definition");
+ if (n)
+ seen.add (last_name);
+ }
+ if (fns.length ())
+ {
+ function_instance *f = fns.pop ();
+ if (f->get_location () == UNKNOWN_LOCATION)
+ {
+ int index = f->name ();
+ int *newn = to_symbol_name.get (index);
+ if (newn)
+ {
+ f->set_name (*newn);
+ if (map_.count (index)
+ && map_[index] == f)
+ map_.erase (index);
+ if (!map_.count (*newn))
+ map_[*newn] = f;
+ }
+ if (cgraph_node *n = f->get_cgraph_node ())
+ {
+ gcc_checking_assert (seen.contains (f->name ()));
+ f->match (n, fns, to_symbol_name);
+ }
+ }
+ fns2.safe_push (f);
+ }
+ else
+ {
+ function_instance *f = fns2.pop ();
+ int index = f->name ();
+ gcc_checking_assert (f->in_worklist_p ());
- /* If map has different function_instance of same name, then
- this is a duplicated entry which needs to be merged. */
- if (map_.count (index) && map_[index] != f)
- {
- if (dump_file)
- {
- fprintf (dump_file, "Merging duplicate instance: ");
- f->dump_inline_stack (dump_file);
- fprintf (dump_file, "\n");
- }
- map_[index]->merge (f, fns);
- gcc_checking_assert (!f->inlined_to ());
- f->clear_in_worklist ();
- delete f;
- }
- /* If name was not seen in the symbol table, remove it. */
- else if (!seen.contains (index))
- {
- f->offline_if_in_set (seen, fns);
- f->clear_in_worklist ();
- if (dump_file)
- fprintf (dump_file, "Removing external %s\n",
- afdo_string_table->get_name (f->name ()));
- if (map_.count (index) && map_[index] == f)
- map_.erase (f->name ());
- delete f;
- }
- /* If this is offline function instance seen in this
- translation unit offline external inlines and possibly
- rename from dwarf name. */
- else
- {
- f->remove_external_functions (seen, to_symbol_name, fns);
- f->clear_in_worklist ();
- }
- }
+ /* If map has different function_instance of same name, then
+ this is a duplicated entry which needs to be merged. */
+ if (map_.count (index) && map_[index] != f)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Merging duplicate instance: ");
+ f->dump_inline_stack (dump_file);
+ fprintf (dump_file, "\n");
+ }
+ map_[index]->merge (f, fns);
+ gcc_checking_assert (!f->inlined_to ());
+ f->clear_in_worklist ();
+ delete f;
+ }
+ /* If name was not seen in the symbol table, remove it. */
+ else if (!seen.contains (index))
+ {
+ f->offline_if_in_set (seen, fns);
+ f->clear_in_worklist ();
+ if (dump_file)
+ fprintf (dump_file, "Removing external %s\n",
+ afdo_string_table->get_name (f->name ()));
+ if (map_.count (index) && map_[index] == f)
+ map_.erase (f->name ());
+ delete f;
+ }
+ /* If this is offline function instance seen in this
+ translation unit offline external inlines and possibly
+ rename from dwarf name. */
+ else
+ {
+ f->remove_external_functions (seen, to_symbol_name, fns);
+ f->clear_in_worklist ();
+ }
+ }
+ }
if (dump_file)
for (auto const &iter : map_)
{
@@ -2288,7 +2320,7 @@ autofdo_source_profile::offline_unrealized_inlines ()
function_instance *
function_instance::read_function_instance (function_instance_stack *stack,
- gcov_type head_count)
+ gcov_type head_count)
{
unsigned name = gcov_read_unsigned ();
unsigned num_pos_counts = gcov_read_unsigned ();
@@ -2311,10 +2343,10 @@ function_instance::read_function_instance (function_instance_stack *stack,
(*stack)[j]->total_count_ += count;
for (unsigned j = 0; j < num_targets; j++)
{
- /* Only indirect call target histogram is supported now. */
- gcov_read_unsigned ();
- gcov_type target_idx = gcov_read_counter ();
- s->pos_counts[offset].targets[target_idx] = gcov_read_counter ();
+ /* Only indirect call target histogram is supported now. */
+ gcov_read_unsigned ();
+ gcov_type target_idx = gcov_read_counter ();
+ s->pos_counts[offset].targets[target_idx] = gcov_read_counter ();
}
}
for (unsigned i = 0; i < num_callsites; i++)
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index a95cc34..ed79d36 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,13 @@
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119064
+ * c.opt (Wc++26-compat): New option.
+ * c.opt.urls: Regenerate.
+ * c-opts.cc (c_common_post_options): Clear warn_cxx26_compat for
+ C++26 or later.
+ * c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine
+ __cpp_trivial_relocatability=202502L.
+
2025-07-10 Jakub Jelinek <jakub@redhat.com>
PR c++/117785
diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog
index 5affc84..5555b8e 100644
--- a/gcc/cobol/ChangeLog
+++ b/gcc/cobol/ChangeLog
@@ -1,3 +1,12 @@
+2025-07-11 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR cobol/120621
+ * lexio.cc (parse_replace_pairs): Cast mfile.lineno() to fmt_size_t.
+ * parse.y (intrinsic): Print ptrdiff_t using %ld, cast arg to long.
+ * scan_ante.h (numstr_of): Print nx using %ld, cast arg to long.
+ * util.cc (cbl_field_t::report_invalid_initial_value): Print
+ ptrdiff_t using %ld, cast arg to long.
+
2025-07-10 James K. Lowden <jklowden@cobolworx.com>
PR cobol/120765
diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md
index 7920232..29a8cb5 100644
--- a/gcc/config/i386/mmx.md
+++ b/gcc/config/i386/mmx.md
@@ -329,7 +329,7 @@
(define_expand "mov<mode>"
[(set (match_operand:V_32 0 "nonimmediate_operand")
- (match_operand:V_32 1 "nonimmediate_operand"))]
+ (match_operand:V_32 1 "nonimm_or_0_operand"))]
""
{
ix86_expand_vector_move (<MODE>mode, operands);
@@ -339,7 +339,7 @@
(define_insn "*mov<mode>_internal"
[(set (match_operand:V_32 0 "nonimmediate_operand"
"=r ,m ,v,v,v,m,r,v")
- (match_operand:V_32 1 "general_operand"
+ (match_operand:V_32 1 "nonimm_or_0_operand"
"rmC,rC,C,v,m,v,v,r"))]
"!(MEM_P (operands[0]) && MEM_P (operands[1]))
&& ix86_hardreg_mov_ok (operands[0], operands[1])"
@@ -457,7 +457,7 @@
(define_expand "movv2qi"
[(set (match_operand:V2QI 0 "nonimmediate_operand")
- (match_operand:V2QI 1 "nonimmediate_operand"))]
+ (match_operand:V2QI 1 "nonimm_or_0_operand"))]
""
{
ix86_expand_vector_move (V2QImode, operands);
@@ -467,9 +467,10 @@
(define_insn "*movv2qi_internal"
[(set (match_operand:V2QI 0 "nonimmediate_operand"
"=r,r,r,m ,v,v,v,jm,m,r,v")
- (match_operand:V2QI 1 "general_operand"
+ (match_operand:V2QI 1 "nonimm_or_0_operand"
"r ,C,m,rC,C,v,m,x,v,v,r"))]
- "!(MEM_P (operands[0]) && MEM_P (operands[1]))"
+ "!(MEM_P (operands[0]) && MEM_P (operands[1]))
+ && ix86_hardreg_mov_ok (operands[0], operands[1])"
{
switch (get_attr_type (insn))
{
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2944f22..b0928d0 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,41 @@
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119064
+ * cp-tree.h: Implement C++26 P2786R13 - Trivial Relocatability.
+ (struct lang_type): Add trivially_relocatable,
+ trivially_relocatable_computed, replaceable and replaceable_computed
+ bitfields. Change width of dummy from 2 to 30.
+ (CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT,
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, CLASSTYPE_REPLACEABLE_BIT,
+ CLASSTYPE_REPLACEABLE_COMPUTED): Define.
+ (enum virt_specifier): Add VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
+ and VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE enumerators.
+ (trivially_relocatable_type_p, replaceable_type_p): Declare.
+ * cp-trait.def (IS_NOTHROW_RELOCATABLE, IS_REPLACEABLE,
+ IS_TRIVIALLY_RELOCATABLE): New traits.
+ * parser.cc (cp_parser_class_property_specifier_seq_opt): Handle
+ trivially_relocatable_if_eligible,
+ __trivially_relocatable_if_eligible, replaceable_if_eligible and
+ __replaceable_if_eligible.
+ (cp_parser_class_head): Set CLASSTYPE_REPLACEABLE_BIT
+ and/or CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT if corresponding
+ conditional keywords were parsed and assert corresponding *_COMPUTED
+ macro is false.
+ * pt.cc (instantiate_class_template): Copy over also
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_{BIT,COMPUTED} and
+ CLASSTYPE_REPLACEABLE_{BIT,COMPUTED} bits.
+ * semantics.cc (referenceable_type_p): Move definition earlier.
+ (trait_expr_value): Handle CPTK_IS_NOTHROW_RELOCATABLE,
+ CPTK_IS_REPLACEABLE and CPTK_IS_TRIVIALLY_RELOCATABLE.
+ (finish_trait_expr): Likewise.
+ * tree.cc (default_movable_type_p): New function.
+ (union_with_no_declared_special_member_fns): Likewise.
+ (trivially_relocatable_type_p): Likewise.
+ (replaceable_type_p): Likewise.
+ * constraint.cc (diagnose_trait_expr): Handle
+ CPTK_IS_NOTHROW_RELOCATABLE, CPTK_IS_REPLACEABLE and
+ CPTK_IS_TRIVIALLY_RELOCATABLE.
+
2025-07-10 Jakub Jelinek <jakub@redhat.com>
* cp-tree.h (struct lang_type): Add comment before key_method.
diff --git a/gcc/diagnostic-digraphs.cc b/gcc/diagnostic-digraphs.cc
new file mode 100644
index 0000000..85c0c51
--- /dev/null
+++ b/gcc/diagnostic-digraphs.cc
@@ -0,0 +1,484 @@
+/* Directed graphs associated with a diagnostic.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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/>. */
+
+#define INCLUDE_ALGORITHM
+#define INCLUDE_MAP
+#define INCLUDE_SET
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "graphviz.h"
+#include "diagnostic-digraphs.h"
+#include "diagnostic-format-sarif.h"
+
+#include "selftest.h"
+
+using digraph = diagnostics::digraphs::digraph;
+using digraph_node = diagnostics::digraphs::node;
+using digraph_edge = diagnostics::digraphs::edge;
+
+namespace {
+
+class conversion_to_dot
+{
+public:
+ std::unique_ptr<dot::graph>
+ make_dot_graph_from_diagnostic_graph (const digraph &);
+
+ std::unique_ptr<dot::stmt>
+ make_dot_node_from_digraph_node (const digraph_node &);
+
+ std::unique_ptr<dot::edge_stmt>
+ make_dot_edge_from_digraph_edge (const digraph_edge &);
+
+ dot::id
+ get_dot_id_for_node (const digraph_node &);
+
+ bool
+ has_edges_p (const digraph_node &);
+
+private:
+ std::set<const digraph_node *> m_nodes_with_edges;
+ std::map<const digraph_node *, dot::stmt *> m_node_map;
+};
+
+} // anonymous namespace
+
+// class conversion_to_dot
+
+std::unique_ptr<dot::graph>
+conversion_to_dot::
+make_dot_graph_from_diagnostic_graph (const diagnostics::digraphs::digraph &input_graph)
+{
+ auto output_graph = std::make_unique<dot::graph> ();
+
+ if (const char *description = input_graph.get_description ())
+ output_graph->m_stmt_list.add_attr (dot::id ("label"),
+ dot::id (description));
+
+ const int num_nodes = input_graph.get_num_nodes ();
+ const int num_edges = input_graph.get_num_edges ();
+
+ /* Determine which nodes have in-edges and out-edges. */
+ for (int i = 0; i < num_edges; ++i)
+ {
+ const digraph_edge &input_edge = input_graph.get_edge (i);
+ m_nodes_with_edges.insert (&input_edge.get_src_node ());
+ m_nodes_with_edges.insert (&input_edge.get_dst_node ());
+ }
+
+ for (int i = 0; i < num_nodes; ++i)
+ {
+ const digraph_node &input_node = input_graph.get_node (i);
+ auto dot_node_stmt = make_dot_node_from_digraph_node (input_node);
+ output_graph->m_stmt_list.add_stmt (std::move (dot_node_stmt));
+ }
+
+ for (int i = 0; i < num_edges; ++i)
+ {
+ const digraph_edge &input_edge = input_graph.get_edge (i);
+ auto dot_edge_stmt = make_dot_edge_from_digraph_edge (input_edge);
+ output_graph->m_stmt_list.add_stmt (std::move (dot_edge_stmt));
+ }
+
+ return output_graph;
+}
+
+std::unique_ptr<dot::stmt>
+conversion_to_dot::
+make_dot_node_from_digraph_node (const diagnostics::digraphs::node &input_node)
+{
+ dot::id dot_id (get_dot_id_for_node (input_node));
+
+ /* For now, we can only do either edges or children, not both
+ ...but see https://graphviz.org/docs/attrs/compound/ */
+
+ if (has_edges_p (input_node))
+ {
+ auto output_node
+ = std::make_unique<dot::node_stmt> (std::move (dot_id));
+ m_node_map[&input_node] = output_node.get ();
+ if (const char *label = input_node.get_label ())
+ output_node->set_label (dot::id (label));
+ return output_node;
+ }
+ else
+ {
+ auto output_node = std::make_unique<dot::subgraph> (std::move (dot_id));
+ m_node_map[&input_node] = output_node.get ();
+ if (const char *label = input_node.get_label ())
+ output_node->add_attr (dot::id ("label"), dot::id (label));
+ const int num_children = input_node.get_num_children ();
+ for (int i = 0; i < num_children; ++i)
+ {
+ const digraph_node &input_child = input_node.get_child (i);
+ auto dot_child_stmt = make_dot_node_from_digraph_node (input_child);
+ output_node->m_stmt_list.add_stmt (std::move (dot_child_stmt));
+ }
+ return output_node;
+ }
+}
+
+std::unique_ptr<dot::edge_stmt>
+conversion_to_dot::
+make_dot_edge_from_digraph_edge (const digraph_edge &input_edge)
+{
+ const digraph_node &src_dnode = input_edge.get_src_node ();
+ const digraph_node &dst_dnode = input_edge.get_dst_node ();
+ auto output_edge
+ = std::make_unique<dot::edge_stmt>
+ (get_dot_id_for_node (src_dnode),
+ get_dot_id_for_node (dst_dnode));
+ if (const char *label = input_edge.get_label ())
+ output_edge->set_label (dot::id (label));
+ return output_edge;
+}
+
+dot::id
+conversion_to_dot::get_dot_id_for_node (const digraph_node &input_node)
+{
+ if (has_edges_p (input_node))
+ return input_node.get_id ();
+ else
+ return std::string ("cluster_") + input_node.get_id ();
+}
+
+bool
+conversion_to_dot::has_edges_p (const digraph_node &input_node)
+{
+ return m_nodes_with_edges.find (&input_node) != m_nodes_with_edges.end ();
+}
+
+// class object
+
+const char *
+diagnostics::digraphs::object::
+get_attr (const char *key_prefix, const char *key) const
+{
+ if (!m_property_bag)
+ return nullptr;
+ std::string prefixed_key = std::string (key_prefix) + key;
+ if (json::value *jv = m_property_bag->get (prefixed_key.c_str ()))
+ if (json::string *jstr = jv->dyn_cast_string ())
+ return jstr->get_string ();
+ return nullptr;
+}
+
+void
+diagnostics::digraphs::object::
+set_attr (const char *key_prefix, const char *key, const char *value)
+{
+ set_json_attr (key_prefix, key, std::make_unique<json::string> (value));
+}
+
+void
+diagnostics::digraphs::object::
+set_json_attr (const char *key_prefix, const char *key, std::unique_ptr<json::value> value)
+{
+ std::string prefixed_key = std::string (key_prefix) + key;
+ if (!m_property_bag)
+ m_property_bag = std::make_unique<json::object> ();
+ m_property_bag->set (prefixed_key.c_str (), std::move (value));
+}
+
+// class digraph
+
+DEBUG_FUNCTION void
+diagnostics::digraphs::digraph::dump () const
+{
+ make_json_sarif_graph ()->dump ();
+}
+
+std::unique_ptr<json::object>
+diagnostics::digraphs::digraph::make_json_sarif_graph () const
+{
+ return make_sarif_graph (*this, nullptr, nullptr);
+}
+
+std::unique_ptr<dot::graph>
+diagnostics::digraphs::digraph::make_dot_graph () const
+{
+ conversion_to_dot to_dot;
+ return to_dot.make_dot_graph_from_diagnostic_graph (*this);
+}
+
+std::unique_ptr<diagnostics::digraphs::digraph>
+diagnostics::digraphs::digraph::clone () const
+{
+ auto result = std::make_unique<diagnostics::digraphs::digraph> ();
+
+ if (get_property_bag ())
+ result->set_property_bag (get_property_bag ()->clone_as_object ());
+
+ std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> node_mapping;
+
+ for (auto &iter : m_nodes)
+ result->add_node (iter->clone (*result, node_mapping));
+ for (auto &iter : m_edges)
+ result->add_edge (iter->clone (*result, node_mapping));
+
+ return result;
+}
+
+void
+diagnostics::digraphs::digraph::add_edge (const char *id,
+ node &src_node,
+ node &dst_node,
+ const char *label)
+{
+ auto e = std::make_unique<digraph_edge> (*this,
+ id,
+ src_node,
+ dst_node);
+ if (label)
+ e->set_label (label);
+ add_edge (std::move (e));
+}
+
+/* Utility function for edge ids: either use EDGE_ID, or
+ generate a unique one for when we don't care about the name.
+
+ Edges in SARIF "SHALL" have an id that's unique within the graph
+ (SARIF 2.1.0 §3.41.2). This is so that graph traversals can refer
+ to edges by id (SARIF 2.1.0's §3.43.2 edgeId property). */
+
+std::string
+diagnostics::digraphs::digraph::make_edge_id (const char *edge_id)
+{
+ /* If we have an id, use it. */
+ if (edge_id)
+ return edge_id;
+
+ /* Otherwise, generate a unique one of the form "edgeN". */
+ while (true)
+ {
+ auto candidate (std::string ("edge")
+ + std::to_string (m_next_edge_id_index++));
+ auto iter = m_id_to_edge_map.find (candidate);
+ if (iter != m_id_to_edge_map.end ())
+ {
+ // Try again with the next index...
+ continue;
+ }
+ return candidate;
+ }
+}
+
+// class node
+
+DEBUG_FUNCTION void
+diagnostics::digraphs::node::dump () const
+{
+ to_json_sarif_node ()->dump ();
+}
+
+std::unique_ptr<json::object>
+diagnostics::digraphs::node::to_json_sarif_node () const
+{
+ return make_sarif_node (*this, nullptr, nullptr);
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+diagnostics::digraphs::node::clone (digraph &new_graph,
+ std::map<node *, node *> &node_mapping) const
+{
+ auto result
+ = std::make_unique<diagnostics::digraphs::node> (new_graph,
+ get_id ());
+ node_mapping.insert ({const_cast <node *> (this), result.get ()});
+
+ result->set_logical_loc (m_logical_loc);
+
+ if (get_property_bag ())
+ result->set_property_bag (get_property_bag ()->clone_as_object ());
+
+ for (auto &iter : m_children)
+ result->add_child (iter->clone (new_graph, node_mapping));
+
+ return result;
+}
+
+// class edge
+
+std::unique_ptr<digraph_edge>
+digraph_edge::clone (digraph &new_graph,
+ const std::map<node *, node *> &node_mapping) const
+{
+ auto iter_new_src = node_mapping.find (&m_src_node);
+ gcc_assert (iter_new_src != node_mapping.end ());
+ auto iter_new_dst = node_mapping.find (&m_dst_node);
+ gcc_assert (iter_new_dst != node_mapping.end ());
+ auto result
+ = std::make_unique<digraph_edge> (new_graph,
+ m_id.c_str (),
+ *iter_new_src->second,
+ *iter_new_dst->second);
+ if (get_property_bag ())
+ result->set_property_bag (get_property_bag ()->clone_as_object ());
+
+ return result;
+}
+
+DEBUG_FUNCTION void
+diagnostics::digraphs::edge::dump () const
+{
+ to_json_sarif_edge ()->dump ();
+}
+
+std::unique_ptr<json::object>
+diagnostics::digraphs::edge::to_json_sarif_edge () const
+{
+ return make_sarif_edge (*this, nullptr);
+}
+
+// class lazy_digraph
+
+const diagnostics::digraphs::digraph &
+diagnostics::digraphs::lazy_digraph::get_or_create_digraph () const
+{
+ if (!m_digraph)
+ m_digraph = create_digraph ();
+ gcc_assert (m_digraph);
+ return *m_digraph;
+}
+
+// class lazy_digraphs
+
+const std::vector<std::unique_ptr<diagnostics::digraphs::digraph>> &
+diagnostics::digraphs::lazy_digraphs::get_or_create_digraphs () const
+{
+ if (!m_digraphs)
+ m_digraphs = create_digraphs ();
+ gcc_assert (m_digraphs);
+ return *m_digraphs;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+test_empty_graph ()
+{
+ digraph g;
+
+ {
+ auto sarif = g.make_json_sarif_graph ();
+
+ pretty_printer pp;
+ sarif->print (&pp, true);
+ ASSERT_STREQ
+ (pp_formatted_text (&pp),
+ ("{\"nodes\": [],\n"
+ " \"edges\": []}"));
+ }
+
+ {
+ auto dg = g.make_dot_graph ();
+
+ pretty_printer pp;
+ dot::writer w (pp);
+ dg->print (w);
+ ASSERT_STREQ
+ (pp_formatted_text (&pp),
+ ("digraph {\n"
+ "}\n"));
+ }
+}
+
+static void
+test_simple_graph ()
+{
+#define KEY_PREFIX "/placeholder/"
+ auto g = std::make_unique<digraph> ();
+ g->set_description ("test graph");
+ g->set_attr (KEY_PREFIX, "date", "1066");
+
+ auto a = std::make_unique<digraph_node> (*g, "a");
+ auto b = std::make_unique<digraph_node> (*g, "b");
+ b->set_attr (KEY_PREFIX, "color", "red");
+ auto c = std::make_unique<digraph_node> (*g, "c");
+ c->set_label ("I am a node label");
+
+ auto e = std::make_unique<digraph_edge> (*g, nullptr, *a, *c);
+ e->set_attr (KEY_PREFIX, "status", "copacetic");
+ e->set_label ("I am an edge label");
+ g->add_edge (std::move (e));
+
+ g->add_node (std::move (a));
+
+ b->add_child (std::move (c));
+ g->add_node (std::move (b));
+#undef KEY_PREFIX
+
+ {
+ auto sarif = g->make_json_sarif_graph ();
+
+ pretty_printer pp;
+ sarif->print (&pp, true);
+ ASSERT_STREQ
+ (pp_formatted_text (&pp),
+ ("{\"properties\": {\"/placeholder/date\": \"1066\"},\n"
+ " \"nodes\": [{\"id\": \"a\"},\n"
+ " {\"id\": \"b\",\n"
+ " \"properties\": {\"/placeholder/color\": \"red\"},\n"
+ " \"children\": [{\"id\": \"c\"}]}],\n"
+ " \"edges\": [{\"id\": \"edge0\",\n"
+ " \"properties\": {\"/placeholder/status\": \"copacetic\"},\n"
+ " \"sourceNodeId\": \"a\",\n"
+ " \"targetNodeId\": \"c\"}]}"));
+ }
+
+ {
+ auto dg = g->make_dot_graph ();
+
+ pretty_printer pp;
+ dot::writer w (pp);
+ dg->print (w);
+ ASSERT_STREQ
+ (pp_formatted_text (&pp),
+ ("digraph {\n"
+ " label=\"test graph\";\n"
+ " a;\n"
+ " \n"
+ " subgraph cluster_b {\n"
+ " c [label=\"I am a node label\"];\n"
+ "\n"
+ " };\n"
+ " a -> c [label=\"I am an edge label\"];\n"
+ "}\n"));
+ }
+}
+
+/* Run all of the selftests within this file. */
+
+void
+diagnostic_digraphs_cc_tests ()
+{
+ test_empty_graph ();
+ test_simple_graph ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-digraphs.h b/gcc/diagnostic-digraphs.h
new file mode 100644
index 0000000..94cb76e
--- /dev/null
+++ b/gcc/diagnostic-digraphs.h
@@ -0,0 +1,411 @@
+/* Directed graphs associated with a diagnostic.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+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/>. */
+
+#ifndef GCC_DIAGNOSTIC_DIGRAPHS_H
+#define GCC_DIAGNOSTIC_DIGRAPHS_H
+
+#include "json.h"
+#include "logical-location.h"
+
+class graphviz_out;
+
+class sarif_graph;
+class sarif_node;
+class sarif_edge;
+
+namespace dot { class graph; }
+
+namespace diagnostics {
+namespace digraphs {
+
+/* A family of classes: digraph, node, and edge, closely related to
+ SARIF's graph, node, and edge types (SARIF v2.1.0 sections 3.39-3.41).
+
+ Nodes can have child nodes, allowing for arbitrarily deep nesting.
+ Edges can be between any pair of nodes (potentially at different
+ nesting levels).
+
+ Digraphs, nodes, and edges also optionally have a JSON property bag,
+ allowing round-tripping of arbitrary key/value pairs through SARIF. */
+
+class digraph;
+class node;
+class edge;
+
+/* A base class for digraph, node, and edge to allow them to have
+ an optional JSON property bag. */
+
+class object
+{
+public:
+ const char *
+ get_attr (const char *key_prefix,
+ const char *key) const;
+
+ void
+ set_attr (const char *key_prefix,
+ const char *key,
+ const char *value);
+
+ void
+ set_json_attr (const char *key_prefix,
+ const char *key,
+ std::unique_ptr<json::value> value);
+
+ json::object *
+ get_property_bag () const { return m_property_bag.get (); }
+
+ void
+ set_property_bag (std::unique_ptr<json::object> property_bag)
+ {
+ m_property_bag = std::move (property_bag);
+ }
+
+private:
+ std::unique_ptr<json::object> m_property_bag;
+};
+
+// A directed graph, corresponding to SARIF v2.1.0 section 3.39.
+
+class digraph : public object
+{
+ public:
+ friend class node;
+ friend class edge;
+
+ digraph () : m_next_edge_id_index (0) {}
+ virtual ~digraph () {}
+
+ const char *
+ get_description () const
+ {
+ if (!m_description)
+ return nullptr;
+ return m_description->c_str ();
+ }
+
+ void
+ set_description (const char *desc)
+ {
+ if (desc)
+ m_description = std::make_unique<std::string> (desc);
+ else
+ m_description = nullptr;
+ }
+
+ node *
+ get_node_by_id (const char *id) const
+ {
+ auto iter = m_id_to_node_map.find (id);
+ if (iter == m_id_to_node_map.end ())
+ return nullptr;
+ return iter->second;
+ }
+
+ edge *
+ get_edge_by_id (const char *id) const
+ {
+ auto iter = m_id_to_edge_map.find (id);
+ if (iter == m_id_to_edge_map.end ())
+ return nullptr;
+ return iter->second;
+ }
+
+ size_t
+ get_num_nodes () const
+ {
+ return m_nodes.size ();
+ }
+
+ node &
+ get_node (size_t idx) const
+ {
+ return *m_nodes[idx].get ();
+ }
+
+ size_t
+ get_num_edges () const
+ {
+ return m_edges.size ();
+ }
+
+ edge &
+ get_edge (size_t idx) const
+ {
+ return *m_edges[idx].get ();
+ }
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ make_json_sarif_graph () const;
+
+ std::unique_ptr<dot::graph>
+ make_dot_graph () const;
+
+ void
+ add_node (std::unique_ptr<node> n)
+ {
+ gcc_assert (n);
+ m_nodes.push_back (std::move (n));
+ }
+
+ void
+ add_edge (std::unique_ptr<edge> e)
+ {
+ gcc_assert (e);
+ m_edges.push_back (std::move (e));
+ }
+
+ void
+ add_edge (const char *id,
+ node &src_node,
+ node &dst_node,
+ const char *label = nullptr);
+
+ std::unique_ptr<digraph> clone () const;
+
+ private:
+ void
+ add_node_id (std::string node_id, node &new_node)
+ {
+ m_id_to_node_map.insert ({std::move (node_id), &new_node});
+ }
+ void
+ add_edge_id (std::string edge_id, edge &new_edge)
+ {
+ m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
+ }
+
+ std::string
+ make_edge_id (const char *edge_id);
+
+ std::unique_ptr<std::string> m_description;
+ std::map<std::string, node *> m_id_to_node_map;
+ std::map<std::string, edge *> m_id_to_edge_map;
+ std::vector<std::unique_ptr<node>> m_nodes;
+ std::vector<std::unique_ptr<edge>> m_edges;
+ size_t m_next_edge_id_index;
+};
+
+// A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
+
+class node : public object
+{
+ public:
+ virtual ~node () {}
+
+ node (digraph &g, std::string id)
+ : m_id (id),
+ m_physical_loc (UNKNOWN_LOCATION)
+ {
+ g.add_node_id (std::move (id), *this);
+ }
+ node (const node &) = delete;
+
+ std::string
+ get_id () const { return m_id; }
+
+ const char *
+ get_label () const
+ {
+ if (!m_label)
+ return nullptr;
+ return m_label->c_str ();
+ }
+
+ void
+ set_label (const char *label)
+ {
+ if (label)
+ m_label = std::make_unique<std::string> (label);
+ else
+ m_label = nullptr;
+ }
+
+ size_t
+ get_num_children () const { return m_children.size (); }
+
+ node &
+ get_child (size_t idx) const { return *m_children[idx].get (); }
+
+ void
+ add_child (std::unique_ptr<node> child)
+ {
+ gcc_assert (child);
+ m_children.push_back (std::move (child));
+ }
+
+ location_t
+ get_physical_loc () const
+ {
+ return m_physical_loc;
+ }
+
+ void
+ set_physical_loc (location_t physical_loc)
+ {
+ m_physical_loc = physical_loc;
+ }
+
+ logical_location
+ get_logical_loc () const
+ {
+ return m_logical_loc;
+ }
+
+ void
+ set_logical_loc (logical_location logical_loc)
+ {
+ m_logical_loc = logical_loc;
+ }
+
+ void print (graphviz_out &gv) const;
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ to_json_sarif_node () const;
+
+ std::unique_ptr<node>
+ clone (digraph &new_graph,
+ std::map<node *, node *> &node_mapping) const;
+
+ private:
+ std::string m_id;
+ std::unique_ptr<std::string> m_label;
+ std::vector<std::unique_ptr<node>> m_children;
+ location_t m_physical_loc;
+ logical_location m_logical_loc;
+};
+
+// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
+
+class edge : public object
+{
+ public:
+ virtual ~edge () {}
+
+ /* SARIF requires us to provide unique edge IDs within a graph,
+ but otherwise we don't need them.
+ Pass in nullptr for the id to get the graph to generate a unique
+ edge id for us. */
+ edge (digraph &g,
+ const char *id,
+ node &src_node,
+ node &dst_node)
+ : m_id (g.make_edge_id (id)),
+ m_src_node (src_node),
+ m_dst_node (dst_node)
+ {
+ g.add_edge_id (m_id, *this);
+ }
+
+ std::string
+ get_id () const { return m_id; }
+
+ const char *
+ get_label () const
+ {
+ if (!m_label)
+ return nullptr;
+ return m_label->c_str ();
+ }
+
+ void
+ set_label (const char *label)
+ {
+ if (label)
+ m_label = std::make_unique<std::string> (label);
+ else
+ m_label = nullptr;
+ }
+
+ node &
+ get_src_node () const { return m_src_node; }
+
+ node &
+ get_dst_node () const { return m_dst_node; }
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ to_json_sarif_edge () const;
+
+ std::unique_ptr<edge>
+ clone (digraph &new_graph,
+ const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
+
+private:
+ std::string m_id;
+ std::unique_ptr<std::string> m_label;
+ node &m_src_node;
+ node &m_dst_node;
+};
+
+/* Abstract base class for lazily creating
+ a digraph on demand.
+
+ This allows us to avoid the work of creating the digraph for
+ the common case where we just have a text sink. */
+
+class lazy_digraph
+{
+public:
+ virtual ~lazy_digraph () {}
+
+ const digraph &
+ get_or_create_digraph () const;
+
+private:
+ virtual std::unique_ptr<digraph>
+ create_digraph () const = 0;
+
+ mutable std::unique_ptr<digraph> m_digraph;
+};
+
+/* Abstract base class for lazily creating a collection of
+ digraphs on demand.
+
+ This allows us to avoid the work of creating the digraphs for
+ the common case where we just have a text sink. */
+
+class lazy_digraphs
+{
+public:
+ virtual ~lazy_digraphs () {}
+
+ const std::vector<std::unique_ptr<digraph>> &
+ get_or_create_digraphs () const;
+
+private:
+ virtual std::unique_ptr<std::vector<std::unique_ptr<digraph>>>
+ create_digraphs () const = 0;
+
+ mutable std::unique_ptr<std::vector<std::unique_ptr<digraph>>> m_digraphs;
+};
+
+} // namespace digraphs
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTIC_DIGRAPHS_H */
diff --git a/gcc/diagnostic-format-html.cc b/gcc/diagnostic-format-html.cc
index 473880f..becac39 100644
--- a/gcc/diagnostic-format-html.cc
+++ b/gcc/diagnostic-format-html.cc
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-format.h"
#include "diagnostic-format-html.h"
#include "diagnostic-format-text.h"
+#include "diagnostic-format-sarif.h"
#include "diagnostic-output-file.h"
#include "diagnostic-buffer.h"
#include "diagnostic-path.h"
@@ -41,7 +42,8 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "xml.h"
#include "xml-printer.h"
-#include "diagnostic-state.h"
+#include "diagnostic-digraphs.h"
+#include "diagnostic-state-graphs.h"
#include "graphviz.h"
#include "json.h"
#include "selftest-xml.h"
@@ -52,8 +54,8 @@ html_generation_options::html_generation_options ()
: m_css (true),
m_javascript (true),
m_show_state_diagrams (false),
- m_show_state_diagram_xml (false),
- m_show_state_diagram_dot_src (false)
+ m_show_state_diagrams_sarif (false),
+ m_show_state_diagrams_dot_src (false)
{
}
@@ -119,6 +121,8 @@ public:
diagnostic_t orig_diag_kind,
diagnostic_html_format_buffer *buffer);
void emit_diagram (const diagnostic_diagram &diagram);
+ void emit_global_graph (const diagnostics::digraphs::lazy_digraph &);
+
void end_group ();
std::unique_ptr<xml::element> take_current_diagnostic ()
@@ -172,6 +176,10 @@ private:
void
pop_nesting_level ();
+ void
+ add_graph (const diagnostics::digraphs::digraph &dg,
+ xml::element &parent_element);
+
diagnostic_context &m_context;
pretty_printer *m_printer;
const line_maps *m_line_maps;
@@ -181,6 +189,7 @@ private:
std::unique_ptr<xml::document> m_document;
xml::element *m_head_element;
xml::element *m_title_element;
+ xml::element *m_body_element;
xml::element *m_diagnostics_element;
std::unique_ptr<xml::element> m_cur_diagnostic_element;
std::vector<xml::element *> m_cur_nesting_levels;
@@ -401,6 +410,7 @@ html_builder::html_builder (diagnostic_context &context,
m_logical_loc_mgr (nullptr),
m_head_element (nullptr),
m_title_element (nullptr),
+ m_body_element (nullptr),
m_diagnostics_element (nullptr),
m_next_diag_id (0),
m_last_location (UNKNOWN_LOCATION),
@@ -447,6 +457,7 @@ html_builder::html_builder (diagnostic_context &context,
{
xml::auto_print_element body (xp, "body");
+ m_body_element = xp.get_insertion_point ();
{
auto diagnostics_element = make_div ("gcc-diagnostic-list");
m_diagnostics_element = diagnostics_element.get ();
@@ -599,39 +610,45 @@ html_builder::maybe_make_state_diagram (const diagnostic_event &event)
if (!m_html_gen_opts.m_show_state_diagrams)
return nullptr;
- /* Get XML state document; if we're going to print it later, also request
+ if (!m_logical_loc_mgr)
+ return nullptr;
+
+ /* Get state graph; if we're going to print it later, also request
the debug version. */
- auto xml_state
- = event.maybe_make_xml_state (m_html_gen_opts.m_show_state_diagram_xml);
- if (!xml_state)
+ auto state_graph
+ = event.maybe_make_diagnostic_state_graph
+ (m_html_gen_opts.m_show_state_diagrams_sarif);
+ if (!state_graph)
return nullptr;
// Convert it to .dot AST
- auto graph = make_dot_graph_from_xml_state (*xml_state);
- gcc_assert (graph);
+ auto dot_graph
+ = diagnostics::state_graphs::make_dot_graph (*state_graph,
+ *m_logical_loc_mgr);
+ gcc_assert (dot_graph);
auto wrapper = std::make_unique<xml::element> ("div", false);
xml::printer xp (*wrapper);
- if (m_html_gen_opts.m_show_state_diagram_xml)
+ if (m_html_gen_opts.m_show_state_diagrams_sarif)
{
- // For debugging, show the XML src inline:
+ // For debugging, show the SARIF src inline:
pretty_printer pp;
- xml_state->write_as_xml (&pp, 0, true);
+ state_graph->make_json_sarif_graph ()->print (&pp, true);
print_pre_source (xp, pp_formatted_text (&pp));
}
- if (m_html_gen_opts.m_show_state_diagram_dot_src)
+ if (m_html_gen_opts.m_show_state_diagrams_dot_src)
{
// For debugging, show the dot src inline:
pretty_printer pp;
dot::writer w (pp);
- graph->print (w);
+ dot_graph->print (w);
print_pre_source (xp, pp_formatted_text (&pp));
}
// Turn the .dot into SVG and splice into place
- auto svg = dot::make_svg_from_graph (*graph);
+ auto svg = dot::make_svg_from_graph (*dot_graph);
if (svg)
xp.append (std::move (svg));
@@ -1125,6 +1142,15 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
gcc_assert (xp.get_num_open_tags () == depth_within_alert_div);
+ // Try to display any per-diagnostic graphs
+ if (diagnostic.metadata)
+ if (auto ldg = diagnostic.metadata->get_lazy_digraphs ())
+ {
+ auto &digraphs = ldg->get_or_create_digraphs ();
+ for (auto &dg : digraphs)
+ add_graph (*dg, *xp.get_insertion_point ());
+ }
+
if (auto patch_element = make_element_for_patch (diagnostic))
{
xp.push_tag ("div");
@@ -1221,6 +1247,35 @@ html_builder::emit_diagram (const diagnostic_diagram &/*diagram*/)
// TODO: currently a no-op
}
+void
+html_builder::add_graph (const diagnostics::digraphs::digraph &dg,
+ xml::element &parent_element)
+{
+ if (auto dot_graph = dg.make_dot_graph ())
+ if (auto svg_element = dot::make_svg_from_graph (*dot_graph))
+ {
+ auto div = std::make_unique<xml::element> ("div", false);
+ div->set_attr ("class", "gcc-directed-graph");
+ xml::printer xp (*div);
+ if (const char *description = dg.get_description ())
+ {
+ xp.push_tag ("h2", true);
+ xp.add_text (description);
+ xp.pop_tag ("h2");
+ }
+ xp.append (std::move (svg_element));
+ parent_element.add_child (std::move (div));
+ }
+}
+
+void
+html_builder::emit_global_graph (const diagnostics::digraphs::lazy_digraph &ldg)
+{
+ auto &dg = ldg.get_or_create_digraph ();
+ gcc_assert (m_body_element);
+ add_graph (dg, *m_body_element);
+}
+
/* Implementation of "end_group_cb" for HTML output. */
void
@@ -1334,6 +1389,12 @@ public:
m_builder.set_printer (*get_printer ());
}
+ void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg) final override
+ {
+ m_builder.emit_global_graph (ldg);
+ }
+
const xml::document &get_document () const
{
return m_builder.get_document ();
diff --git a/gcc/diagnostic-format-html.h b/gcc/diagnostic-format-html.h
index 09a97e0..537ba54 100644
--- a/gcc/diagnostic-format-html.h
+++ b/gcc/diagnostic-format-html.h
@@ -36,11 +36,11 @@ struct html_generation_options
// If true, attempt to show state diagrams at events
bool m_show_state_diagrams;
- // If true, show the XML form of the state with such diagrams
- bool m_show_state_diagram_xml;
+ // If true, show the SARIF form of the state with such diagrams
+ bool m_show_state_diagrams_sarif;
// If true, show the .dot source used for the diagram
- bool m_show_state_diagram_dot_src;
+ bool m_show_state_diagrams_dot_src;
};
extern diagnostic_output_file
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 14cdbc2..d20ca86 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "diagnostic.h"
#include "diagnostic-metadata.h"
+#include "diagnostic-digraphs.h"
+#include "diagnostic-state-graphs.h"
#include "diagnostic-path.h"
#include "diagnostic-format.h"
#include "diagnostic-buffer.h"
@@ -776,6 +778,9 @@ public:
void emit_diagram (const diagnostic_diagram &diagram);
void end_group ();
+ void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &);
+
std::unique_ptr<sarif_result> take_current_result ()
{
return std::move (m_cur_group_result);
@@ -789,7 +794,7 @@ public:
const diagnostic_info &diagnostic,
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_location>
- make_location_object (sarif_location_manager &loc_mgr,
+ make_location_object (sarif_location_manager *loc_mgr,
const rich_location &rich_loc,
logical_location logical_loc,
enum diagnostic_artifact_role role);
@@ -974,6 +979,8 @@ private:
std::unique_ptr<sarif_array_of_unique<sarif_logical_location>> m_cached_logical_locs;
+ std::unique_ptr<sarif_array_of_unique<sarif_graph>> m_run_graphs;
+
int m_tabstop;
std::unique_ptr<sarif_serialization_format> m_serialization_format;
@@ -1305,7 +1312,7 @@ sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
sometimes these will related to current_function_decl, but
often they won't. */
auto location_obj
- = builder.make_location_object (*this, *diagnostic.richloc,
+ = builder.make_location_object (this, *diagnostic.richloc,
logical_location (),
diagnostic_artifact_role::result_file);
auto message_obj
@@ -1663,6 +1670,8 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_rules_arr (new json::array ()),
m_cached_logical_locs
(std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
+ m_run_graphs
+ (std::make_unique<sarif_array_of_unique<sarif_graph>> ()),
m_tabstop (context.m_tabstop),
m_serialization_format (std::move (serialization_format)),
m_sarif_gen_opts (sarif_gen_opts),
@@ -1895,6 +1904,17 @@ sarif_builder::end_group ()
}
}
+void
+sarif_builder::
+report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg)
+{
+ auto &dg = ldg.get_or_create_digraph ();
+
+ /* Presumably the location manager must be nullptr; see
+ https://github.com/oasis-tcs/sarif-spec/issues/712 */
+ m_run_graphs->append (make_sarif_graph (dg, this, nullptr));
+}
+
/* Create a top-level object, and add it to all the results
(and other entities) we've seen so far, moving ownership
to the object. */
@@ -2049,6 +2069,19 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
result_obj->set<json::array> ("codeFlows", std::move (code_flows_arr));
}
+ // "graphs" property (SARIF v2.1.0 section 3.27.19). */
+ if (diagnostic.metadata)
+ if (auto ldg = diagnostic.metadata->get_lazy_digraphs ())
+ {
+ auto &digraphs = ldg->get_or_create_digraphs ();
+ auto graphs_arr = std::make_unique<json::array> ();
+ for (auto &iter : digraphs)
+ graphs_arr->append (make_sarif_graph (*iter, this,
+ result_obj.get ()));
+ if (graphs_arr->size () > 0)
+ result_obj->set<json::array> ("graphs", std::move (graphs_arr));
+ }
+
/* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
set up later, if any nested diagnostics occur within this diagnostic
group. */
@@ -2176,7 +2209,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
logical_loc = client_data_hooks->get_current_logical_location ();
auto location_obj
- = make_location_object (loc_mgr, *diagnostic.richloc, logical_loc, role);
+ = make_location_object (&loc_mgr, *diagnostic.richloc, logical_loc, role);
/* Don't add entirely empty location objects to the array. */
if (!location_obj->is_empty ())
locations_arr->append<sarif_location> (std::move (location_obj));
@@ -2210,10 +2243,12 @@ set_any_logical_locs_arr (sarif_location &location_obj,
/* Make a "location" object (SARIF v2.1.0 section 3.28) for RICH_LOC
and LOGICAL_LOC.
Use LOC_MGR for any locations that need "id" values, and for
- any worklist items. */
+ any worklist items.
+ Note that we might not always have a LOC_MGR; see
+ https://github.com/oasis-tcs/sarif-spec/issues/712 */
std::unique_ptr<sarif_location>
-sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
+sarif_builder::make_location_object (sarif_location_manager *loc_mgr,
const rich_location &rich_loc,
logical_location logical_loc,
enum diagnostic_artifact_role role)
@@ -2309,8 +2344,8 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
/* Add related locations for any secondary locations in RICH_LOC
that don't have labels (and thus aren't added to "annotations"). */
- if (i > 0 && !handled)
- loc_mgr.add_relationship_to_worklist
+ if (loc_mgr && i > 0 && !handled)
+ loc_mgr->add_relationship_to_worklist
(*location_obj.get (),
sarif_location_manager::worklist_item::kind::unlabelled_secondary_location,
range->m_loc);
@@ -2321,7 +2356,8 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
std::move (annotations_arr));
}
- add_any_include_chain (loc_mgr, *location_obj.get (), loc);
+ if (loc_mgr)
+ add_any_include_chain (*loc_mgr, *location_obj.get (), loc);
/* A flag for hinting that the diagnostic involves issues at the
level of character encodings (such as homoglyphs, or misleading
@@ -2799,6 +2835,142 @@ sarif_property_bag::set_logical_location (const char *property_name,
builder.make_minimal_sarif_logical_location (logical_loc));
}
+static void
+copy_any_property_bag (const diagnostics::digraphs::object &input_obj,
+ sarif_object &output_obj)
+{
+ if (input_obj.get_property_bag ())
+ {
+ const json::object &old_bag = *input_obj.get_property_bag ();
+ sarif_property_bag &new_bag = output_obj.get_or_create_properties ();
+ for (size_t i = 0; i < old_bag.get_num_keys (); ++i)
+ {
+ const char *key = old_bag.get_key (i);
+ json::value *val = old_bag.get (key);
+ new_bag.set (key, val->clone ());
+ }
+ }
+}
+
+std::unique_ptr<sarif_graph>
+make_sarif_graph (const diagnostics::digraphs::digraph &g,
+ sarif_builder *builder,
+ sarif_location_manager *sarif_location_mgr)
+{
+ auto result = std::make_unique<sarif_graph> ();
+
+ // 3.39.2 description property
+ if (const char *desc = g.get_description ())
+ if (builder)
+ result->set<sarif_message> ("description",
+ builder->make_message_object (desc));
+
+ copy_any_property_bag (g, *result);
+
+ // 3.39.3 nodes property
+ auto nodes_arr = std::make_unique<json::array> ();
+ const int num_nodes = g.get_num_nodes ();
+ for (int i = 0; i < num_nodes; ++i)
+ nodes_arr->append (make_sarif_node (g.get_node (i),
+ builder,
+ sarif_location_mgr));
+ result->set ("nodes", std::move (nodes_arr));
+
+ // 3.39.4 edges property
+ auto edges_arr = std::make_unique<json::array> ();
+ const int num_edges = g.get_num_edges ();
+ for (int i = 0; i < num_edges; ++i)
+ edges_arr->append (make_sarif_edge (g.get_edge (i), builder));
+ result->set ("edges", std::move (edges_arr));
+
+ return result;
+}
+
+std::unique_ptr<sarif_node>
+make_sarif_node (const diagnostics::digraphs::node &n,
+ sarif_builder *builder,
+ sarif_location_manager *sarif_location_mgr)
+{
+ auto result = std::make_unique<sarif_node> ();
+
+ // 3.40.2 id property
+ result->set_string ("id", n.get_id ().c_str ());
+
+ copy_any_property_bag (n, *result);
+
+ // 3.40.3 label property
+ if (const char *label = n.get_label ())
+ if (builder)
+ result->set<sarif_message> ("label",
+ builder->make_message_object (label));
+
+ // 3.40.4 location property
+ if (n.get_logical_loc ()
+ || n.get_physical_loc () != UNKNOWN_LOCATION)
+ if (builder)
+ {
+ rich_location rich_loc
+ (line_table, n.get_physical_loc ());
+ auto loc_obj
+ = builder->make_location_object
+ (sarif_location_mgr,
+ rich_loc,
+ n.get_logical_loc (),
+ diagnostic_artifact_role::scanned_file);
+ result->set<sarif_location> ("location",
+ std::move (loc_obj));
+ }
+
+ // 3.40.5 children property
+ if (const int num_children = n.get_num_children ())
+ {
+ auto children_arr = std::make_unique<json::array> ();
+ for (int i = 0; i < num_children; ++i)
+ children_arr->append (make_sarif_node (n.get_child (i),
+ builder,
+ sarif_location_mgr));
+ result->set ("children", std::move (children_arr));
+ }
+
+ return result;
+}
+
+std::unique_ptr<sarif_edge>
+make_sarif_edge (const diagnostics::digraphs::edge &e,
+ sarif_builder *builder)
+{
+ auto result = std::make_unique<sarif_edge> ();
+
+ // 3.41.2 id property
+ result->set_string ("id", e.get_id ().c_str ());
+
+ copy_any_property_bag (e, *result);
+
+ // 3.41.3 label property
+ if (const char *label = e.get_label ())
+ if (builder)
+ result->set<sarif_message> ("label",
+ builder->make_message_object (label));
+
+ // 3.41.4 sourceNodeId property
+ result->set_string ("sourceNodeId", e.get_src_node ().get_id ().c_str ());
+
+ // 3.41.5 targetNodeId property
+ result->set_string ("targetNodeId", e.get_dst_node ().get_id ().c_str ());
+
+ return result;
+}
+
+void
+sarif_property_bag::set_graph (const char *property_name,
+ sarif_builder &builder,
+ sarif_location_manager *sarif_location_mgr,
+ const diagnostics::digraphs::digraph &g)
+{
+ set<sarif_graph> (property_name,
+ make_sarif_graph (g, &builder, sarif_location_mgr));
+}
+
/* Ensure that m_cached_logical_locs has a "logicalLocation" object
(SARIF v2.1.0 section 3.33) for K, and return its index within the
array. */
@@ -2960,17 +3132,21 @@ populate_thread_flow_location_object (sarif_result &result,
via a property bag. */
ev.maybe_add_sarif_properties (*this, tfl_obj);
- if (get_opts ().m_xml_state)
- if (auto xml_state = ev.maybe_make_xml_state (true))
+ if (get_opts ().m_state_graph)
+ if (auto state_graph = ev.maybe_make_diagnostic_state_graph (true))
{
sarif_property_bag &props = tfl_obj.get_or_create_properties ();
- pretty_printer pp;
- xml_state->write_as_xml (&pp, 0, true);
-
#define PROPERTY_PREFIX "gcc/diagnostic_event/"
- props.set_string (PROPERTY_PREFIX "xml_state",
- pp_formatted_text (&pp));
+ props.set_graph (PROPERTY_PREFIX "state_graph",
+ *this,
+ /* Use RESULT for any related locations in the graph's
+ nodes.
+ It's not clear if this is correct; see:
+ https://github.com/oasis-tcs/sarif-spec/issues/712
+ */
+ &result,
+ *state_graph);
#undef PROPERTY_PREFIX
}
@@ -3234,6 +3410,11 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
std::move (m_cached_logical_locs));
}
+ // "graphs" property (SARIF v2.1.0 3.14.20)
+ if (m_run_graphs->size () > 0)
+ run_obj->set<json::array> ("graphs",
+ std::move (m_run_graphs));
+
return run_obj;
}
@@ -3739,6 +3920,12 @@ public:
/* No-op. */
}
+ void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &lazy_digraph) final override
+ {
+ m_builder.report_global_digraph (lazy_digraph);
+ }
+
sarif_builder &get_builder () { return m_builder; }
size_t num_results () const { return m_builder.num_results (); }
@@ -4117,7 +4304,7 @@ make_sarif_sink (diagnostic_context &context,
sarif_generation_options::sarif_generation_options ()
: m_version (sarif_version::v2_1_0),
- m_xml_state (false)
+ m_state_graph (false)
{
}
@@ -4299,7 +4486,7 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts,
std::unique_ptr<sarif_location> location_obj
= builder.make_location_object
- (result, richloc, logical_location (),
+ (&result, richloc, logical_location (),
diagnostic_artifact_role::analysis_target);
ASSERT_NE (location_obj, nullptr);
diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h
index c3ae330..60657c6 100644
--- a/gcc/diagnostic-format-sarif.h
+++ b/gcc/diagnostic-format-sarif.h
@@ -101,7 +101,7 @@ struct sarif_generation_options
sarif_generation_options ();
enum sarif_version m_version;
- bool m_xml_state;
+ bool m_state_graph;
};
extern std::unique_ptr<diagnostic_output_format>
@@ -112,6 +112,14 @@ make_sarif_sink (diagnostic_context &context,
diagnostic_output_file output_file);
class sarif_builder;
+class sarif_location_manager;
+
+namespace diagnostics {
+namespace digraphs {
+ class digraph;
+ class node;
+ class edge;
+}}
/* Concrete subclass of json::object for SARIF property bags
(SARIF v2.1.0 section 3.8). */
@@ -122,6 +130,10 @@ public:
void set_logical_location (const char *property_name,
sarif_builder &,
logical_location logical_loc);
+ void set_graph (const char *property_name,
+ sarif_builder &,
+ sarif_location_manager *sarif_location_mgr,
+ const diagnostics::digraphs::digraph &g);
};
/* Concrete subclass of json::object for SARIF objects that can
@@ -136,4 +148,39 @@ public:
sarif_property_bag &get_or_create_properties ();
};
+/* Subclass of sarif_object for SARIF "graph" objects
+ (SARIF v2.1.0 section 3.39). */
+
+class sarif_graph : public sarif_object
+{
+};
+
+/* Subclass of sarif_object for SARIF "node" objects
+ (SARIF v2.1.0 section 3.40). */
+
+class sarif_node : public sarif_object
+{
+};
+
+/* Subclass of sarif_object for SARIF "edge" objects
+ (SARIF v2.1.0 section 3.41). */
+
+class sarif_edge : public sarif_object
+{
+};
+
+extern std::unique_ptr<sarif_graph>
+make_sarif_graph (const diagnostics::digraphs::digraph &g,
+ sarif_builder *builder,
+ sarif_location_manager *sarif_location_mgr);
+
+extern std::unique_ptr<sarif_node>
+make_sarif_node (const diagnostics::digraphs::node &n,
+ sarif_builder *builder,
+ sarif_location_manager *sarif_location_mgr);
+
+extern std::unique_ptr<sarif_edge>
+make_sarif_edge (const diagnostics::digraphs::edge &e,
+ sarif_builder *builder);
+
#endif /* ! GCC_DIAGNOSTIC_FORMAT_SARIF_H */
diff --git a/gcc/diagnostic-format-text.h b/gcc/diagnostic-format-text.h
index 64f8e13..64a4452 100644
--- a/gcc/diagnostic-format-text.h
+++ b/gcc/diagnostic-format-text.h
@@ -70,6 +70,12 @@ public:
void update_printer () override;
+ void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &) final override
+ {
+ // no-op for text
+ }
+
/* Helpers for writing lang-specific starters/finalizers for text output. */
char *build_prefix (const diagnostic_info &) const;
void report_current_module (location_t where);
diff --git a/gcc/diagnostic-format.h b/gcc/diagnostic-format.h
index 07db2cd..a4c776c 100644
--- a/gcc/diagnostic-format.h
+++ b/gcc/diagnostic-format.h
@@ -72,6 +72,9 @@ public:
Subclasses should update their m_printer accordingly. */
virtual void update_printer () = 0;
+ virtual void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &) = 0;
+
diagnostic_context &get_context () const { return m_context; }
pretty_printer *get_printer () const { return m_printer.get (); }
diff --git a/gcc/diagnostic-metadata.h b/gcc/diagnostic-metadata.h
index baeeb6e..f6ea7dc 100644
--- a/gcc/diagnostic-metadata.h
+++ b/gcc/diagnostic-metadata.h
@@ -23,11 +23,20 @@ along with GCC; see the file COPYING3. If not see
class sarif_object;
+namespace diagnostics {
+ namespace digraphs {
+ class lazy_digraphs;
+ } // namespace digraphs
+} // namespace diagnostics
+
/* A bundle of additional metadata that can be associated with a
diagnostic.
This supports an optional CWE identifier, and zero or more
- "rules". */
+ "rules".
+
+ Additionally, this provides a place to associate a diagnostic
+ with zero or more directed graphs. */
class diagnostic_metadata
{
@@ -64,7 +73,7 @@ class diagnostic_metadata
const char *m_url;
};
- diagnostic_metadata () : m_cwe (0) {}
+ diagnostic_metadata () : m_cwe (0), m_lazy_digraphs (nullptr) {}
virtual ~diagnostic_metadata () {}
/* Hook for SARIF output to allow for adding diagnostic-specific
@@ -87,9 +96,25 @@ class diagnostic_metadata
unsigned get_num_rules () const { return m_rules.length (); }
const rule &get_rule (unsigned idx) const { return *(m_rules[idx]); }
+ void
+ set_lazy_digraphs (const diagnostics::digraphs::lazy_digraphs *lazy_digraphs)
+ {
+ m_lazy_digraphs = lazy_digraphs;
+ }
+
+ const diagnostics::digraphs::lazy_digraphs *
+ get_lazy_digraphs () const
+ {
+ return m_lazy_digraphs;
+ }
+
private:
int m_cwe;
auto_vec<const rule *> m_rules;
+
+ /* An optional way to create directed graphs associated with the
+ diagnostic, for the sinks that support this (e.g. SARIF). */
+ const diagnostics::digraphs::lazy_digraphs *m_lazy_digraphs;
};
#endif /* ! GCC_DIAGNOSTIC_METADATA_H */
diff --git a/gcc/diagnostic-output-spec.cc b/gcc/diagnostic-output-spec.cc
index 25ef86f..4fa3176 100644
--- a/gcc/diagnostic-output-spec.cc
+++ b/gcc/diagnostic-output-spec.cc
@@ -183,7 +183,7 @@ public:
private:
static sarif_generation_options
make_sarif_gen_opts (enum sarif_version version,
- bool xml_state);
+ bool state_graph);
static std::unique_ptr<sarif_serialization_format>
make_sarif_serialization_object (enum sarif_serialization_kind);
@@ -431,7 +431,7 @@ sarif_scheme_handler::make_sink (const context &ctxt,
enum sarif_serialization_kind serialization_kind
= sarif_serialization_kind::json;
enum sarif_version version = sarif_version::v2_1_0;
- bool xml_state = false;
+ bool state_graph = false;
for (auto& iter : parsed_arg.m_kvs)
{
const std::string &key = iter.first;
@@ -469,10 +469,10 @@ sarif_scheme_handler::make_sink (const context &ctxt,
return nullptr;
continue;
}
- if (key == "xml-state")
+ if (key == "state-graphs")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- xml_state))
+ state_graph))
return nullptr;
continue;
}
@@ -481,8 +481,8 @@ sarif_scheme_handler::make_sink (const context &ctxt,
auto_vec<const char *> known_keys;
known_keys.safe_push ("file");
known_keys.safe_push ("serialization");
+ known_keys.safe_push ("state-graphs");
known_keys.safe_push ("version");
- known_keys.safe_push ("xml-state");
ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
known_keys);
return nullptr;
@@ -513,7 +513,7 @@ sarif_scheme_handler::make_sink (const context &ctxt,
if (!output_file)
return nullptr;
- auto sarif_gen_opts = make_sarif_gen_opts (version, xml_state);
+ auto sarif_gen_opts = make_sarif_gen_opts (version, state_graph);
auto serialization_obj = make_sarif_serialization_object (serialization_kind);
@@ -527,11 +527,11 @@ sarif_scheme_handler::make_sink (const context &ctxt,
sarif_generation_options
sarif_scheme_handler::make_sarif_gen_opts (enum sarif_version version,
- bool xml_state)
+ bool state_graph)
{
sarif_generation_options sarif_gen_opts;
sarif_gen_opts.m_version = version;
- sarif_gen_opts.m_xml_state = xml_state;
+ sarif_gen_opts.m_state_graph = state_graph;
return sarif_gen_opts;
}
@@ -561,8 +561,8 @@ html_scheme_handler::make_sink (const context &ctxt,
label_text filename;
bool javascript = true;
bool show_state_diagrams = false;
- bool show_state_diagram_xml = false;
- bool show_state_diagram_dot_src = false;
+ bool show_state_diagrams_sarif = false;
+ bool show_state_diagrams_dot_src = false;
for (auto& iter : parsed_arg.m_kvs)
{
const std::string &key = iter.first;
@@ -593,17 +593,17 @@ html_scheme_handler::make_sink (const context &ctxt,
return nullptr;
continue;
}
- if (key == "show-state-diagram-dot-src")
+ if (key == "show-state-diagrams-dot-src")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- show_state_diagram_dot_src))
+ show_state_diagrams_dot_src))
return nullptr;
continue;
}
- if (key == "show-state-diagram-xml")
+ if (key == "show-state-diagrams-sarif")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- show_state_diagram_xml))
+ show_state_diagrams_sarif))
return nullptr;
continue;
}
@@ -615,7 +615,7 @@ html_scheme_handler::make_sink (const context &ctxt,
known_keys.safe_push ("javascript");
known_keys.safe_push ("show-state-diagrams");
known_keys.safe_push ("show-state-diagram-dot-src");
- known_keys.safe_push ("show-state-diagram-xml");
+ known_keys.safe_push ("show-state-diagram-sarif");
ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
known_keys);
return nullptr;
@@ -649,8 +649,8 @@ html_scheme_handler::make_sink (const context &ctxt,
html_gen_opts.m_css = css;
html_gen_opts.m_javascript = javascript;
html_gen_opts.m_show_state_diagrams = show_state_diagrams;
- html_gen_opts.m_show_state_diagram_xml = show_state_diagram_xml;
- html_gen_opts.m_show_state_diagram_dot_src = show_state_diagram_dot_src;
+ html_gen_opts.m_show_state_diagrams_sarif = show_state_diagrams_sarif;
+ html_gen_opts.m_show_state_diagrams_dot_src = show_state_diagrams_dot_src;
auto sink = make_html_sink (dc,
*ctxt.get_affected_location_mgr (),
diff --git a/gcc/diagnostic-path.cc b/gcc/diagnostic-path.cc
index 3e169da..1ae87b7 100644
--- a/gcc/diagnostic-path.cc
+++ b/gcc/diagnostic-path.cc
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "diagnostic.h"
#include "diagnostic-path.h"
-#include "xml.h"
+#include "diagnostic-state-graphs.h"
/* Disable warnings about missing quoting in GCC diagnostics for the print
calls below. */
@@ -156,12 +156,12 @@ diagnostic_event::get_desc (pretty_printer &ref_pp) const
return label_text::take (xstrdup (pp_formatted_text (pp.get ())));
}
-// Base implementation of diagnostic_event::maybe_make_xml_state
+// Base implementation of diagnostic_event::maybe_make_diagnostic_state_graph
-std::unique_ptr<xml::document>
-diagnostic_event::maybe_make_xml_state (bool) const
+std::unique_ptr<diagnostics::digraphs::digraph>
+diagnostic_event::maybe_make_diagnostic_state_graph (bool) const
{
- // Don't attempt to make a state document:
+ // Don't attempt to make a state graph:
return nullptr;
}
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h
index e68f768..ca2628e 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostic-path.h
@@ -30,6 +30,12 @@ namespace xml { class document; }
class sarif_builder;
class sarif_object;
+namespace diagnostics {
+namespace digraphs {
+ class digraph;
+} // namespace digraphs
+} //namespace diagnostics
+
/* A diagnostic_path is an optional additional piece of metadata associated
with a diagnostic (via its rich_location).
@@ -173,9 +179,9 @@ class diagnostic_event
}
/* Hook for capturing state at this event, potentially for visualizing
- in HTML output. */
- virtual std::unique_ptr<xml::document>
- maybe_make_xml_state (bool debug) const;
+ in HTML output, or for adding to SARIF. */
+ virtual std::unique_ptr<diagnostics::digraphs::digraph>
+ maybe_make_diagnostic_state_graph (bool debug) const;
label_text get_desc (pretty_printer &ref_pp) const;
};
diff --git a/gcc/diagnostic-state-graphs.cc b/gcc/diagnostic-state-graphs.cc
new file mode 100644
index 0000000..62eb6f5
--- /dev/null
+++ b/gcc/diagnostic-state-graphs.cc
@@ -0,0 +1,158 @@
+/* Extensions to diagnostics::digraphs to support state graphs.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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/>. */
+
+#define INCLUDE_ALGORITHM
+#define INCLUDE_MAP
+#define INCLUDE_SET
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "diagnostic-state-graphs.h"
+#include "graphviz.h"
+#include "xml.h"
+#include "xml-printer.h"
+#include "intl.h"
+#include "selftest.h"
+
+using namespace diagnostics::state_graphs;
+
+const char * const node_kind_strs[] = {
+ "globals",
+ "code",
+ "function",
+ "stack",
+ "stack-frame",
+ "heap",
+ "thread-local",
+ "dynalloc-buffer",
+ "variable",
+ "field",
+ "padding",
+ "element",
+ "other",
+};
+
+const char *
+diagnostics::state_graphs::node_kind_to_str (enum node_kind k)
+{
+ return node_kind_strs[static_cast<int> (k)];
+}
+
+// struct state_node_ref
+
+enum node_kind
+state_node_ref::get_node_kind () const
+{
+ const char *value = get_attr ("kind");
+ if (!value)
+ return node_kind::other;
+
+ for (size_t i = 0; i < ARRAY_SIZE (node_kind_strs); ++i)
+ if (!strcmp (node_kind_strs[i], value))
+ return static_cast<enum node_kind> (i);
+
+ return node_kind::other;
+}
+
+void
+state_node_ref::set_node_kind (enum node_kind k)
+{
+ set_attr ("kind", node_kind_to_str (k));
+}
+
+const char * const dynalloc_state_strs[] = {
+ "unknown",
+ "nonnull",
+ "unchecked",
+ "freed"
+};
+
+enum node_dynalloc_state
+state_node_ref::get_dynalloc_state () const
+{
+ const char *value = get_attr ("dynalloc-state");
+ if (!value)
+ return node_dynalloc_state::unknown;
+
+ for (size_t i = 0; i < ARRAY_SIZE (dynalloc_state_strs); ++i)
+ if (!strcmp (dynalloc_state_strs[i], value))
+ return static_cast<enum node_dynalloc_state> (i);
+
+ return node_dynalloc_state::unknown;
+}
+
+void
+state_node_ref::set_dynalloc_state (enum node_dynalloc_state s) const
+{
+ set_attr ("dynalloc-state",
+ dynalloc_state_strs[static_cast <size_t> (s)]);
+}
+
+const char *
+state_node_ref::get_dynamic_extents () const
+{
+ return m_node.get_attr (STATE_NODE_PREFIX, "dynamic-extents");
+}
+
+void
+state_node_ref::set_json_attr (const char *key,
+ std::unique_ptr<json::value> value) const
+{
+ m_node.set_json_attr (STATE_NODE_PREFIX, key, std::move (value));
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+test_node_attrs ()
+{
+ diagnostics::digraphs::digraph g;
+ diagnostics::digraphs::node n (g, "a");
+ state_node_ref node_ref (n);
+
+ ASSERT_EQ (node_ref.get_node_kind (), node_kind::other);
+ node_ref.set_node_kind (node_kind::stack);
+ ASSERT_EQ (node_ref.get_node_kind (), node_kind::stack);
+
+ ASSERT_EQ (node_ref.get_dynalloc_state (), node_dynalloc_state::unknown);
+ node_ref.set_dynalloc_state (node_dynalloc_state::freed);
+ ASSERT_EQ (node_ref.get_dynalloc_state (), node_dynalloc_state::freed);
+
+ ASSERT_EQ (node_ref.get_type (), nullptr);
+ node_ref.set_type ("const char *");
+ ASSERT_STREQ (node_ref.get_type (), "const char *");
+}
+
+/* Run all of the selftests within this file. */
+
+void
+diagnostic_state_graphs_cc_tests ()
+{
+ test_node_attrs ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-state-graphs.h b/gcc/diagnostic-state-graphs.h
new file mode 100644
index 0000000..def6d05
--- /dev/null
+++ b/gcc/diagnostic-state-graphs.h
@@ -0,0 +1,156 @@
+/* Extensions to diagnostics::digraphs to support state graphs.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+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/>. */
+
+#ifndef GCC_DIAGNOSTIC_STATE_GRAPHS_H
+#define GCC_DIAGNOSTIC_STATE_GRAPHS_H
+
+#include "diagnostic-digraphs.h"
+#include "logical-location.h"
+
+/* diagnostics::digraphs provides support for directed graphs.
+
+ diagnostics::state_graphs provides a way to extend these graphs
+ for representing "state graphs" i.e. a representation of the state
+ of memory inside a program, for use e.g. by -fanalyzer.
+
+ Specifically, nodes represent memory regions, and we use property bags
+ in these nodes to stash extra properties (e.g. what kind of memory region
+ a node is e.g. stack vs heap). */
+
+class sarif_graph;
+namespace dot { class graph; }
+
+namespace diagnostics {
+namespace state_graphs {
+
+enum class node_kind
+{
+ // Memory regions
+ globals,
+ code,
+ function, // code within a particular function
+ stack,
+ stack_frame,
+ heap_,
+ thread_local_,
+
+ /* Dynamically-allocated buffer,
+ on heap or stack (depending on parent). */
+ dynalloc_buffer,
+
+ variable,
+
+ field, // field within a struct or union
+ padding, // padding bits in a struct or union
+ element, // element within an array
+
+ other // anything else
+};
+
+extern const char *
+node_kind_to_str (enum node_kind);
+
+enum class node_dynalloc_state
+{
+ unknown,
+ nonnull,
+ unchecked,
+ freed
+};
+
+/* Prefixes to use in SARIF property bags. */
+#define STATE_GRAPH_PREFIX "gcc/diagnostic_state_graph/"
+#define STATE_NODE_PREFIX "gcc/diagnostic_state_node/"
+#define STATE_EDGE_PREFIX "gcc/diagnostic_state_edge/"
+
+/* A wrapper around a node that gets/sets attributes, using
+ the node's property bag for storage, so that the data roundtrips
+ through SARIF. */
+
+struct state_node_ref
+{
+ state_node_ref (diagnostics::digraphs::node &node)
+ : m_node (node)
+ {}
+
+ enum node_kind
+ get_node_kind () const;
+ void
+ set_node_kind (enum node_kind);
+
+ // For node_kind::stack_frame, this will be the function
+ logical_location
+ get_logical_loc () const
+ {
+ return m_node.get_logical_loc ();
+ }
+
+ // For node_kind::dynalloc_buffer
+ enum node_dynalloc_state
+ get_dynalloc_state () const;
+
+ void
+ set_dynalloc_state (enum node_dynalloc_state) const;
+
+ const char *
+ get_dynamic_extents () const;
+
+ const char *
+ get_name () const { return get_attr ("name"); }
+ void
+ set_name (const char *name) const { set_attr ("name", name); }
+
+ const char *
+ get_type () const { return get_attr ("type"); }
+ void
+ set_type (const char *type) const { set_attr ("type", type); }
+
+ const char *
+ get_value () const { return get_attr ("value"); }
+
+ const char *
+ get_index () const { return get_attr ("index"); }
+
+ const char *
+ get_attr (const char *key) const
+ {
+ return m_node.get_attr (STATE_NODE_PREFIX, key);
+ }
+
+ void
+ set_attr (const char *key, const char *value) const
+ {
+ return m_node.set_attr (STATE_NODE_PREFIX, key, value);
+ }
+
+ void
+ set_json_attr (const char *key, std::unique_ptr<json::value> value) const;
+
+ diagnostics::digraphs::node &m_node;
+};
+
+extern std::unique_ptr<dot::graph>
+make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
+ const logical_location_manager &logical_loc_mgr);
+
+} // namespace state_graphs
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTIC_STATE_GRAPHS_H */
diff --git a/gcc/diagnostic-state-to-dot.cc b/gcc/diagnostic-state-to-dot.cc
index ddae83b..8195c11 100644
--- a/gcc/diagnostic-state-to-dot.cc
+++ b/gcc/diagnostic-state-to-dot.cc
@@ -1,4 +1,4 @@
-/* Creating GraphViz .dot files from XML state documents.
+/* Creating GraphViz .dot files from diagnostic state graphs.
Copyright (C) 2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -27,81 +27,59 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
+#include "diagnostic-state-graphs.h"
+#include "graphviz.h"
#include "xml.h"
#include "xml-printer.h"
-#include "graphviz.h"
+#include "intl.h"
+
+using namespace diagnostics::state_graphs;
static int
-get_depth (const xml::element &e)
+get_depth (const diagnostics::digraphs::node &n)
{
int deepest_child = 0;
- for (auto &iter : e.m_children)
- if (xml::element *child_element = iter->dyn_cast_element ())
+ for (size_t i = 0; i < n.get_num_children (); ++i)
deepest_child = std::max (deepest_child,
- get_depth (*child_element));
+ get_depth (n.get_child (i)));
return deepest_child + 1;
}
-enum class dynalloc_state
-{
- unknown,
- nonnull,
- unchecked,
- freed
-};
-
static const char *
-get_color_for_dynalloc_state (enum dynalloc_state dynalloc_st)
+get_color_for_dynalloc_state (enum node_dynalloc_state dynalloc_st)
{
switch (dynalloc_st)
{
default:
gcc_unreachable ();
break;
- case dynalloc_state::unknown:
- case dynalloc_state::nonnull:
+ case node_dynalloc_state::unknown:
+ case node_dynalloc_state::nonnull:
return nullptr;
- case dynalloc_state::unchecked:
+ case node_dynalloc_state::unchecked:
return "#ec7a08"; // pf-orange-400
- case dynalloc_state::freed:
+ case node_dynalloc_state::freed:
return "#cc0000"; // pf-red-100
}
}
static void
set_color_for_dynalloc_state (dot::attr_list &attrs,
- enum dynalloc_state dynalloc_state)
+ enum node_dynalloc_state state)
{
- if (const char *color = get_color_for_dynalloc_state (dynalloc_state))
+ if (const char *color = get_color_for_dynalloc_state (state))
attrs.add (dot::id ("color"), dot::id (color));
}
-static enum dynalloc_state
-get_dynalloc_state (const xml::element &input_element)
-{
- const char *dyn_alloc_state = input_element.get_attr ("dynamic-alloc-state");
- if (!dyn_alloc_state)
- return dynalloc_state::unknown;
-
- if (dyn_alloc_state == std::string ("unchecked"))
- return dynalloc_state::unchecked;
-
- if (dyn_alloc_state == std::string ("nonnull"))
- return dynalloc_state::nonnull;
-
- if (dyn_alloc_state == std::string ("freed"))
- return dynalloc_state::freed;
-
- return dynalloc_state::unknown;
-}
-
class state_diagram : public dot::graph
{
public:
- state_diagram (const xml::document &input_state_doc)
- : m_next_id (0),
+ state_diagram (const diagnostics::digraphs::digraph &input_state_graph,
+ const logical_location_manager &logical_loc_mgr)
+ : m_logical_loc_mgr (logical_loc_mgr),
+ // m_next_id (0),
m_show_tags (false)
{
// "node [shape=plaintext]\n"
@@ -112,41 +90,46 @@ public:
add_stmt (std::move (attr_stmt));
}
- /* Recurse down the XML state diagram, creating subgraphs
+ /* Determine which nodes are involved in edges. */
+ for (size_t i = 0; i < input_state_graph.get_num_edges (); ++i)
+ {
+ auto &edge = input_state_graph.get_edge (i);
+ m_src_nodes.insert (&edge.get_src_node ());
+ m_dst_nodes.insert (&edge.get_dst_node ());
+ }
+
+ /* Recurse down the nodes in the state graph, creating subgraphs
and then eventually creating nodes, and recursively
- creating XML tables, adding ports for the endpoints of edges,
- and recording edges we'll want to create (into m_pending_edges). */
- xml::element *input_elmt_state_diagram
- = input_state_doc.find_child_element ("state-diagram");
- gcc_assert (input_elmt_state_diagram);
- xml::element *input_elmt_mem_regions
- = input_elmt_state_diagram->find_child_element ("memory-regions");
- if (!input_elmt_mem_regions)
- return;
+ creating XML tables, and adding ports for the endpoints of edges
+ where needed. */
+
auto root_cluster
= std::make_unique<dot::subgraph> (dot::id ("cluster_memory_regions"));
- for (auto &iter : input_elmt_mem_regions->m_children)
- on_input_xml_node (*root_cluster, *iter);
+ for (size_t i = 0; i < input_state_graph.get_num_nodes (); ++i)
+ on_input_state_node (*root_cluster,
+ state_node_ref (input_state_graph.get_node (i)));
add_stmt (std::move (root_cluster));
- /* We should now have ports for edge endpoints for all region ids.
- Use them now to create edges. */
- for (auto &pe : m_pending_edges)
+ /* Now create dot edges for edges in input_stage_graph. */
+ for (size_t i = 0; i < input_state_graph.get_num_edges (); ++i)
{
- auto search = m_region_id_to_dst_node_id.find (pe.m_dst_region_id);
- if (search != m_region_id_to_dst_node_id.end ())
- {
- auto &dst_node_id = search->second;
- auto e = std::make_unique<dot::edge_stmt> (pe.m_src_node_id,
- dst_node_id);
-
- auto dynalloc_state = m_region_id_to_dynalloc_state.find (pe.m_dst_region_id);
- if (dynalloc_state != m_region_id_to_dynalloc_state.end ())
- set_color_for_dynalloc_state (e->m_attrs,
- dynalloc_state->second);
-
- add_stmt (std::move (e));
- }
+ auto &edge = input_state_graph.get_edge (i);
+ auto &src_node = edge.get_src_node ();
+ auto &dst_node = edge.get_dst_node ();
+
+ auto src_port_id = m_src_node_to_port_id.find (&src_node);
+ if (src_port_id == m_src_node_to_port_id.end ())
+ continue;
+ auto dst_port_id = m_dst_node_to_port_id.find (&dst_node);
+ if (dst_port_id == m_dst_node_to_port_id.end ())
+ continue;
+
+ auto e = std::make_unique<dot::edge_stmt> (src_port_id->second,
+ dst_port_id->second);
+ set_color_for_dynalloc_state
+ (e->m_attrs, state_node_ref (dst_node).get_dynalloc_state ());
+
+ add_stmt (std::move (e));
}
}
@@ -165,35 +148,58 @@ private:
}
dot::id
- make_id (bool cluster = false)
+ make_id (state_node_ref state_node, bool cluster)
{
+ std::string input_node_id = state_node.m_node.get_id ();
if (cluster)
- return std::string ("cluster_") + std::to_string (m_next_id++);
+ return std::string ("cluster_") + input_node_id;
else
- return std::string ("id_") + std::to_string (m_next_id++);
+ return input_node_id;
}
bool
- starts_node_p (const xml::element &e)
+ starts_node_p (state_node_ref state_node)
{
- if (e.m_kind == "stack"
- || e.m_kind == "heap-buffer"
- || e.m_kind == "variable") // e.g. within globals
- return true;
- return false;
+ switch (state_node.get_node_kind ())
+ {
+ default:
+ return false;
+
+ case node_kind::stack:
+ /* We want all frames in the stack in the same table,
+ so they are grouped. */
+ case node_kind::dynalloc_buffer:
+ case node_kind::variable:
+ return true;
+ }
}
- void
- on_input_xml_node (dot::subgraph &parent_subgraph,
- xml::node &input_node)
+ const char *
+ get_label_for_node (state_node_ref state_node)
{
- xml::element *input_element = input_node.dyn_cast_element ();
- if (!input_element)
- return;
+ switch (state_node.get_node_kind ())
+ {
+ default:
+ return nullptr;
+
+ case node_kind::globals:
+ return _("Globals");
+ case node_kind::code:
+ return _("Code");
+ case node_kind::stack:
+ return _("Stack");
+ case node_kind::heap_:
+ return _("Heap");
+ }
+ }
- dot::id sg_id = make_id (true);
+ void
+ on_input_state_node (dot::subgraph &parent_subgraph,
+ state_node_ref state_node)
+ {
+ dot::id sg_id = make_id (state_node, true);
- if (starts_node_p (*input_element))
+ if (starts_node_p (state_node))
{
// Create node with table
xml::element table ("table", false);
@@ -202,14 +208,14 @@ private:
xp.set_attr ("cellborder", "1");
xp.set_attr ("cellspacing", "0");
- const int max_depth = get_depth (*input_element);
+ const int max_depth = get_depth (state_node.m_node);
const int num_columns = max_depth + 2;
- dot::id id_of_node = make_id ();
- on_xml_node (id_of_node, xp, *input_element,
- max_depth, 0, num_columns);
+ dot::id id_of_dot_node = make_id (state_node, false);
+ on_node_in_table (id_of_dot_node, xp, state_node,
+ max_depth, 0, num_columns);
- auto node = std::make_unique<dot::node_stmt> (std::move (id_of_node));
+ auto node = std::make_unique<dot::node_stmt> (std::move (id_of_dot_node));
node->m_attrs.add (dot::id ("shape"),
dot::id ("plaintext"));
@@ -224,12 +230,13 @@ private:
{
auto child_subgraph = std::make_unique<dot::subgraph> (std::move (sg_id));
- if (const char *label = input_element->get_attr ("label"))
+ if (const char *label = get_label_for_node (state_node))
child_subgraph->add_attr (dot::id ("label"), dot::id (label));
// recurse:
- for (auto &iter : input_element->m_children)
- on_input_xml_node (*child_subgraph, *iter);
+ for (size_t i = 0; i < state_node.m_node.get_num_children (); ++i)
+ on_input_state_node (*child_subgraph,
+ state_node.m_node.get_child (i));
parent_subgraph.m_stmt_list.add_stmt (std::move (child_subgraph));
}
}
@@ -237,13 +244,13 @@ private:
enum class style { h1, h2 };
void
- add_title_tr (const dot::id &id_of_node,
+ add_title_tr (const dot::id &id_of_dot_node,
xml::printer &xp,
int num_columns,
- const xml::element &input_element,
+ state_node_ref state_node,
std::string heading,
enum style styl,
- enum dynalloc_state dynalloc_state)
+ enum node_dynalloc_state dynalloc_state)
{
xp.push_tag ("tr", true);
xp.push_tag ("td", false);
@@ -282,183 +289,194 @@ private:
xp.add_text (std::move (heading));
xp.pop_tag ("font");
- maybe_add_dst_port (id_of_node, xp, input_element);
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
xp.pop_tag ("td");
xp.pop_tag ("tr");
}
- /* Recursively add <TR> to XP for INPUT_NODE and its descendents. */
+ /* Recursively add <TR> to XP for STATE_NODE and its descendents. */
void
- on_xml_node (const dot::id &id_of_node,
- xml::printer &xp,
- xml::node &input_node,
- int max_depth,
- int depth,
- int num_columns)
+ on_node_in_table (const dot::id &id_of_dot_node,
+ xml::printer &xp,
+ state_node_ref state_node,
+ int max_depth,
+ int depth,
+ int num_columns)
{
bool recurse = true;
+ auto input_node_kind = state_node.get_node_kind ();
- xml::element *input_element = input_node.dyn_cast_element ();
- if (!input_element)
- return;
-
- if (input_element->m_kind == "concrete-bindings")
- return;
- if (input_element->m_kind == "padding")
- return;
-
- if (input_element->m_kind == "stack")
- {
- add_title_tr (id_of_node, xp, num_columns, *input_element, "Stack",
- style::h1, dynalloc_state::unknown);
- }
- else if (input_element->m_kind == "stack-frame")
- {
- if (const char *function = input_element->get_attr ("function"))
- add_title_tr (id_of_node, xp, num_columns, *input_element,
- std::string ("Frame: ") + function,
- style::h2, dynalloc_state::unknown);
- }
- else if (input_element->m_kind == "heap-buffer")
+ switch (input_node_kind)
{
- const char *extents = input_element->get_attr ("dynamic-extents");
- enum dynalloc_state dynalloc_st = get_dynalloc_state (*input_element);
- if (auto region_id = input_element->get_attr ("region_id"))
- m_region_id_to_dynalloc_state[region_id] = dynalloc_st;
- const char *type = input_element->get_attr ("type");
- pretty_printer pp;
- switch (dynalloc_st)
- {
- default:
- gcc_unreachable ();
-
- case dynalloc_state::unknown:
- case dynalloc_state::nonnull:
- if (type)
- {
+ case node_kind::padding:
+ case node_kind::other:
+ return;
+
+ case node_kind::stack:
+ add_title_tr (id_of_dot_node, xp, num_columns, state_node, "Stack",
+ style::h1,
+ node_dynalloc_state::unknown);
+ break;
+ case node_kind::stack_frame:
+ if (auto logical_loc = state_node.get_logical_loc ())
+ if (const char *function
+ = m_logical_loc_mgr.get_short_name (logical_loc))
+ add_title_tr (id_of_dot_node, xp, num_columns, state_node,
+ std::string ("Frame: ") + function,
+ style::h2,
+ node_dynalloc_state::unknown);
+ break;
+ case node_kind::dynalloc_buffer:
+ {
+ enum node_dynalloc_state dynalloc_st
+ = state_node.get_dynalloc_state ();
+ const char *extents = state_node.get_dynamic_extents ();
+ const char *type = state_node.get_type ();
+ pretty_printer pp;
+ switch (dynalloc_st)
+ {
+ default:
+ gcc_unreachable ();
+
+ case node_dynalloc_state::unknown:
+ case node_dynalloc_state::nonnull:
+ if (type)
+ {
if (extents)
pp_printf (&pp, "%s (%s byte allocation)",
type, extents);
else
pp_printf (&pp, "%s", type);
- }
- else
+ }
+ else
+ {
+ if (extents)
+ pp_printf (&pp, "%s byte allocation",
+ extents);
+ }
+ break;
+
+ case node_dynalloc_state::unchecked:
+ if (type)
+ {
+ if (extents)
+ pp_printf (&pp, "%s (unchecked %s byte allocation)",
+ type, extents);
+ }
+ else
+ {
+ if (extents)
+ pp_printf (&pp, "Unchecked %s byte allocation",
+ extents);
+ }
+ break;
+
+ case node_dynalloc_state::freed:
+ // TODO: show deallocator
+ // TODO: show deallocation event
+ pp_printf (&pp, "Freed buffer");
+ break;
+ }
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
+ add_title_tr (id_of_dot_node, xp, num_columns, state_node,
+ pp_formatted_text (&pp),
+ style::h2,
+ dynalloc_st);
+ }
+ break;
+
+ default:
+ {
+ xp.push_tag ("tr", true);
+
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
+
+ if (depth > 0)
+ {
+ /* Indent, by create a <td> spanning "depth" columns. */
+ xp.push_tag ("td", false);
+ xp.set_attr ("colspan", std::to_string (depth));
+ xp.add_text (" "); // graphviz doesn't like <td/>
+ xp.pop_tag ("td");
+ }
+
+ switch (input_node_kind)
+ {
+ default:
+ break;
+ case node_kind::variable:
{
- if (extents)
- pp_printf (&pp, "%s byte allocation",
- extents);
+ const char *name = state_node.get_name ();
+ gcc_assert (name);
+ xp.push_tag ("td", false);
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
+ push_src_text (xp);
+ xp.add_text (name);
+ pop_src_text (xp);
+ xp.pop_tag ("td");
}
- break;
-
- case dynalloc_state::unchecked:
- if (type)
+ break;
+ case node_kind::element:
{
- if (extents)
- pp_printf (&pp, "%s (unchecked %s byte allocation)",
- type, extents);
+ const char *index = state_node.get_index ();
+ gcc_assert (index);
+ xp.push_tag ("td", false);
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
+ push_src_text (xp);
+ xp.add_text ("[");
+ xp.add_text (index);
+ xp.add_text ("]");
+ pop_src_text (xp);
+ xp.pop_tag ("td");
}
- else
+ break;
+ case node_kind::field:
{
- if (extents)
- pp_printf (&pp, "Unchecked %s byte allocation",
- extents);
+ const char *name = state_node.get_name ();
+ gcc_assert (name);
+ xp.push_tag ("td", false);
+ maybe_add_dst_port (id_of_dot_node, xp, state_node);
+ push_src_text (xp);
+ xp.add_text (".");
+ xp.add_text (name);
+ pop_src_text (xp);
+ xp.pop_tag ("td");
}
- break;
-
- case dynalloc_state::freed:
- // TODO: show deallocator
- // TODO: show deallocation event
- pp_printf (&pp, "Freed buffer");
- break;
- }
- add_title_tr (id_of_node, xp, num_columns, *input_element,
- pp_formatted_text (&pp),
- style::h2,
- dynalloc_st);
- }
- else
- {
- xp.push_tag ("tr", true);
- if (depth > 0)
- {
- /* Indent, by create a <td> spanning "depth" columns. */
- xp.push_tag ("td", false);
- xp.set_attr ("colspan", std::to_string (depth));
- xp.add_text (" "); // graphviz doesn't like <td/>
- xp.pop_tag ("td");
- }
- if (m_show_tags)
- {
- // Debug: show XML tag
- xp.push_tag ("td", false);
- xp.add_text ("<");
- xp.add_text (input_element->m_kind);
- xp.add_text (">");
- xp.pop_tag ("td");
- }
- if (input_element->m_kind == "variable")
- {
- const char *name = input_element->get_attr ("name");
- gcc_assert (name);
- xp.push_tag ("td", false);
- maybe_add_dst_port (id_of_node, xp, *input_element);
- push_src_text (xp);
- xp.add_text (name);
- pop_src_text (xp);
- xp.pop_tag ("td");
- }
- else if (input_element->m_kind == "element")
- {
- const char *index = input_element->get_attr ("index");
- gcc_assert (index);
- xp.push_tag ("td", false);
- maybe_add_dst_port (id_of_node, xp, *input_element);
- push_src_text (xp);
- xp.add_text ("[");
- xp.add_text (index);
- xp.add_text ("]");
- pop_src_text (xp);
- xp.pop_tag ("td");
- }
- else if (input_element->m_kind == "field")
- {
- const char *name = input_element->get_attr ("name");
- gcc_assert (name);
- xp.push_tag ("td", false);
- maybe_add_dst_port (id_of_node, xp, *input_element);
- push_src_text (xp);
- xp.add_text (".");
- xp.add_text (name);
- pop_src_text (xp);
- xp.pop_tag ("td");
- }
- if (const char *type = input_element->get_attr ("type"))
- {
- xp.push_tag ("td", false);
- if (max_depth > depth)
- xp.set_attr ("colspan", std::to_string (max_depth - depth));
- xp.set_attr ("align", "right");
- push_src_text (xp);
- xp.add_text (type);
- pop_src_text (xp);
- xp.pop_tag ("td");
- }
- if (auto value = input_element->find_child_element ("value-of-region"))
- {
- xp.push_tag ("td", false);
- for (auto &iter : value->m_children)
- if (auto child_element = iter->dyn_cast_element ())
- print_value (id_of_node, xp, *child_element);
- xp.pop_tag ("td");
- recurse = false;
- }
- xp.pop_tag ("tr");
+ break;
+ }
+
+ if (const char *type = state_node.get_type ())
+ {
+ xp.push_tag ("td", false);
+ xp.set_attr ("align", "right");
+ push_src_text (xp);
+ xp.add_text (type);
+ pop_src_text (xp);
+ xp.pop_tag ("td");
+ }
+
+ if (const char *value = state_node.get_value ())
+ {
+ xp.push_tag ("td", false);
+ xp.set_attr ("align", "left");
+ maybe_add_src_port (id_of_dot_node, xp, state_node);
+ push_src_text (xp);
+ xp.add_text (value);
+ pop_src_text (xp);
+ xp.pop_tag ("td");
+ recurse = false;
+ }
+ xp.pop_tag ("tr");
+ }
+ break;
}
if (recurse)
- for (auto &iter : input_element->m_children)
- on_xml_node (id_of_node, xp, *iter, max_depth, depth + 1, num_columns);
+ for (size_t i = 0; i < state_node.m_node.get_num_children (); ++i)
+ on_node_in_table (id_of_dot_node, xp,
+ state_node.m_node.get_child (i),
+ max_depth, depth + 1, num_columns);
}
void
@@ -474,64 +492,63 @@ private:
xp.pop_tag ("font");
}
+ /* If STATE_NODE is in m_src_nodes, add a port to XP for possible
+ incoming edges to use. */
+
void
- print_value (const dot::id &id_of_node,
- xml::printer &xp,
- xml::element &input_element)
+ maybe_add_src_port (const dot::id &id_of_dot_node,
+ xml::printer &xp,
+ state_node_ref state_node)
{
- if (input_element.m_kind == "pointer-to-region")
- if (const char *dst_region_id = input_element.get_attr ("region_id"))
- {
- dot::id src_port_id = make_id ();
- xp.set_attr ("port", src_port_id.m_str);
- m_pending_edges.push_back
- ({dot::node_id (id_of_node,
- dot::port (src_port_id,
- dot::compass_pt::e)),
- dst_region_id});
- }
-
- if (input_element.m_kind == "uninitialized")
- {
- xp.add_text ("(uninitialized)");
- return;
- }
+ auto iter = m_src_nodes.find (&state_node.m_node);
+ if (iter == m_src_nodes.end ())
+ return;
- if (auto dump_text = input_element.get_attr ("dump-text"))
- xp.add_text (dump_text);
+ dot::id src_id = make_id (state_node, false);
+ dot::node_id node_id (id_of_dot_node,
+ dot::port (src_id,
+ dot::compass_pt::e));
+ m_src_node_to_port_id.insert ({&state_node.m_node, node_id});
+ xp.set_attr ("port", src_id.m_str);
}
- /* If INPUT_ELEMENT has a "region_id", add a port to XP for possible
+ /* If STATE_NODE is in m_dst_nodes, add a port to XP for possible
incoming edges to use. */
void
- maybe_add_dst_port (const dot::id &id_of_node,
+ maybe_add_dst_port (const dot::id &id_of_dot_node,
xml::printer &xp,
- const xml::element &input_element)
+ state_node_ref state_node)
{
- if (const char *region_id = input_element.get_attr ("region_id"))
- {
- dot::id dst_id = make_id ();
- dot::node_id node_id (id_of_node,
- dot::port (dst_id/*,
- dot::compass_pt::w*/));
- xp.set_attr ("port", dst_id.m_str);
- m_region_id_to_dst_node_id.emplace (std::string (region_id),
- std::move (node_id));
- }
- }
+ auto iter = m_dst_nodes.find (&state_node.m_node);
+ if (iter == m_dst_nodes.end ())
+ return;
+ dot::id dst_id = make_id (state_node, false);
+ dot::node_id node_id (id_of_dot_node,
+ dot::port (dst_id/*,
+ dot::compass_pt::w*/));
+ m_dst_node_to_port_id.insert ({&state_node.m_node, node_id});
+ xp.set_attr ("port", dst_id.m_str);
+ }
private:
- int m_next_id;
- std::vector<pending_edge> m_pending_edges;
- std::map<std::string, dot::node_id> m_region_id_to_dst_node_id;
- std::map<std::string, enum dynalloc_state> m_region_id_to_dynalloc_state;
+ const logical_location_manager &m_logical_loc_mgr;
+
+ /* All nodes involved in edges (and thus will need a port). */
+ std::set<diagnostics::digraphs::node *> m_src_nodes;
+ std::set<diagnostics::digraphs::node *> m_dst_nodes;
+
+ std::map<diagnostics::digraphs::node *, dot::node_id> m_src_node_to_port_id;
+ std::map<diagnostics::digraphs::node *, dot::node_id> m_dst_node_to_port_id;
+
bool m_show_tags;
};
std::unique_ptr<dot::graph>
-make_dot_graph_from_xml_state (const xml::document &xml_state)
+diagnostics::state_graphs::
+make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
+ const logical_location_manager &logical_loc_mgr)
{
- return std::make_unique<state_diagram> (xml_state);
+ return std::make_unique<state_diagram> (state_graph, logical_loc_mgr);
}
diff --git a/gcc/diagnostic-state.h b/gcc/diagnostic-state.h
deleted file mode 100644
index 68c3e00..0000000
--- a/gcc/diagnostic-state.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Capturing changing state in diagnostic paths.
- Copyright (C) 2025 Free Software Foundation, Inc.
- Contributed by David Malcolm <dmalcolm@redhat.com>.
-
-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/>. */
-
-#ifndef GCC_DIAGNOSTIC_STATE_H
-#define GCC_DIAGNOSTIC_STATE_H
-
-/* We want to be able to express changing program states in diagnostic paths,
- so that we can emit this in HTML and SARIF output, and to keep this
- separate from implementation details of -fanalyzer.
-
- For now, we use xml::document as the type in the diagnostic subsystem
- for (optionally) tracking the state at a diagnostic_event. */
-
-namespace xml { class document; }
-namespace dot { class graph; }
-
-extern std::unique_ptr<dot::graph>
-make_dot_graph_from_xml_state (const xml::document &xml_state);
-
-#endif /* GCC_DIAGNOSTIC_STATE_H */
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 088390b..7e5ac87 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -1624,6 +1624,14 @@ diagnostic_context::report_verbatim (text_info &text)
}
}
+void
+diagnostic_context::
+report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg)
+{
+ for (auto sink : m_output_sinks)
+ sink->report_global_digraph (ldg);
+}
+
/* Get the number of digits in the decimal representation of VALUE. */
int
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 00f6e35..04eb2b1 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -26,6 +26,12 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print.h"
#include "diagnostic-core.h"
+namespace diagnostics {
+ namespace digraphs {
+ class lazy_digraph;
+ } // namespace digraphs
+} // namespace diagnostics
+
namespace text_art
{
class theme;
@@ -616,6 +622,11 @@ public:
bool report_diagnostic (diagnostic_info *);
void report_verbatim (text_info &);
+ /* Report a directed graph associated with the run as a whole
+ to any sinks that support directed graphs. */
+ void
+ report_global_digraph (const diagnostics::digraphs::lazy_digraph &);
+
diagnostic_t
classify_diagnostic (diagnostic_option_id option_id,
diagnostic_t new_kind,
diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi
index 4dd14c8..4efba4d 100644
--- a/gcc/doc/analyzer.texi
+++ b/gcc/doc/analyzer.texi
@@ -624,17 +624,17 @@ which writes out the diagnostics in HTML form, and generates SVG state
diagrams visualizing the state of memory at each event (inspired by the
"ddd" debugger). These can be seen by pressing 'j' and 'k' to single-step
forward and backward through events. Note that these SVG diagrams are
-created from an intermediate XML representation generated from
-@code{program_state} objects. The XML representation can be easier to
+created from an intermediate SARIF directed graph representation generated from
+@code{program_state} objects. The SARIF representation can be easier to
read - for example, rather than storing the contents of memory via byte
offsets, it uses fields for structs and element indexes for arrays,
recursively. However it is a different representation, and thus bugs could
be hidden by this transformation. Generating the SVG diagrams requires
an invocation of "dot" per event, so it noticeably slows down diagnostic
-emission, hence the opt-in command-line flag. The XML and ``dot''
+emission, hence the opt-in command-line flag. The SARIF and ``dot''
representations can be seen by @code{__analyzer_dump_xml} and
@code{__analyzer_dump_dot} below (writing them to stderr), or by adding
-@code{show-state-diagrams-xml=yes} and
+@code{show-state-diagrams-sarif=yes} and
@code{show-state-diagrams-dot-src=yes} to the html sink, which shows
them within the generated HTML next to the generated SVG.
@@ -792,9 +792,9 @@ will emit a warning describing the state of the 2nd argument
a name matching the 1st argument (which must be a string literal).
This is for use when debugging, and may be of use in DejaGnu tests.
-@item __analyzer_dump_xml
+@item __analyzer_dump_sarif
@smallexample
-__analyzer_dump_xml ();
+__analyzer_dump_sarif ();
@end smallexample
will dump the copious information about the analyzer's state each time it
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d49f291..9a1aa37 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6143,10 +6143,10 @@ end-users, and subject to change or removal without notice:
@table @gcctabopt
-@item xml-state=@r{[}yes@r{|}no@r{]}
+@item state-graphs=@r{[}yes@r{|}no@r{]}
This is a debugging feature and defaults to @code{no}.
-If @code{xml-state=yes}, then attempt to capture detailed state information
-from @option{-fanalyzer} in the generated SARIF.
+If @code{state-graphs=yes}, then attempt to capture detailed state
+information from @option{-fanalyzer} in the generated SARIF.
@end table
@@ -6194,11 +6194,11 @@ then if @code{show-state-diagrams=yes},
the generated state diagrams will also show the .dot source input to
GraphViz used for the diagram.
-@item show-state-diagrams-xml=@r{[}yes@r{|}no@r{]}
+@item show-state-diagrams-sarif=@r{[}yes@r{|}no@r{]}
This is a debugging feature and defaults to @code{no}.
-If @code{show-state-diagrams-xml=yes}
+If @code{show-state-diagrams-sarif=yes}
then if @code{show-state-diagrams=yes}, the generated state diagrams will
-also show an XML representation of the state.
+also show a SARIF representation of the state.
@end table
diff --git a/gcc/doc/libgdiagnostics/topics/compatibility.rst b/gcc/doc/libgdiagnostics/topics/compatibility.rst
index 6d8c92f..0e078d0 100644
--- a/gcc/doc/libgdiagnostics/topics/compatibility.rst
+++ b/gcc/doc/libgdiagnostics/topics/compatibility.rst
@@ -188,3 +188,34 @@ supporting command-line options and SARIF playback:
* :func:`diagnostic_manager_add_sink_from_spec`
* :func:`diagnostic_manager_set_analysis_target`
+
+.. _LIBGDIAGNOSTICS_ABI_3:
+
+``LIBGDIAGNOSTICS_ABI_3``
+-------------------------
+``LIBGDIAGNOSTICS_ABI_3`` covers the addition of these functions for
+working with directed graphs:
+
+ * :func:`diagnostic_manager_new_graph`
+
+ * :func:`diagnostic_manager_take_global_graph`
+
+ * :func:`diagnostic_take_graph`
+
+ * :func:`diagnostic_graph_release`
+
+ * :func:`diagnostic_graph_set_description`
+
+ * :func:`diagnostic_graph_add_node`
+
+ * :func:`diagnostic_graph_add_edge`
+
+ * :func:`diagnostic_graph_get_node_by_id`
+
+ * :func:`diagnostic_graph_get_edge_by_id`
+
+ * :func:`diagnostic_node_set_label`
+
+ * :func:`diagnostic_node_set_location`
+
+ * :func:`diagnostic_node_set_logical_location`
diff --git a/gcc/doc/libgdiagnostics/topics/graphs.rst b/gcc/doc/libgdiagnostics/topics/graphs.rst
new file mode 100644
index 0000000..b976013
--- /dev/null
+++ b/gcc/doc/libgdiagnostics/topics/graphs.rst
@@ -0,0 +1,197 @@
+.. Copyright (C) 2025 Free Software Foundation, Inc.
+ Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+ This 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see
+ <https://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Graphs
+======
+
+.. type:: diagnostic_graph
+
+SARIF has support for capturing directed graphs (such as callgraphs
+and control flow graphs), both at the level of the run as a whole,
+and at the level of individual results.
+
+libgdiagnostics supports this with the following entrypoints, allowing
+directed graphs to be
+
+* created (with :func:`diagnostic_manager_new_graph`)
+
+* reported "globally" (with :func:`diagnostic_manager_take_global_graph`)
+
+* reported as part of a :type:`diagnostic` (with :func:`diagnostic_take_graph`), or
+
+* discarded (with :func:`diagnostic_graph_release`).
+
+.. function:: diagnostic_graph * diagnostic_manager_new_graph (diagnostic_manager *manager)
+
+ Create a new directed graph.
+
+ The resulting graph is owned by the caller and must have one of
+ :func:`diagnostic_manager_take_global_graph`,
+ :func:`diagnostic_take_graph`,
+ or :func:`diagnostic_graph_release` called on it to avoid leaks.
+
+ The parameter ``manager`` must be non-null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: void diagnostic_manager_take_global_graph (diagnostic_manager *manager, \
+ diagnostic_graph *graph)
+
+ Report this graph "globally", taking ownership of it.
+ This won't appear in text sinks, but in SARIF sinks the graph will be
+ added to theRun.graphs (SARIF v2.1.0 3.14.20).
+
+ Parameters ``manager`` and ``graph`` must both be non-null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: void diagnostic_take_graph (diagnostic *diag, \
+ diagnostic_graph *graph)
+
+ Add this graph to ``diag``, transferring ownership of it to ``diag``.
+ This won't appear in text sinks, but in SARIF sinks the graph will be
+ added to theResult.graphs (SARIF v2.1.0 3.27.19).
+
+ Parameters ``diag`` and ``graph`` must both be non-null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: void diagnostic_graph_release (diagnostic_graph *graph)
+
+ Release ``graph`` which must still be owned by the caller
+ i.e. it must *not* have had
+ :func:`diagnostic_manager_take_global_graph` or
+ :func:`diagnostic_take_graph` called on it.
+
+ Parameters ``graph`` can be null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+
+.. function:: void diagnostic_graph_set_description (diagnostic_graph *graph, \
+ const char *description)
+
+ Set the description of ``graph`` for use in the value of the
+ SARIF ``description`` property (SARIF v2.1.0 section 3.39.2).
+
+ The parameter ``graph`` must be non-null.
+ The parameter ``description`` can be null, for clearing any existing
+ description.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: diagnostic_node * diagnostic_graph_add_node (diagnostic_graph *graph, \
+ const char *node_id, \
+ diagnostic_node *parent_node)
+
+ Create and add a new node within ``graph`` with the given `id``.
+ The id must be unique within nodes in ``graph``.
+
+ The parameters ``graph`` and ``id`` must be non-null.
+
+ ``parent_node`` can be NULL (for a top-level node in the graph),
+ or non-null for a child node, allowing for arbitrary nesting of
+ nodes.
+
+ The new node is owned by ``graph``.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: diagnostic_edge * diagnostic_graph_add_edge (diagnostic_graph *graph, \
+ const char *edge_id, \
+ diagnostic_node *src_node, \
+ diagnostic_node *dst_node, \
+ const char *label)
+
+ Create and add a new edge within ``graph``.
+
+ The parameters ``graph``, ``src_node`` and ``dest_node``
+ must be non-null.
+
+ If non-null, then ``edge_id`` must be unique within ``graph``;
+ if ``edge_id`` is null then a unique id of the form "edge0", "edge1",
+ etc will be used automatically.
+
+ If non-null, then ``label`` will be used for the value of the
+ SARIF ``label`` property (SARIF v2.1.0 section 3.41.3).
+
+ The new edge is owned by ``graph``.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: diagnostic_node *diagnostic_graph_get_node_by_id (diagnostic_graph *graph, \
+ const char *node_id)
+
+ Get the node in ``graph`` with the given id, or null.
+
+ The parameters ``graph`` and ``node_id`` must be non-null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: diagnostic_edge *diagnostic_graph_get_edge_by_id (diagnostic_graph *graph, \
+ const char *edge_id)
+
+ Get the edge in ``graph`` with the given id, or null.
+
+ The parameters ``graph`` and ``edge_id`` must be non-null.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+
+.. type:: diagnostic_node
+
+.. function:: void diagnostic_node_set_label (diagnostic_node *node, \
+ const char *label)
+
+ Set the label of ``node`` for use in the value of the
+ SARIF ``label`` property (SARIF v2.1.0 section 3.40.3).
+
+ The parameter ``node`` must be non-null.
+ The parameter ``label`` can be null, for clearing any existing
+ label.
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: void diagnostic_node_set_location (diagnostic_node *node, \
+ const diagnostic_physical_location *loc)
+
+ Set the physical location of ``node``, if any.
+
+ The parameter ``node`` must be non-null.
+ The parameter ``loc`` can be null, for clearing any existing
+ location.
+
+ If set, the value will be used by SARIF sinks within the
+ ``location`` property (SARIF v2.1.0 section 3.40.4).
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
+
+.. function:: void diagnostic_node_set_logical_location (diagnostic_node *node, \
+ const diagnostic_logical_location *logical_loc)
+
+ Set the logical location of ``node``, if any.
+
+ The parameter ``node`` must be non-null.
+ The parameter ``logical_loc`` _can be null, for clearing any existing
+ location.
+
+ If set, the value will be used by SARIF sinks within the
+ ``location`` property (SARIF v2.1.0 section 3.40.4).
+
+ This function was added in :ref:`LIBGDIAGNOSTICS_ABI_3`.
diff --git a/gcc/doc/libgdiagnostics/topics/index.rst b/gcc/doc/libgdiagnostics/topics/index.rst
index 6eb3ed6..966f5ef 100644
--- a/gcc/doc/libgdiagnostics/topics/index.rst
+++ b/gcc/doc/libgdiagnostics/topics/index.rst
@@ -35,5 +35,6 @@ Topic reference
execution-paths.rst
text-output.rst
sarif.rst
+ graphs.rst
ux.rst
compatibility.rst
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 168c475..b4fadac 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,30 @@
+2025-07-11 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/106135
+ * decl.cc (build_sym): Emit an error if a symbol associated by
+ an IMPORT, ONLY or IMPORT, all statement is being redeclared.
+ (gfc_match_import): Parse and check the F2018 versions of the
+ IMPORT statement. For scopes other than and interface body, if
+ the symbol cannot be found in the host scope, generate it and
+ set it up such that gfc_fixup_sibling_symbols can transfer its
+ 'imported attribute' if it turnes out to be a not yet parsed
+ procedure. Test for violations of C897-8100.
+ * gfortran.h : Add 'import_only' to the gfc_symtree structure.
+ Add the enum, 'importstate', which is used for values the new
+ field 'import_state' in gfc_namespace.
+ * parse.cc (gfc_fixup_sibling_symbols): Transfer the attribute
+ 'imported' to the new symbol.
+ * resolve.cc (check_sym_import_status, check_import_status):
+ New functions to test symbols and expressions for violations of
+ F2018:C8102.
+ (resolve_call): Test the 'resolved_sym' against C8102 by a call
+ to 'check_sym_import_status'.
+ (gfc_resolve_expr): If the expression is OK and an IMPORT
+ statement has been registered in the current scope, test C102
+ by calling 'check_import_status'.
+ (resolve_select_type): Test the declared derived type in TYPE
+ IS and CLASS IS statements.
+
2025-07-08 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/120637
diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi
index da085d1..0b893e8 100644
--- a/gcc/fortran/invoke.texi
+++ b/gcc/fortran/invoke.texi
@@ -1170,6 +1170,10 @@ A @code{CHARACTER} variable is declared with negative length.
With @option{-fopenmp}, for fixed-form source code, when an @code{omx}
vendor-extension sentinel is encountered. (The equivalent @code{ompx},
used in free-form source code, is diagnosed by default.)
+
+@item
+With @option{-fopenacc}, when using named constances with clauses that
+take a variable as doing so has no effect.
@end itemize
@opindex Wtabs
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index fe0a47a..f1acc00 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -8895,15 +8895,21 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
if (list == OMP_LIST_MAP
&& n->sym->attr.flavor == FL_PARAMETER)
{
+ /* OpenACC since 3.4 permits for Fortran named constants, but
+ permits removing then as optimization is not needed and such
+ ignore them. Likewise below for FIRSTPRIVATE. */
if (openacc)
- gfc_error ("Object %qs is not a variable at %L; parameters"
- " cannot be and need not be copied", n->sym->name,
- &n->where);
+ gfc_warning (OPT_Wsurprising, "Clause for object %qs at %L is "
+ "ignored as parameters need not be copied",
+ n->sym->name, &n->where);
else
gfc_error ("Object %qs is not a variable at %L; parameters"
" cannot be and need not be mapped", n->sym->name,
&n->where);
}
+ else if (openacc && n->sym->attr.flavor == FL_PARAMETER)
+ gfc_warning (OPT_Wsurprising, "Clause for object %qs at %L is ignored"
+ " as it is a parameter", n->sym->name, &n->where);
else if (list != OMP_LIST_USES_ALLOCATORS)
gfc_error ("Object %qs is not a variable at %L", n->sym->name,
&n->where);
@@ -12756,9 +12762,21 @@ gfc_resolve_oacc_declare (gfc_namespace *ns)
&& (n->sym->attr.flavor != FL_PROCEDURE
|| n->sym->result != n->sym))
{
- gfc_error ("Object %qs is not a variable at %L",
- n->sym->name, &oc->loc);
- continue;
+ if (n->sym->attr.flavor != FL_PARAMETER)
+ {
+ gfc_error ("Object %qs is not a variable at %L",
+ n->sym->name, &oc->loc);
+ continue;
+ }
+ /* Note that OpenACC 3.4 permits name constants, but the
+ implementation is permitted to ignore the clause;
+ as semantically, device_resident kind of makes sense
+ (and the wording with it is a bit odd), the warning
+ is suppressed. */
+ if (list != OMP_LIST_DEVICE_RESIDENT)
+ gfc_warning (OPT_Wsurprising, "Object %qs at %L is ignored as"
+ " parameters need not be copied", n->sym->name,
+ &oc->loc);
}
if (n->expr && n->expr->ref->type == REF_ARRAY)
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index a2e70fc..f3d7cd4 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -2792,8 +2792,13 @@ gfc_trans_omp_variable_list (enum omp_clause_code code,
gfc_omp_namelist *namelist, tree list,
bool declare_simd)
{
+ /* PARAMETER (named constants) are excluded as OpenACC 3.4 permits them now
+ as 'var' but permits compilers to ignore them. In expressions, it should
+ have been replaced by the value (and this function should not be called
+ anyway) and for var-using clauses, they should just be skipped. */
for (; namelist != NULL; namelist = namelist->next)
- if (namelist->sym->attr.referenced || declare_simd)
+ if ((namelist->sym->attr.referenced || declare_simd)
+ && namelist->sym->attr.flavor != FL_PARAMETER)
{
tree t = gfc_trans_omp_variable (namelist->sym, declare_simd);
if (t != error_mark_node)
@@ -4029,7 +4034,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
case OMP_LIST_MAP:
for (; n != NULL; n = n->next)
{
- if (!n->sym->attr.referenced)
+ if (!n->sym->attr.referenced
+ || n->sym->attr.flavor == FL_PARAMETER)
continue;
location_t map_loc = gfc_get_location (&n->where);
@@ -4986,7 +4992,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
case OMP_LIST_CACHE:
for (; n != NULL; n = n->next)
{
- if (!n->sym->attr.referenced)
+ if (!n->sym->attr.referenced
+ && n->sym->attr.flavor != FL_PARAMETER)
continue;
switch (list)
diff --git a/gcc/graphviz.h b/gcc/graphviz.h
index 5943589..9a0fe6f 100644
--- a/gcc/graphviz.h
+++ b/gcc/graphviz.h
@@ -311,6 +311,16 @@ struct node_id : public ast_node
m_port = std::make_unique<port> (*other.m_port);
}
+ node_id &operator= (const node_id &other)
+ {
+ m_id = other.m_id;
+ if (other.m_port)
+ m_port = std::make_unique<port> (*other.m_port);
+ else
+ m_port = nullptr;
+ return *this;
+ }
+
void print (writer &w) const final override;
id m_id;
diff --git a/gcc/json.h b/gcc/json.h
index 156c086d..c706f2a 100644
--- a/gcc/json.h
+++ b/gcc/json.h
@@ -130,6 +130,7 @@ class value
void DEBUG_FUNCTION dump () const;
virtual object *dyn_cast_object () { return nullptr; }
+ virtual string *dyn_cast_string () { return nullptr; }
static int compare (const json::value &val_a, const json::value &val_b);
@@ -184,6 +185,9 @@ class object : public value
static int compare (const json::object &obj_a, const json::object &obj_b);
+ size_t get_num_keys () const { return m_keys.length (); }
+ const char *get_key (size_t i) const { return m_keys[i]; }
+
std::unique_ptr<object> clone_as_object () const;
private:
@@ -284,6 +288,7 @@ class string : public value
enum kind get_kind () const final override { return JSON_STRING; }
void print (pretty_printer *pp, bool formatted) const final override;
std::unique_ptr<value> clone () const final override;
+ string *dyn_cast_string () final override { return this; }
const char *get_string () const { return m_utf8; }
size_t get_length () const { return m_len; }
diff --git a/gcc/libgdiagnostics++.h b/gcc/libgdiagnostics++.h
index 93b8f90..4beee44 100644
--- a/gcc/libgdiagnostics++.h
+++ b/gcc/libgdiagnostics++.h
@@ -34,6 +34,9 @@ class execution_path;
class group;
class manager;
class diagnostic;
+class graph;
+class node;
+class edge;
/* Wrapper around a borrowed diagnostic_text_sink *. */
@@ -246,6 +249,9 @@ public:
take_execution_path (execution_path path);
void
+ take_graph (graph g);
+
+ void
finish (const char *fmt, ...)
LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
LIBGDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (2, 3);
@@ -395,10 +401,99 @@ public:
void
set_analysis_target (file f);
+ void
+ take_global_graph (graph g);
+
diagnostic_manager *m_inner;
bool m_owned;
};
+class graph
+{
+public:
+ graph () : m_inner (nullptr), m_owned (false) {}
+
+ graph (diagnostic_graph *graph)
+ : m_inner (graph), m_owned (true)
+ {}
+
+ graph (const diagnostic_graph *graph)
+ : m_inner (const_cast<diagnostic_graph *> (graph)),
+ m_owned (false)
+ {}
+
+ graph (const graph &other) = delete;
+ graph &operator= (const graph &other) = delete;
+
+ graph (graph &&other)
+ : m_inner (other.m_inner),
+ m_owned (other.m_owned)
+ {
+ other.m_inner = nullptr;
+ other.m_owned = false;
+ }
+
+ graph &operator= (graph &&other)
+ {
+ m_inner = other.m_inner;
+ m_owned = other.m_owned;
+ other.m_inner = nullptr;
+ other.m_owned = false;
+ return *this;
+ }
+
+ ~graph ()
+ {
+ if (m_owned)
+ diagnostic_graph_release (m_inner);
+ }
+
+ void
+ set_description (const char *);
+
+ node
+ get_node_by_id (const char *id) const;
+
+ edge
+ get_edge_by_id (const char *id) const;
+
+ edge
+ add_edge (const char *id, node src_node, node dst_node, const char *label);
+
+ diagnostic_graph *m_inner;
+ bool m_owned;
+};
+
+// Borrowed pointer to a diagnostic_node.
+
+class node
+{
+public:
+ node () : m_inner (nullptr) {}
+ node (diagnostic_node *node_) : m_inner (node_) {}
+
+ void
+ set_label (const char *);
+
+ void
+ set_location (physical_location loc);
+
+ void
+ set_logical_location (logical_location loc);
+
+ diagnostic_node *m_inner;
+};
+
+// Borrowed edge to a diagnostic_edge.
+
+class edge
+{
+public:
+ edge (diagnostic_edge *edge_) : m_inner (edge_) {}
+
+ diagnostic_edge *m_inner;
+};
+
// Implementation
// class file
@@ -593,6 +688,14 @@ diagnostic::take_execution_path (execution_path path)
}
inline void
+diagnostic::take_graph (graph g)
+{
+ diagnostic_take_graph (m_inner,
+ g.m_inner);
+ g.m_owned = false;
+}
+
+inline void
diagnostic::finish (const char *fmt, ...)
{
va_list ap;
@@ -702,6 +805,66 @@ manager::set_analysis_target (file f)
diagnostic_manager_set_analysis_target (m_inner, f.m_inner);
}
+inline void
+manager::take_global_graph (graph g)
+{
+ diagnostic_manager_take_global_graph (m_inner,
+ g.m_inner);
+ g.m_owned = false;
+}
+
+// class graph
+
+inline void
+graph::set_description (const char *desc)
+{
+ diagnostic_graph_set_description (m_inner, desc);
+}
+
+inline node
+graph::get_node_by_id (const char *id) const
+{
+ return node (diagnostic_graph_get_node_by_id (m_inner, id));
+}
+
+inline edge
+graph::get_edge_by_id (const char *id) const
+{
+ return edge (diagnostic_graph_get_edge_by_id (m_inner, id));
+}
+
+inline edge
+graph::add_edge (const char *id,
+ node src_node, node dst_node,
+ const char *label)
+{
+ return edge (diagnostic_graph_add_edge (m_inner,
+ id,
+ src_node.m_inner,
+ dst_node.m_inner,
+ label));
+}
+
+// class node
+
+inline void
+node::set_label (const char *label)
+{
+ diagnostic_node_set_label (m_inner, label);
+}
+
+inline void
+node::set_location (physical_location loc)
+{
+ diagnostic_node_set_location (m_inner, loc.m_inner);
+}
+
+inline void
+node::set_logical_location (logical_location loc)
+{
+ diagnostic_node_set_logical_location (m_inner, loc.m_inner);
+}
+
} // namespace libgdiagnostics
#endif // #ifndef LIBGDIAGNOSTICSPP_H
diff --git a/gcc/libgdiagnostics-private.h b/gcc/libgdiagnostics-private.h
new file mode 100644
index 0000000..0f628e4
--- /dev/null
+++ b/gcc/libgdiagnostics-private.h
@@ -0,0 +1,62 @@
+/* Private API entrypoints to libgdiagnostics purely for use by sarif-replay.
+ Copyright (C) 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/>. */
+
+#ifndef LIBGDIAGNOSTICS_PRIVATE_H
+#define LIBGDIAGNOSTICS_PRIVATE_H
+
+#include "libgdiagnostics.h"
+
+namespace json { class object; }
+
+extern "C" {
+
+/* Private entrypoints, for use only by sarif-replay.
+ These are subject to removal without notice. */
+
+/* Entrypoints added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_event_id
+private_diagnostic_execution_path_add_event_2 (diagnostic_execution_path *path,
+ const diagnostic_physical_location *physical_loc,
+ const diagnostic_logical_location *logical_loc,
+ unsigned stack_depth,
+ diagnostic_graph *state_graph,
+ const char *fmt, ...)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (3)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (5)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (6)
+ LIBGDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (6, 7);
+
+extern void
+private_diagnostic_graph_set_property_bag (diagnostic_graph &graph,
+ std::unique_ptr<json::object> properties);
+
+extern void
+private_diagnostic_node_set_property_bag (diagnostic_node &node,
+ std::unique_ptr<json::object> properties);
+
+extern void
+private_diagnostic_edge_set_property_bag (diagnostic_edge &edge,
+ std::unique_ptr<json::object> properties);
+
+} // extern "C"
+
+#endif /* LIBGDIAGNOSTICS_PRIVATE_H */
diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc
index 74814c7..04812dc 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#define INCLUDE_MAP
+#define INCLUDE_STRING
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
@@ -32,9 +33,12 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-format-sarif.h"
#include "diagnostic-format-text.h"
#include "diagnostic-output-spec.h"
+#include "diagnostic-digraphs.h"
+#include "diagnostic-state-graphs.h"
#include "logical-location.h"
#include "edit-context.h"
#include "libgdiagnostics.h"
+#include "libgdiagnostics-private.h"
class owned_nullable_string
{
@@ -644,6 +648,9 @@ public:
return m_prev_diag_logical_loc;
}
+ void
+ take_global_graph (std::unique_ptr<diagnostic_graph> graph);
+
private:
void
ensure_linemap_for_file_and_line (const diagnostic_file *file,
@@ -743,17 +750,53 @@ private:
owned_nullable_string m_url;
};
+struct diagnostic_graph : public diagnostics::digraphs::digraph
+{
+ diagnostic_graph (diagnostic_manager &) {}
+
+ diagnostic_node *
+ add_node_with_id (std::string id,
+ diagnostic_node *parent_node);
+ diagnostic_edge *
+ add_edge_with_label (const char *id,
+ diagnostic_node &src_node,
+ diagnostic_node &dst_node,
+ const char *label);
+};
+
+struct diagnostic_node : public diagnostics::digraphs::node
+{
+ diagnostic_node (diagnostic_graph &g,
+ std::string id)
+ : node (g, std::move (id))
+ {
+ }
+};
+
+struct diagnostic_edge : public diagnostics::digraphs::edge
+{
+ diagnostic_edge (diagnostic_graph &g,
+ const char *id,
+ diagnostic_node &src_node,
+ diagnostic_node &dst_node)
+ : edge (g, id, src_node, dst_node)
+ {
+ }
+};
+
class libgdiagnostics_path_event : public diagnostic_event
{
public:
libgdiagnostics_path_event (const diagnostic_physical_location *physical_loc,
const diagnostic_logical_location *logical_loc,
unsigned stack_depth,
+ std::unique_ptr<diagnostic_graph> state_graph,
const char *gmsgid,
va_list *args)
: m_physical_loc (physical_loc),
m_logical_loc (logical_loc),
- m_stack_depth (stack_depth)
+ m_stack_depth (stack_depth),
+ m_state_graph (std::move (state_graph))
{
m_desc_uncolored = make_desc (gmsgid, args, false);
m_desc_colored = make_desc (gmsgid, args, true);
@@ -799,6 +842,15 @@ public:
return 0;
}
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ maybe_make_diagnostic_state_graph (bool) const final override
+ {
+ if (!m_state_graph)
+ return nullptr;
+
+ return m_state_graph->clone ();
+ }
+
private:
static label_text make_desc (const char *gmsgid,
va_list *args,
@@ -824,6 +876,7 @@ private:
const diagnostic_physical_location *m_physical_loc;
const diagnostic_logical_location *m_logical_loc;
unsigned m_stack_depth;
+ std::unique_ptr<diagnostic_graph> m_state_graph;
label_text m_desc_uncolored;
label_text m_desc_colored;
};
@@ -855,6 +908,7 @@ struct diagnostic_execution_path : public diagnostic_path
add_event_va (const diagnostic_physical_location *physical_loc,
const diagnostic_logical_location *logical_loc,
unsigned stack_depth,
+ std::unique_ptr<diagnostic_graph> state_graph,
const char *gmsgid,
va_list *args)
{
@@ -862,6 +916,7 @@ struct diagnostic_execution_path : public diagnostic_path
(std::make_unique<libgdiagnostics_path_event> (physical_loc,
logical_loc,
stack_depth,
+ std::move (state_graph),
gmsgid,
args));
return m_events.size () - 1;
@@ -902,6 +957,27 @@ private:
std::vector<std::unique_ptr<libgdiagnostics_path_event>> m_events;
};
+class prebuilt_digraphs : public diagnostics::digraphs::lazy_digraphs
+{
+public:
+ using digraph = diagnostics::digraphs::digraph;
+
+ std::unique_ptr<std::vector<std::unique_ptr<digraph>>>
+ create_digraphs () const final override
+ {
+ return std::make_unique<std::vector<std::unique_ptr<digraph>>> (std::move (m_digraphs));
+ }
+
+ void
+ take_graph (std::unique_ptr<diagnostic_graph> graph)
+ {
+ m_digraphs.push_back (std::move (graph));
+ }
+
+private:
+ mutable std::vector<std::unique_ptr<digraph>> m_digraphs;
+};
+
/* This has to be a "struct" as it is exposed in the C API. */
struct diagnostic
@@ -914,7 +990,9 @@ public:
m_rich_loc (diag_mgr.get_line_table ()),
m_logical_loc (nullptr),
m_path (nullptr)
- {}
+ {
+ m_metadata.set_lazy_digraphs (&m_graphs);
+ }
diagnostic_manager &get_manager () const
{
@@ -990,12 +1068,25 @@ public:
m_rich_loc.set_path (path);
}
+ void
+ take_graph (std::unique_ptr<diagnostic_graph> graph)
+ {
+ m_graphs.take_graph (std::move (graph));
+ }
+
+ const prebuilt_digraphs &
+ get_graphs () const
+ {
+ return m_graphs;
+ }
+
private:
diagnostic_manager &m_diag_mgr;
enum diagnostic_level m_level;
impl_rich_location m_rich_loc;
const diagnostic_logical_location *m_logical_loc;
diagnostic_metadata m_metadata;
+ prebuilt_digraphs m_graphs;
std::vector<std::unique_ptr<range_label>> m_labels;
std::vector<std::unique_ptr<impl_rule>> m_rules;
std::unique_ptr<diagnostic_execution_path> m_path;
@@ -1248,6 +1339,29 @@ diagnostic_manager::new_execution_path ()
return new diagnostic_execution_path (*mgr);
}
+void
+diagnostic_manager::take_global_graph (std::unique_ptr<diagnostic_graph> graph)
+{
+ class prebuilt_lazy_digraph : public diagnostics::digraphs::lazy_digraph
+ {
+ public:
+ prebuilt_lazy_digraph (std::unique_ptr<diagnostic_graph> graph)
+ : m_graph (std::move (graph))
+ {
+ }
+
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ create_digraph () const final override
+ {
+ return std::move (m_graph);
+ }
+
+ private:
+ mutable std::unique_ptr<diagnostic_graph> m_graph;
+ };
+
+ m_dc.report_global_digraph (prebuilt_lazy_digraph (std::move (graph)));
+}
/* Error-checking at the API boundary. */
#define FAIL_IF_NULL(PTR_ARG) \
@@ -1876,6 +1990,7 @@ diagnostic_execution_path_add_event (diagnostic_execution_path *path,
diagnostic_event_id_t result = path->add_event_va (physical_loc,
logical_loc,
stack_depth,
+ nullptr,
gmsgid, &args);
va_end (args);
@@ -1898,6 +2013,7 @@ diagnostic_execution_path_add_event_va (diagnostic_execution_path *path,
diagnostic_event_id_t result = path->add_event_va (physical_loc,
logical_loc,
stack_depth,
+ nullptr,
gmsgid, args);
return as_diagnostic_event_id (result);
}
@@ -2048,3 +2164,223 @@ diagnostic_manager_set_analysis_target (diagnostic_manager *mgr,
mgr->get_dc ().set_main_input_filename (file->get_name ());
}
+
+// struct diagnostic_graph : public diagnostics::digraphs::graph<foo_traits>
+
+diagnostic_node *
+diagnostic_graph::add_node_with_id (std::string id,
+ diagnostic_node *parent_node)
+{
+ auto node_up = std::make_unique<diagnostic_node> (*this, std::move (id));
+ diagnostic_node *new_node = node_up.get ();
+ if (parent_node)
+ parent_node->add_child (std::move (node_up));
+ else
+ add_node (std::move (node_up));
+ return new_node;
+}
+
+diagnostic_edge *
+diagnostic_graph::add_edge_with_label (const char *id,
+ diagnostic_node &src_node,
+ diagnostic_node &dst_node,
+ const char *label)
+{
+ auto edge_up
+ = std::make_unique<diagnostic_edge> (*this, id,
+ src_node, dst_node);
+ diagnostic_edge *new_edge = edge_up.get ();
+ if (label)
+ new_edge->set_label (label);
+ add_edge (std::move (edge_up));
+ return new_edge;
+}
+
+/* Public entrypoint. */
+
+diagnostic_graph *
+diagnostic_manager_new_graph (diagnostic_manager *manager)
+{
+ FAIL_IF_NULL (manager);
+
+ return new diagnostic_graph (*manager);
+}
+
+/* Public entrypoint. */
+
+void
+diagnostic_manager_take_global_graph (diagnostic_manager *manager,
+ diagnostic_graph *graph)
+{
+ FAIL_IF_NULL (manager);
+ FAIL_IF_NULL (graph);
+
+ manager->take_global_graph (std::unique_ptr<diagnostic_graph> (graph));
+}
+
+void
+diagnostic_take_graph (diagnostic *diag,
+ diagnostic_graph *graph)
+{
+ FAIL_IF_NULL (diag);
+ FAIL_IF_NULL (graph);
+
+ diag->take_graph (std::unique_ptr<diagnostic_graph> (graph));
+}
+
+/* Public entrypoint. */
+
+void
+diagnostic_graph_release (diagnostic_graph *graph)
+{
+ delete graph;
+}
+
+/* Public entrypoint. */
+
+void
+diagnostic_graph_set_description (diagnostic_graph *graph,
+ const char *desc)
+{
+ FAIL_IF_NULL (graph);
+
+ graph->set_description (desc);
+}
+
+diagnostic_node *
+diagnostic_graph_add_node (diagnostic_graph *graph,
+ const char *id,
+ diagnostic_node *parent_node)
+{
+ FAIL_IF_NULL (graph);
+ FAIL_IF_NULL (id);
+
+ return graph->add_node_with_id (id, parent_node);
+}
+
+/* Public entrypoint. */
+
+diagnostic_edge *
+diagnostic_graph_add_edge (diagnostic_graph *graph,
+ const char *id,
+ diagnostic_node *src_node,
+ diagnostic_node *dst_node,
+ const char *label)
+{
+ FAIL_IF_NULL (graph);
+ FAIL_IF_NULL (src_node);
+ FAIL_IF_NULL (dst_node);
+
+ return graph->add_edge_with_label (id, *src_node, *dst_node, label);
+}
+
+/* Public entrypoint. */
+
+diagnostic_node *
+diagnostic_graph_get_node_by_id (diagnostic_graph *graph,
+ const char *id)
+{
+ FAIL_IF_NULL (graph);
+ FAIL_IF_NULL (id);
+
+ return static_cast<diagnostic_node *> (graph->get_node_by_id (id));
+}
+
+/* Public entrypoint. */
+
+diagnostic_edge *
+diagnostic_graph_get_edge_by_id (diagnostic_graph *graph,
+ const char *id)
+{
+ FAIL_IF_NULL (graph);
+ FAIL_IF_NULL (id);
+
+ return static_cast<diagnostic_edge *> (graph->get_edge_by_id (id));
+}
+
+/* Public entrypoint. */
+
+void
+diagnostic_node_set_location (diagnostic_node *node,
+ const diagnostic_physical_location *loc)
+{
+ FAIL_IF_NULL (node);
+
+ node->set_physical_loc (loc ? loc->m_inner : UNKNOWN_LOCATION);
+}
+
+/* Public entrypoint. */
+
+void
+diagnostic_node_set_label (diagnostic_node *node,
+ const char *label)
+{
+ FAIL_IF_NULL (node);
+
+ node->set_label (label);
+}
+
+void
+diagnostic_node_set_logical_location (diagnostic_node *node,
+ const diagnostic_logical_location *logical_loc)
+{
+ FAIL_IF_NULL (node);
+
+ node->set_logical_loc
+ (impl_logical_location_manager::key_from_ptr (logical_loc));
+}
+
+/* Private entrypoint. */
+
+diagnostic_event_id
+private_diagnostic_execution_path_add_event_2 (diagnostic_execution_path *path,
+ const diagnostic_physical_location *physical_loc,
+ const diagnostic_logical_location *logical_loc,
+ unsigned stack_depth,
+ diagnostic_graph *state_graph,
+ const char *gmsgid, ...)
+
+{
+ FAIL_IF_NULL (path);
+ FAIL_IF_NULL (gmsgid);
+
+ va_list args;
+ va_start (args, gmsgid);
+ diagnostic_event_id_t result
+ = path->add_event_va (physical_loc,
+ logical_loc,
+ stack_depth,
+ std::unique_ptr <diagnostic_graph> (state_graph),
+ gmsgid, &args);
+ va_end (args);
+
+ return as_diagnostic_event_id (result);
+
+}
+
+/* Private entrypoint. */
+
+void
+private_diagnostic_graph_set_property_bag (diagnostic_graph &graph,
+ std::unique_ptr<json::object> properties)
+{
+ graph.set_property_bag (std::move (properties));
+}
+
+/* Private entrypoint. */
+
+void
+private_diagnostic_node_set_property_bag (diagnostic_node &node,
+ std::unique_ptr<json::object> properties)
+{
+ node.set_property_bag (std::move (properties));
+}
+
+/* Private entrypoint. */
+
+void
+private_diagnostic_edge_set_property_bag (diagnostic_edge &edge,
+ std::unique_ptr<json::object> properties)
+{
+ edge.set_property_bag (std::move (properties));
+}
diff --git a/gcc/libgdiagnostics.h b/gcc/libgdiagnostics.h
index 9af2747..f79790a 100644
--- a/gcc/libgdiagnostics.h
+++ b/gcc/libgdiagnostics.h
@@ -765,6 +765,140 @@ diagnostic_manager_set_analysis_target (diagnostic_manager *mgr,
LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+/* Directed graphs. */
+
+typedef struct diagnostic_graph diagnostic_graph;
+typedef struct diagnostic_node diagnostic_node;
+typedef struct diagnostic_edge diagnostic_edge;
+
+/* Create a new graph.
+ This is owned by the caller and must have one of
+ diagnostic_manager_take_global_graph, diagnostic_take_graph,
+ or diagnostic_graph_release called on it.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_graph *
+diagnostic_manager_new_graph (diagnostic_manager *manager)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Report this graph "globally", taking ownership of it.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_manager_take_global_graph (diagnostic_manager *manager,
+ diagnostic_graph *graph)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Add this graph to DIAG, transferring ownership to it.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_take_graph (diagnostic *diag,
+ diagnostic_graph *graph)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Release this graph. Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_graph_release (diagnostic_graph *graph)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (1);
+
+/* Set the description of GRAPH for use
+ in the value of the SARIF "description" property
+ (SARIF v2.1.0 section 3.39.2).
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_graph_set_description (diagnostic_graph *graph,
+ const char *description)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Create and add a new node within GRAPH.
+ NODE_ID must be unique within nodes in GRAPH.
+ The new node is owned by GRAPH.
+ PARENT_NODE can be NULL (for a top-level node in the graph),
+ or non-null for a child node.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_node *
+diagnostic_graph_add_node (diagnostic_graph *graph,
+ const char *node_id,
+ diagnostic_node *parent_node)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (3);
+
+/* Create and add a new edge within GRAPH.
+
+ If non-null, then EDGE_ID must be unique within edges in GRAPH;
+ if EDGE_ID is null then a unique id of the form "edge0", "edge1", etc
+ will be used automatically.
+
+ The new edge is owned by GRAPH.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_edge *
+diagnostic_graph_add_edge (diagnostic_graph *graph,
+ const char *edge_id,
+ diagnostic_node *src_node,
+ diagnostic_node *dst_node,
+ const char *label)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (4)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (5);
+
+/* Get the node in GRAPH with the given id, or null.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_node *
+diagnostic_graph_get_node_by_id (diagnostic_graph *graph,
+ const char *node_id)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Get the edge in GRAPH with the given id, or null.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern diagnostic_edge *
+diagnostic_graph_get_edge_by_id (diagnostic_graph *graph,
+ const char *edge_id)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Set the label of NODE for use
+ in the value of the SARIF "label" property
+ (SARIF v2.1.0 section 3.40.3).
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_node_set_label (diagnostic_node *node,
+ const char *label)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Set the physical location of NODE.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_node_set_location (diagnostic_node *node,
+ const diagnostic_physical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Set the logical location of NODE.
+ Added in LIBGDIAGNOSTICS_ABI_3. */
+
+extern void
+diagnostic_node_set_logical_location (diagnostic_node *node,
+ const diagnostic_logical_location *logical_loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
/* DEFERRED:
- thread-safety
- plural forms
diff --git a/gcc/libgdiagnostics.map b/gcc/libgdiagnostics.map
index 49cabca..cae28d1 100644
--- a/gcc/libgdiagnostics.map
+++ b/gcc/libgdiagnostics.map
@@ -90,3 +90,26 @@ LIBGDIAGNOSTICS_ABI_2 {
diagnostic_manager_add_sink_from_spec;
diagnostic_manager_set_analysis_target;
} LIBGDIAGNOSTICS_ABI_1;
+
+# Add hooks needed for diagnostic_graph support.
+LIBGDIAGNOSTICS_ABI_3 {
+ global:
+ diagnostic_manager_new_graph;
+ diagnostic_manager_take_global_graph;
+ diagnostic_take_graph;
+ diagnostic_graph_release;
+ diagnostic_graph_set_description;
+ diagnostic_graph_add_node;
+ diagnostic_graph_add_edge;
+ diagnostic_graph_get_node_by_id;
+ diagnostic_graph_get_edge_by_id;
+ diagnostic_node_set_label;
+ diagnostic_node_set_location;
+ diagnostic_node_set_logical_location;
+
+ # Private hooks used by sarif-replay
+ private_diagnostic_execution_path_add_event_2;
+ private_diagnostic_graph_set_property_bag;
+ private_diagnostic_node_set_property_bag;
+ private_diagnostic_edge_set_property_bag;
+} LIBGDIAGNOSTICS_ABI_2;
diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index 2d6c394..cad535b 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "libgdiagnostics++.h"
+#include "libgdiagnostics-private.h"
#include "json-parsing.h"
#include "intl.h"
#include "sarif-spec-urls.def"
@@ -291,6 +292,8 @@ public:
label_text m_label;
};
+using id_map = std::map<std::string, const json::string *>;
+
class sarif_replayer
{
public:
@@ -413,6 +416,30 @@ private:
const json::object &run_obj,
libgdiagnostics::execution_path &out);
+ // "graph" object (§3.39)
+ enum status
+ handle_graph_object (const json::object &graph_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &out);
+ // "node" object (§3.40)
+ libgdiagnostics::node
+ handle_node_object (const json::object &node_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &graph,
+ libgdiagnostics::node parent_node,
+ id_map &node_id_map);
+
+ // "edge" object (§3.41)
+ libgdiagnostics::edge
+ handle_edge_object (const json::object &edge_obj,
+ libgdiagnostics::graph &graph,
+ id_map &edge_id_map);
+
+ libgdiagnostics::node
+ get_graph_node_by_id_property (const json::object &edge_json_object,
+ const property_spec_ref &id_prop,
+ libgdiagnostics::graph &graph);
+
// reportingDescriptor lookup (§3.52.3)
const json::object *
lookup_rule_by_id_in_tool (const char *rule_id,
@@ -446,7 +473,7 @@ private:
{
va_list ap;
va_start (ap, gmsgid);
- report_problem (jv, ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_ERROR);
+ report_problem (jv, &ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_ERROR);
va_end (ap);
return status::err_invalid_sarif;
}
@@ -462,14 +489,25 @@ private:
{
va_list ap;
va_start (ap, gmsgid);
- report_problem (jv, ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_SORRY);
+ report_problem (jv, &ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_SORRY);
va_end (ap);
return status::err_unhandled_sarif;
}
void
+ report_note (const json::value &jv,
+ const char *gmsgid, ...)
+ LIBGDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (3, 4)
+ {
+ va_list ap;
+ va_start (ap, gmsgid);
+ report_problem (jv, nullptr, gmsgid, &ap, DIAGNOSTIC_LEVEL_NOTE);
+ va_end (ap);
+ }
+
+ void
report_problem (const json::value &jv,
- const spec_ref &ref,
+ const spec_ref *ref,
const char *gmsgid,
va_list *args,
enum diagnostic_level level)
@@ -481,11 +519,14 @@ private:
There doesn't seem to be a systematic mapping from spec sections to
HTML anchors, so we can't provide URLs
(filed as https://github.com/oasis-tcs/sarif-spec/issues/533 ). */
- char *ref_desc = ref.make_description ();
- char *ref_url = ref.make_url ();
- diag.add_rule (ref_desc, ref_url);
- free (ref_desc);
- free (ref_url);
+ if (ref)
+ {
+ char *ref_desc = ref->make_description ();
+ char *ref_url = ref->make_url ();
+ diag.add_rule (ref_desc, ref_url);
+ free (ref_desc);
+ free (ref_url);
+ }
auto loc_range
= make_physical_location (m_control_mgr,
@@ -651,6 +692,38 @@ private:
const string_property_value<ValueType> *value_arr,
size_t num_values);
+ const json::object *
+ maybe_get_property_bag (const json::object &obj)
+ {
+ const property_spec_ref properties
+ ("object", "properties", "3.8.1");
+ return get_optional_property<json::object> (obj, properties);
+ }
+
+ /* Look for a property bag within OBJ.
+ If found, look for a property within it named PROPERTY_NAME
+ of the given type.
+ If successful, return the property's value.
+ Otherwise, return nullptr without complaining (unless the property bag
+ is itself not an object). */
+ template <typename JsonType>
+ const JsonType *
+ maybe_get_property_bag_value (const json::object &obj,
+ const char *property_name)
+ {
+ auto property_bag_obj = maybe_get_property_bag (obj);
+ if (!property_bag_obj)
+ return nullptr;
+ const json::value *property_val = property_bag_obj->get (property_name);
+ if (!property_val)
+ return nullptr;
+ const JsonType *sub = dyn_cast<const JsonType *> (property_val);
+ if (!sub)
+ /* Property is wrong kind of value. Don't treat this as an error. */
+ return nullptr;
+ return sub;
+ }
+
/* The manager to replay the SARIF files to. */
libgdiagnostics::manager m_output_mgr;
@@ -929,6 +1002,31 @@ sarif_replayer::handle_run_obj (const json::object &run_obj)
break;
}
+ // §3.14.20 "graphs"
+ const property_spec_ref prop_graphs ("run", "graphs", "3.14.20");
+ if (const json::array *graphs
+ = get_optional_property<json::array> (run_obj,
+ prop_graphs))
+ {
+ for (auto element : *graphs)
+ {
+ if (const json::object *graph_json_obj
+ = require_object_for_element (*element, prop_graphs))
+ {
+ libgdiagnostics::graph graph;
+ enum status s = handle_graph_object (*graph_json_obj,
+ run_obj,
+ graph);
+ if (s != status::ok)
+ return s;
+
+ m_output_mgr.take_global_graph (std::move (graph));
+ }
+ else
+ return status::err_invalid_sarif;
+ }
+ }
+
return status::ok;
}
@@ -1244,6 +1342,31 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
if (path.m_inner)
err.take_execution_path (std::move (path));
+ // §3.27.19 "graphs" property
+ const property_spec_ref prop_graphs ("result", "graphs", "3.27.19");
+ if (const json::array *graphs
+ = get_optional_property<json::array> (result_obj,
+ prop_graphs))
+ {
+ for (auto element : *graphs)
+ {
+ if (const json::object *graph_json_obj
+ = require_object_for_element (*element, prop_graphs))
+ {
+ libgdiagnostics::graph graph;
+ enum status s = handle_graph_object (*graph_json_obj,
+ run_obj,
+ graph);
+ if (s != status::ok)
+ return s;
+
+ err.take_graph (std::move (graph));
+ }
+ else
+ return status::err_invalid_sarif;
+ }
+ }
+
// §3.27.22 relatedLocations property
std::vector<std::pair<libgdiagnostics::diagnostic, label_text>> notes;
const property_spec_ref prop_related_locations
@@ -1740,16 +1863,32 @@ handle_thread_flow_location_object (const json::object &tflow_loc_obj,
}
}
+ libgdiagnostics::graph state_graph;
+ if (auto sarif_state_graph
+ = maybe_get_property_bag_value<json::object> (tflow_loc_obj,
+ "gcc/diagnostic_event/state_graph"))
+ {
+ enum status s
+ = handle_graph_object (*sarif_state_graph, run_obj, state_graph);
+ if (s != status::ok)
+ return s;
+ }
+
if (message.get ())
- path.add_event (physical_loc,
- logical_loc,
- stack_depth,
- "%s", message.get ());
+ private_diagnostic_execution_path_add_event_2 (path.m_inner,
+ physical_loc.m_inner,
+ logical_loc.m_inner,
+ stack_depth,
+ state_graph.m_inner,
+ "%s", message.get ());
else
- path.add_event (physical_loc,
- logical_loc,
- stack_depth,
- "");
+ private_diagnostic_execution_path_add_event_2 (path.m_inner,
+ physical_loc.m_inner,
+ logical_loc.m_inner,
+ stack_depth,
+ state_graph.m_inner,
+ "");
+ state_graph.m_owned = false;
return status::ok;
}
@@ -2142,6 +2281,270 @@ handle_logical_location_object (const json::object &logical_loc_obj,
return status::ok;
}
+// "graph" object (§3.39)
+
+enum status
+sarif_replayer::handle_graph_object (const json::object &graph_json_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &out_graph)
+{
+ out_graph = libgdiagnostics::graph
+ (diagnostic_manager_new_graph (m_output_mgr.m_inner));
+
+ id_map node_id_map;
+ id_map edge_id_map;
+
+ if (auto properties = maybe_get_property_bag (graph_json_obj))
+ private_diagnostic_graph_set_property_bag (*out_graph.m_inner,
+ properties->clone_as_object ());
+
+ // §3.39.2: MAY contain a "description" property
+ const property_spec_ref description_prop
+ ("graph", "description", "3.39.2");
+ if (auto description_obj
+ = get_optional_property<json::object> (graph_json_obj, description_prop))
+ {
+ label_text text
+ = make_plain_text_within_result_message (&run_obj,
+ *description_obj,
+ nullptr);
+ if (!text.get ())
+ return status::err_invalid_sarif;
+ out_graph.set_description (text.get ());
+ }
+
+ // §3.39.3: MAY contain a "nodes" property
+ const property_spec_ref nodes_prop
+ ("graph", "nodes", "3.39.3");
+ if (auto nodes_arr
+ = get_optional_property<json::array> (graph_json_obj, nodes_prop))
+ {
+ for (auto element : *nodes_arr)
+ {
+ const json::object *node_json_obj
+ = require_object_for_element (*element, nodes_prop);
+ if (!node_json_obj)
+ return status::err_invalid_sarif;
+ libgdiagnostics::node node
+ = handle_node_object (*node_json_obj, run_obj, out_graph,
+ nullptr, node_id_map);
+ if (node.m_inner == nullptr)
+ return status::err_invalid_sarif;
+ }
+ }
+ else
+ // If we have no nodes, we can't handle the edges.
+ return status::ok;
+
+ // §3.39.4 edges property
+ const property_spec_ref edges_prop
+ ("graph", "edges", "3.39.4");
+ if (auto edges_arr
+ = get_optional_property<json::array> (graph_json_obj, edges_prop))
+ {
+ for (auto element : *edges_arr)
+ {
+ const json::object *edge_json_obj
+ = require_object_for_element (*element, edges_prop);
+ if (!edge_json_obj)
+ return status::err_invalid_sarif;
+ libgdiagnostics::edge edge
+ = handle_edge_object (*edge_json_obj, out_graph, edge_id_map);
+ if (edge.m_inner == nullptr)
+ return status::err_invalid_sarif;
+ }
+ }
+
+ return status::ok;
+}
+
+// "node" object (§3.40)
+
+libgdiagnostics::node
+sarif_replayer::handle_node_object (const json::object &node_json_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &graph,
+ libgdiagnostics::node parent_node,
+ id_map &node_id_map)
+{
+ // §3.40.2 "id" property
+ const property_spec_ref id_prop ("node", "id", "3.40.2");
+ auto id_str = get_required_property<json::string> (node_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ if (diagnostic_graph_get_node_by_id (graph.m_inner, id))
+ {
+ // Duplicate id; fail:
+ libgdiagnostics::group g (m_control_mgr);
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "duplicate node id %qs within graph",
+ id);
+ gcc_assert (node_id_map[id]);
+ report_note (*node_id_map[id],
+ "%qs already used as node id within graph here",
+ id);
+ return nullptr;
+ }
+ node_id_map[id] = id_str;
+
+ libgdiagnostics::node new_node
+ = libgdiagnostics::node (diagnostic_graph_add_node (graph.m_inner,
+ id,
+ parent_node.m_inner));
+ if (auto properties = maybe_get_property_bag (node_json_obj))
+ private_diagnostic_node_set_property_bag (*new_node.m_inner,
+ properties->clone_as_object ());
+
+ // §3.40.3 "label" property
+ const property_spec_ref label_prop
+ ("node", "label", "3.40.3");
+ if (auto label_obj
+ = get_optional_property<json::object> (node_json_obj, label_prop))
+ {
+ label_text text
+ = make_plain_text_within_result_message (&run_obj,
+ *label_obj,
+ nullptr);
+ if (!text.get ())
+ return nullptr;
+ new_node.set_label (text.get ());
+ }
+
+ // §3.40.4 "location" property
+ const property_spec_ref location_prop ("node", "location", "3.40.4");
+ if (auto location_json_obj
+ = get_optional_property<json::object> (node_json_obj, location_prop))
+ {
+ libgdiagnostics::physical_location physical_loc;
+ libgdiagnostics::logical_location logical_loc;
+ enum status s = handle_location_object (*location_json_obj,
+ run_obj,
+ physical_loc,
+ logical_loc,
+ nullptr); // annotations
+ if (s != status::ok)
+ return nullptr;
+
+ new_node.set_location (physical_loc);
+ new_node.set_logical_location (logical_loc);
+ }
+
+ // §3.40.5: MAY contain a "children" property
+ const property_spec_ref children_prop
+ ("graph", "children", "3.40.5");
+ if (auto children_json_arr
+ = get_optional_property<json::array> (node_json_obj, children_prop))
+ {
+ for (auto json_element : *children_json_arr)
+ {
+ const json::object *child_json_obj
+ = require_object_for_element (*json_element, children_prop);
+ if (!child_json_obj)
+ return nullptr;
+ libgdiagnostics::node child_node
+ = handle_node_object (*child_json_obj, run_obj, graph,
+ new_node, node_id_map);
+ if (child_node.m_inner == nullptr)
+ return nullptr;
+ }
+ }
+
+ return new_node;
+}
+
+// "edge" object (§3.41)
+
+libgdiagnostics::edge
+sarif_replayer::handle_edge_object (const json::object &edge_json_obj,
+ libgdiagnostics::graph &graph,
+ id_map &edge_id_map)
+{
+ // §3.41.2 "id" property
+ const property_spec_ref id_prop ("edge", "id", "3.41.2");
+ auto id_str = get_required_property<json::string> (edge_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ if (diagnostic_graph_get_edge_by_id (graph.m_inner, id))
+ {
+ // Duplicate id; fail:
+ libgdiagnostics::group g (m_control_mgr);
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "duplicate edge id %qs within graph",
+ id);
+ gcc_assert (edge_id_map[id]);
+ report_note (*edge_id_map[id],
+ "%qs already used as edge id within graph here",
+ id);
+ return nullptr;
+ }
+ edge_id_map[id] = id_str;
+
+ // §3.41.3 "label" property
+ label_text label;
+ const property_spec_ref label_prop
+ ("edge", "label", "3.41.3");
+ if (auto label_obj
+ = get_optional_property<json::object> (edge_json_obj, label_prop))
+ {
+ label = make_plain_text_within_result_message (nullptr,
+ *label_obj,
+ nullptr);
+ if (!label.get ())
+ return nullptr;
+ }
+
+ // §3.41.4 "sourceNodeId" property
+ const property_spec_ref src_id_prop ("edge", "sourceNodeId", "3.41.4");
+ auto src_node = get_graph_node_by_id_property (edge_json_obj,
+ src_id_prop,
+ graph);
+ if (!src_node.m_inner)
+ return nullptr;
+
+ // §3.41.5 "targetNodeId" property
+ const property_spec_ref dst_id_prop ("edge", "targetNodeId", "3.41.5");
+ auto dst_node = get_graph_node_by_id_property (edge_json_obj,
+ dst_id_prop,
+ graph);
+ if (!dst_node.m_inner)
+ return nullptr;
+
+ auto result = graph.add_edge (id, src_node, dst_node, label.get ());
+
+ if (auto properties = maybe_get_property_bag (edge_json_obj))
+ private_diagnostic_edge_set_property_bag (*result.m_inner,
+ properties->clone_as_object ());
+
+ return result;
+}
+
+libgdiagnostics::node
+sarif_replayer::
+get_graph_node_by_id_property (const json::object &edge_json_obj,
+ const property_spec_ref &id_prop,
+ libgdiagnostics::graph &graph)
+{
+ auto id_str = get_required_property<json::string> (edge_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ auto node = graph.get_node_by_id (id);
+ if (!node.m_inner)
+ {
+ // id not found; complain:
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "no node with id %qs in graph",
+ id);
+ return nullptr;
+ }
+ return node;
+}
+
// 3.52.3 reportingDescriptor lookup
// "For an example of the interaction between ruleId and rule.id, see §3.52.4."
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 274b52cd..c941d2f 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2416,14 +2416,15 @@ process_alt_operands (int only_alternative)
if (curr_static_id->operand[nop].type == OP_INOUT
|| curr_static_id->operand[m].type == OP_INOUT)
break;
- /* Operands don't match. If the operands are
- different user defined explicit hard
+ /* Operands don't match. For asm if the operands
+ are different user defined explicit hard
registers, then we cannot make them match
when one is early clobber operand. */
if ((REG_P (*curr_id->operand_loc[nop])
|| SUBREG_P (*curr_id->operand_loc[nop]))
&& (REG_P (*curr_id->operand_loc[m])
- || SUBREG_P (*curr_id->operand_loc[m])))
+ || SUBREG_P (*curr_id->operand_loc[m]))
+ && INSN_CODE (curr_insn) < 0)
{
rtx nop_reg = *curr_id->operand_loc[nop];
if (SUBREG_P (nop_reg))
@@ -3328,19 +3329,15 @@ process_alt_operands (int only_alternative)
first_conflict_j = j;
last_conflict_j = j;
/* Both the earlyclobber operand and conflicting operand
- cannot both be user defined hard registers. */
+ cannot both be user defined hard registers for asm.
+ Let curr_insn_transform diagnose it. */
if (HARD_REGISTER_P (operand_reg[i])
&& REG_USERVAR_P (operand_reg[i])
&& operand_reg[j] != NULL_RTX
&& HARD_REGISTER_P (operand_reg[j])
- && REG_USERVAR_P (operand_reg[j]))
- {
- /* For asm, let curr_insn_transform diagnose it. */
- if (INSN_CODE (curr_insn) < 0)
+ && REG_USERVAR_P (operand_reg[j])
+ && INSN_CODE (curr_insn) < 0)
return false;
- fatal_insn ("unable to generate reloads for "
- "impossible constraints:", curr_insn);
- }
}
if (last_conflict_j < 0)
continue;
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index 3245453..d43d9dd 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -102,7 +102,9 @@ selftest::run_tests ()
diagnostic_show_locus_cc_tests ();
diagnostic_format_html_cc_tests ();
diagnostic_format_sarif_cc_tests ();
+ diagnostic_digraphs_cc_tests ();
diagnostic_output_spec_cc_tests ();
+ diagnostic_state_graphs_cc_tests ();
edit_context_cc_tests ();
fold_const_cc_tests ();
spellcheck_cc_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index eb9e604..06485e1 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -222,11 +222,13 @@ extern void cgraph_cc_tests ();
extern void convert_cc_tests ();
extern void dbgcnt_cc_tests ();
extern void diagnostic_color_cc_tests ();
+extern void diagnostic_digraphs_cc_tests ();
extern void diagnostic_format_html_cc_tests ();
extern void diagnostic_format_sarif_cc_tests ();
extern void diagnostic_output_spec_cc_tests ();
extern void diagnostic_path_output_cc_tests ();
extern void diagnostic_show_locus_cc_tests ();
+extern void diagnostic_state_graphs_cc_tests ();
extern void digraph_cc_tests ();
extern void dumpfile_cc_tests ();
extern void edit_context_cc_tests ();
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4aceccb..4f1b932 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,114 @@
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/analyzer/state-diagram-1-sarif.py (test_xml_state):
+ Rename to...
+ (test_state_graph): ...this. Port from XML to SARIF graphs.
+ * gcc.dg/analyzer/state-diagram-1.c: Update sink option
+ from "sarif:xml-state=yes" to "sarif:state-graphs=yes".
+ * gcc.dg/analyzer/state-diagram-5-sarif.c: Likewise.
+ * gcc.dg/analyzer/state-diagram-5-sarif.py: Drop import of ET.
+ (test_nested_types_in_xml_state): Rename to...
+ (test_nested_types_in_state_graph): ...this. Port from XML to
+ SARIF graphs.
+ * gcc.dg/plugin/diagnostic-test-graphs-html.c: New test.
+ * gcc.dg/plugin/diagnostic-test-graphs-html.py: New test script.
+ * gcc.dg/plugin/diagnostic-test-graphs-sarif.c: New test.
+ * gcc.dg/plugin/diagnostic-test-graphs-sarif.py: New test script.
+ * gcc.dg/plugin/diagnostic-test-graphs.c: New test.
+ * gcc.dg/plugin/diagnostic_plugin_test_graphs.cc: New test plugin.
+ * gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above.
+ * lib/sarif.py (get_xml_state): Delete.
+ (get_state_graph): New.
+ (def get_state_node_attr): New.
+ (get_state_node_kind): New.
+ (get_state_node_name): New.
+ (get_state_node_type): New.
+ (get_state_node_value): New.
+ * sarif-replay.dg/2.1.0-invalid/3.40.2-duplicate-node-id.sarif:
+ New test.
+ * sarif-replay.dg/2.1.0-invalid/3.41.4-unrecognized-node-id.sarif:
+ New test.
+ * sarif-replay.dg/2.1.0-valid/graphs-check-html.py: New test
+ script.
+ * sarif-replay.dg/2.1.0-valid/graphs-check-sarif-roundtrip.py: New
+ test script.
+ * sarif-replay.dg/2.1.0-valid/graphs.sarif: New test.
+
+2025-07-11 Vladimir N. Makarov <vmakarov@redhat.com>
+
+ * gcc.target/powerpc/pr121007.c: New.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119064
+ * g++.dg/cpp26/feat-cxx26.C: Add test for
+ __cpp_trivial_relocatability.
+ * g++.dg/cpp26/trivially-relocatable1.C: New test.
+ * g++.dg/cpp26/trivially-relocatable2.C: New test.
+ * g++.dg/cpp26/trivially-relocatable3.C: New test.
+ * g++.dg/cpp26/trivially-relocatable4.C: New test.
+ * g++.dg/cpp26/trivially-relocatable5.C: New test.
+ * g++.dg/cpp26/trivially-relocatable6.C: New test.
+ * g++.dg/cpp26/trivially-relocatable7.C: New test.
+ * g++.dg/cpp26/trivially-relocatable8.C: New test.
+ * g++.dg/cpp26/trivially-relocatable9.C: New test.
+ * g++.dg/cpp26/trivially-relocatable10.C: New test.
+ * g++.dg/cpp26/trivially-relocatable11.C: New test.
+
+2025-07-11 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR target/121027
+ * gcc.target/aarch64/sve/acle/general/perm_1.c: New test.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * gcc.target/aarch64/simd/eor3_d.c: Add tests for DImode operands.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * gcc.target/aarch64/simd/bcax_d.c: Add tests for DImode arguments.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * gcc.target/aarch64/simd/eor3_d.c: New test.
+
+2025-07-11 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * gcc.target/aarch64/simd/bcax_d.c: New test.
+
+2025-07-11 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121034
+ * gcc.dg/vect/pr121034.c: New testcase.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120954
+ * c-c++-common/Warray-bounds-11.c: New test.
+
+2025-07-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * g++.dg/lto/pr114790_0.C: New test.
+ * g++.dg/lto/pr114790_1.C: New test.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+ Martin Jambor <mjambor@suse.cz>
+
+ PR ipa/121023
+ * c-c++-common/musttail32.c: New test.
+
+2025-07-11 Hu, Lin1 <lin1.hu@intel.com>
+
+ PR target/91384
+ * gcc.target/i386/pr91384-1.c: New test.
+
+2025-07-11 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/106135
+ * gfortran.dg/import3.f90: Use -std=f2008 and comment on change
+ in error message texts with f2018.
+ * gfortran.dg/import12.f90: New test.
+
2025-07-10 Jakub Jelinek <jakub@redhat.com>
PR c++/120628
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py
index d2967d4..d92af83 100644
--- a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1-sarif.py
@@ -6,7 +6,7 @@ import pytest
def sarif():
return sarif_from_env()
-def test_xml_state(sarif):
+def test_state_graph(sarif):
result = get_result_by_index(sarif, 0)
assert result['level'] == 'warning'
@@ -17,16 +17,49 @@ def test_xml_state(sarif):
# Event "(1)": "entry to 'test'" (index == 0)
assert events[0]['location']['message']['text'] == "entry to 'test'"
- state0 = get_xml_state(events, 0)
- memory_regions = state0.find('memory-regions')
- assert memory_regions is not None
- stack = memory_regions.find('stack')
- assert stack is not None
- frame = stack.find('stack-frame')
- assert frame.get('function') == 'test'
+ state0 = get_state_graph(events, 0)
+
+ stack = state0['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
+
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
# Final event:
assert events[-1]['location']['message']['text'].startswith("use after 'free' of ")
- state = get_xml_state(events, -1)
- # TODO
+ state = get_state_graph(events, -1)
+
+ stack = state['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
+
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
+
+ heap = state['nodes'][1]
+ assert heap['id'] == 'heap'
+ assert get_state_node_kind(heap) == 'heap'
+
+ assert len(heap['children']) == 3
+ heap_buffer0 = heap['children'][0]
+ assert heap_buffer0['id'].startswith('heap-allocated-region-')
+ assert get_state_node_kind(heap_buffer0) == 'dynalloc-buffer'
+
+ globals_ = state['nodes'][2]
+ assert globals_['id'] == 'globals'
+ assert get_state_node_kind(globals_) == 'globals'
+ first = globals_['children'][0]
+ assert first['id'].startswith('decl-region-')
+ assert get_state_node_kind(first) == 'variable'
+ assert get_state_node_name(first) == 'first'
+ assert get_state_node_type(first) == 'struct node *'
+
+ assert len(state['edges']) == 3
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c
index 3d853d2..3b35cfa 100644
--- a/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-1.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fdiagnostics-add-output=sarif:xml-state=yes" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif:state-graphs=yes" } */
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c
index 28cf580..b981cf9 100644
--- a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fdiagnostics-add-output=sarif:xml-state=yes" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif:state-graphs=yes" } */
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py
index 484da96..3a2c6f8 100644
--- a/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py
+++ b/gcc/testsuite/gcc.dg/analyzer/state-diagram-5-sarif.py
@@ -1,5 +1,3 @@
-import xml.etree.ElementTree as ET
-
from sarif import *
import pytest
@@ -8,7 +6,7 @@ import pytest
def sarif():
return sarif_from_env()
-def test_nested_types_in_xml_state(sarif):
+def test_nested_types_in_state_graph(sarif):
result = get_result_by_index(sarif, 0)
assert result['level'] == 'note'
@@ -16,16 +14,17 @@ def test_nested_types_in_xml_state(sarif):
events = result["codeFlows"][0]["threadFlows"][0]['locations']
assert events[0]['location']['message']['text'] == 'here'
- state = get_xml_state(events, 0)
-
- memory_regions = state.find('memory-regions')
- assert memory_regions is not None
+ state = get_state_graph(events, 0)
- stack = memory_regions.find('stack')
- assert stack is not None
+ stack = state['nodes'][0]
+ assert stack['id'] == 'stack'
+ assert get_state_node_kind(stack) == 'stack'
- frame = stack.find('stack-frame')
- assert frame.get('function') == 'test'
+ frame = stack['children'][0]
+ assert frame['id'].startswith('frame-region-')
+ assert get_state_node_kind(frame) == 'stack-frame'
+ assert get_state_node_attr(frame, 'function') == 'test'
+ assert frame['location']['logicalLocations'][0]['fullyQualifiedName'] == 'test'
# We have:
# baz_arr[1].m_bars[1].m_foos[2].m_ints[1] = 42;
@@ -34,40 +33,57 @@ def test_nested_types_in_xml_state(sarif):
# representation to nested elements and fields.
# "baz_arr":
- baz_arr = frame.find("variable[@name='baz_arr']")
- assert baz_arr.get('type') == 'struct baz[2]'
+ baz_arr = frame['children'][0]
+ assert get_state_node_kind(baz_arr) == 'variable'
+ assert get_state_node_type(baz_arr) == 'struct baz[2]'
+
+ assert len(baz_arr['children']) == 2
+
+ bindings = baz_arr['children'][0]
+ assert bindings['id'].startswith('concrete-bindings-')
+ assert get_state_node_kind(bindings) == 'other'
+ assert get_state_node_value(bindings['children'][0]) == '(int)42'
# "baz_arr[1]":
- baz_arr_1 = baz_arr.find("element[@index='1']")
- assert baz_arr_1.get('type') == 'struct baz'
+ baz_arr_1 = baz_arr['children'][1]
+ assert get_state_node_type(baz_arr_1) == 'struct baz'
+ assert get_state_node_kind(baz_arr_1) == 'element'
+ assert get_state_node_attr(baz_arr_1, 'index') == '1'
- assert baz_arr.find("element[@index='0']") is None
+ assert len(baz_arr_1['children']) == 1
# "baz_arr[1].m_bars":
- baz_arr_1_m_bars = baz_arr_1.find("field[@name='m_bars']")
- assert baz_arr_1_m_bars.get('type') == 'struct bar[2]'
+ baz_arr_1_m_bars = baz_arr_1['children'][0]
+ assert get_state_node_name(baz_arr_1_m_bars) == 'm_bars'
+ assert get_state_node_type(baz_arr_1_m_bars) == 'struct bar[2]'
# "baz_arr[1].m_bars[1]"
- baz_arr_1_m_bars_1 = baz_arr_1_m_bars.find("element[@index='1']")
- assert baz_arr_1_m_bars_1.get('type') == 'struct bar'
+ baz_arr_1_m_bars_1 = baz_arr_1_m_bars['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1) == 'struct bar'
+ assert get_state_node_kind(baz_arr_1_m_bars_1) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1, 'index') == '1'
# "baz_arr[1].m_bars[1].m_foos"
- baz_arr_1_m_bars_1_m_foos = baz_arr_1_m_bars_1.find("field[@name='m_foos']")
- assert baz_arr_1_m_bars_1_m_foos.get('type') == 'struct foo[3]'
+ baz_arr_1_m_bars_1_m_foos = baz_arr_1_m_bars_1['children'][0]
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos) == 'field'
+ assert get_state_node_name(baz_arr_1_m_bars_1_m_foos) == 'm_foos'
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos) == 'struct foo[3]'
# "baz_arr[1].m_bars[1].m_foos[2]"
- baz_arr_1_m_bars_1_m_foos_2 = baz_arr_1_m_bars_1_m_foos.find("element[@index='2']")
- assert baz_arr_1_m_bars_1_m_foos_2.get('type') == 'struct foo'
-
+ baz_arr_1_m_bars_1_m_foos_2 = baz_arr_1_m_bars_1_m_foos['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2) == 'struct foo'
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1_m_foos_2, 'index') == '2'
+
# "baz_arr[1].m_bars[1].m_foos[2].m_ints"
- baz_arr_1_m_bars_1_m_foos_2_m_ints = baz_arr_1_m_bars_1_m_foos_2.find('field[@name="m_ints"]')
- assert baz_arr_1_m_bars_1_m_foos_2_m_ints.get('type') == 'int[4]'
-
- # "baz_arr[1].m_bars[1].m_foos[2].m_ints[1]"
- baz_arr_1_m_bars_1_m_foos_2_m_ints_1 = baz_arr_1_m_bars_1_m_foos_2_m_ints.find('element[@index="1"]')
- assert baz_arr_1_m_bars_1_m_foos_2_m_ints_1.get('type') == 'int'
+ baz_arr_1_m_bars_1_m_foos_2_m_ints = baz_arr_1_m_bars_1_m_foos_2['children'][0]
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'field'
+ assert get_state_node_name(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'm_ints'
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2_m_ints) == 'int[4]'
- value = baz_arr_1_m_bars_1_m_foos_2_m_ints_1.find('value-of-region')
- constant = value.find('constant')
- assert constant.get('value') == '42'
- assert constant.get('type') == 'int'
+ # "baz_arr[1].m_bars[1].m_foos[2].m_ints[1]"
+ baz_arr_1_m_bars_1_m_foos_2_m_ints_1 = baz_arr_1_m_bars_1_m_foos_2_m_ints['children'][0]
+ assert get_state_node_type(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == 'int'
+ assert get_state_node_kind(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == 'element'
+ assert get_state_node_attr(baz_arr_1_m_bars_1_m_foos_2_m_ints_1, 'index') == '1'
+ assert get_state_node_value(baz_arr_1_m_bars_1_m_foos_2_m_ints_1) == '(int)42'
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c
new file mode 100644
index 0000000..2256a63
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */
+
+extern void here (void);
+
+void test_graphs (void)
+{
+ here (); /* { dg-error "this is a placeholder error, with graphs" } */
+}
+
+/* Use a Python script to verify various properties about the generated
+ HTML file:
+ { dg-final { run-html-pytest diagnostic-test-graphs-html.c "diagnostic-test-graphs-html.py" } } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py
new file mode 100644
index 0000000..11e5fd1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py
@@ -0,0 +1,48 @@
+# Verify that metadata works in HTML output.
+
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def test_result_graph(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ diag_list = body.find('xhtml:div', ns)
+ assert diag_list is not None
+ assert diag_list.attrib['class'] == 'gcc-diagnostic-list'
+
+ diag = diag_list.find('xhtml:div', ns)
+ assert diag is not None
+
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
+ assert message.attrib['id'] == 'gcc-diag-0-message'
+
+ assert message[0].tag == make_tag('strong')
+ assert message[0].tail == ' this is a placeholder error, with graphs '
+
+ graph = diag.find("./xhtml:div[@class='gcc-directed-graph']", ns)
+ assert graph is not None
+
+ header = graph.find("./xhtml:h2", ns)
+ assert header.text == 'foo'
+
+def test_run_graph(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ graph = body.find("./xhtml:div[@class='gcc-directed-graph']", ns)
+ assert graph is not None
+
+ header = graph.find("./xhtml:h2", ns)
+ assert header.text == 'Optimization Passes'
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c
new file mode 100644
index 0000000..4170f51
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-add-output=sarif" } */
+
+extern void here (void);
+
+void test_graphs (void)
+{
+ here (); /* { dg-error "this is a placeholder error, with graphs" } */
+}
+
+/* Verify that some JSON was written to a file with the expected name. */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest diagnostic-test-graphs-sarif.c "diagnostic-test-graphs-sarif.py" } } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py
new file mode 100644
index 0000000..4bb7535
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py
@@ -0,0 +1,55 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_basics(sarif):
+ schema = sarif['$schema']
+ assert schema == "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json"
+
+ version = sarif['version']
+ assert version == "2.1.0"
+
+def test_result_graph(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+ results = run['results']
+
+ assert len(results) == 1
+
+ result = results[0]
+ assert result['level'] == 'error'
+ assert result['message']['text'] == "this is a placeholder error, with graphs"
+
+ assert len(result['graphs']) == 2
+
+ assert result['graphs'][0]['description']['text'] == 'foo'
+
+ assert len(result['graphs'][0]['nodes']) == 2
+ assert result['graphs'][0]['nodes'][0]['id'] == 'a'
+ assert result['graphs'][0]['nodes'][1]['id'] == 'b'
+ assert result['graphs'][0]['nodes'][1]['properties']['/placeholder-prefix/color'] == 'red'
+ assert len(result['graphs'][0]['nodes'][1]['children']) == 1
+ assert result['graphs'][0]['nodes'][1]['children'][0]['id'] == 'c'
+ assert result['graphs'][0]['nodes'][1]['children'][0]['label']['text'] == 'I am a node label'
+
+ assert len(result['graphs'][0]['edges']) == 1
+ result['graphs'][0]['edges'][0]['id'] == 'my-edge'
+ assert result['graphs'][0]['edges'][0]['label']['text'] == 'I am an edge label'
+ assert result['graphs'][0]['edges'][0]['sourceNodeId'] == 'a'
+ assert result['graphs'][0]['edges'][0]['targetNodeId'] == 'c'
+
+ assert result['graphs'][1]['description']['text'] == 'bar'
+
+def test_run_graph(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ assert len(run['graphs']) == 1
+
+ assert run['graphs'][0]['description']['text'] == 'Optimization Passes'
+ assert run['graphs'][0]['nodes'][0]['id'] == 'all_lowering_passes'
+ assert run['graphs'][0]['edges'][0]['id'] == 'edge0'
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c
new file mode 100644
index 0000000..7973954
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+
+extern void here (void);
+
+void test_graphs (void)
+{
+ here (); /* { dg-error "this is a placeholder error, with graphs" } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
new file mode 100644
index 0000000..d432161
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
@@ -0,0 +1,283 @@
+/* This plugin exercises diagnostic graphs.
+ We emit an error with a pair of digraphs associated with it,
+ and a global digraph showing the optimization passes. */
+
+#define INCLUDE_MAP
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin-version.h"
+#include "diagnostic.h"
+#include "context.h"
+#include "gcc-rich-location.h"
+#include "diagnostic-metadata.h"
+#include "diagnostic-digraphs.h"
+#include "pass_manager.h"
+
+
+int plugin_is_GPL_compatible;
+
+const pass_data pass_data_test_graph_emission =
+{
+ GIMPLE_PASS, /* type */
+ "test_graph_emission", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_test_graph_emission : public gimple_opt_pass
+{
+public:
+ pass_test_graph_emission(gcc::context *ctxt)
+ : gimple_opt_pass(pass_data_test_graph_emission, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate (function *) { return true; }
+ virtual unsigned int execute (function *);
+
+}; // class pass_test_graph_emission
+
+/* Determine if STMT is a call with NUM_ARGS arguments to a function
+ named FUNCNAME.
+ If so, return STMT as a gcall *. Otherwise return NULL. */
+
+static gcall *
+check_for_named_call (gimple *stmt,
+ const char *funcname, unsigned int num_args)
+{
+ gcc_assert (funcname);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ if (!call)
+ return NULL;
+
+ tree fndecl = gimple_call_fndecl (call);
+ if (!fndecl)
+ return NULL;
+
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
+ return NULL;
+
+ if (gimple_call_num_args (call) != num_args)
+ {
+ error_at (stmt->location, "expected number of args: %i (got %i)",
+ num_args, gimple_call_num_args (call));
+ return NULL;
+ }
+
+ return call;
+}
+
+class lazy_passes_graph : public diagnostics::digraphs::lazy_digraph
+{
+public:
+ lazy_passes_graph (const ::gcc::pass_manager &pass_manager_)
+ : m_pass_manager (pass_manager_)
+ {
+ }
+
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ create_digraph () const final override
+ {
+ auto g = std::make_unique<diagnostics::digraphs::digraph> ();
+ g->set_description ("Optimization Passes");
+
+#define DEF_PASS_LIST(NAME) \
+ add_top_level_pass_list (*g, #NAME, m_pass_manager.NAME);
+
+ GCC_PASS_LISTS
+
+#undef DEF_PASS_LIST
+
+ return g;
+ }
+
+ void
+ add_top_level_pass_list (diagnostics::digraphs::digraph &g,
+ const char *pass_list_name,
+ const opt_pass *p) const
+ {
+ gcc_assert (p);
+ auto n = std::make_unique<diagnostics::digraphs::node> (g, pass_list_name);
+ n->set_label (pass_list_name);
+ add_child_pass (g, *n, *p);
+ g.add_node (std::move (n));
+ }
+
+ diagnostics::digraphs::node &
+ add_child_pass (diagnostics::digraphs::digraph &g,
+ diagnostics::digraphs::node &parent_node,
+ const opt_pass &p) const
+ {
+ std::string node_label;
+ std::string node_id;
+ if (p.static_pass_number > 0 )
+ {
+ node_label = std::to_string (p.static_pass_number) + "_" + p.name;
+ node_id = node_label;
+ }
+ else
+ {
+ node_label = std::string (p.name);
+ pretty_printer pp;
+ pp_printf (&pp, "%s_%p", p.name, &p);
+ node_id = pp_formatted_text (&pp);
+ }
+ auto n
+ = std::make_unique<diagnostics::digraphs::node> (g,
+ std::move (node_id));
+ n->set_label (node_label.c_str ());
+ diagnostics::digraphs::node &result = *n;
+ parent_node.add_child (std::move (n));
+
+ // TODO: add attrs for things like type, properties_*, etc
+
+ if (p.sub)
+ {
+ auto &other_node = add_child_pass (g, parent_node, *p.sub);
+ g.add_edge (nullptr, result, other_node, "sub");
+ }
+
+ if (p.next)
+ {
+ auto &other_node = add_child_pass (g, parent_node, *p.next);
+ g.add_edge (nullptr, result, other_node, "next");
+ }
+
+ return result;
+ }
+
+private:
+ const ::gcc::pass_manager &m_pass_manager;
+};
+
+static void
+report_diag_with_graphs (location_t loc)
+{
+ class my_lazy_digraphs : public diagnostics::digraphs::lazy_digraphs
+ {
+ public:
+ using diagnostic_graph = diagnostics::digraphs::digraph;
+ using diagnostic_node = diagnostics::digraphs::node;
+ using diagnostic_edge = diagnostics::digraphs::edge;
+
+ std::unique_ptr<std::vector<std::unique_ptr<diagnostic_graph>>>
+ create_digraphs () const final override
+ {
+ auto graphs
+ = std::make_unique<std::vector<std::unique_ptr<diagnostic_graph>>> ();
+
+ graphs->push_back (make_test_graph ("foo"));
+ graphs->push_back (make_test_graph ("bar"));
+
+ return graphs;
+ }
+
+ private:
+ std::unique_ptr<diagnostic_graph>
+ make_test_graph (const char *desc) const
+ {
+ auto g = std::make_unique<diagnostic_graph> ();
+ g->set_description (desc);
+ auto a = std::make_unique<diagnostic_node> (*g, "a");
+ auto b = std::make_unique<diagnostic_node> (*g, "b");
+#define KEY_PREFIX "/placeholder-prefix/"
+ b->set_attr (KEY_PREFIX, "color", "red");
+#undef KEY_PREFIX
+ auto c = std::make_unique<diagnostic_node> (*g, "c");
+ c->set_label ("I am a node label");
+
+ auto e = std::make_unique<diagnostic_edge> (*g, "my-edge", *a, *c);
+ e->set_label ("I am an edge label");
+ g->add_edge (std::move (e));
+
+ g->add_node (std::move (a));
+
+ b->add_child (std::move (c));
+ g->add_node (std::move (b));
+
+ return g;
+ }
+ };
+
+ gcc_rich_location rich_loc (loc);
+ diagnostic_metadata meta;
+ my_lazy_digraphs ldg;
+ meta.set_lazy_digraphs (&ldg);
+ error_meta (&rich_loc, meta,
+ "this is a placeholder error, with graphs");
+}
+
+/* Exercise diagnostic graph emission. */
+
+unsigned int
+pass_test_graph_emission::execute (function *fun)
+{
+ gimple_stmt_iterator gsi;
+ basic_block bb;
+
+ FOR_EACH_BB_FN (bb, fun)
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gcall *call = check_for_named_call (stmt, "here", 0))
+ report_diag_with_graphs (gimple_location (call));
+ }
+
+ return 0;
+}
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+ struct plugin_gcc_version *version)
+{
+ struct register_pass_info pass_info;
+ const char *plugin_name = plugin_info->base_name;
+ int argc = plugin_info->argc;
+ struct plugin_argument *argv = plugin_info->argv;
+
+ if (!plugin_default_version_check (version, &gcc_version))
+ return 1;
+
+ pass_info.pass = new pass_test_graph_emission (g);
+ pass_info.reference_pass_name = "ssa";
+ pass_info.ref_pass_instance_number = 1;
+ pass_info.pos_op = PASS_POS_INSERT_AFTER;
+ register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ &pass_info);
+
+ gcc_assert (::g->get_passes ());
+ global_dc->report_global_digraph (lazy_passes_graph (*::g->get_passes ()));
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index d1d7f5d..ce25c0a 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -107,6 +107,10 @@ set plugin_test_list [list \
diagnostic-test-metadata.c \
diagnostic-test-metadata-html.c \
diagnostic-test-metadata-sarif.c } \
+ { diagnostic_plugin_test_graphs.cc
+ diagnostic-test-graphs.c \
+ diagnostic-test-graphs-html.c \
+ diagnostic-test-graphs-sarif.c } \
{ diagnostic_plugin_test_nesting.cc \
diagnostic-test-nesting-text-plain.c \
diagnostic-test-nesting-text-indented.c \
diff --git a/gcc/testsuite/gcc.dg/pr87600-1.c b/gcc/testsuite/gcc.dg/pr87600-1.c
index 3517957..9d74cad 100644
--- a/gcc/testsuite/gcc.dg/pr87600-1.c
+++ b/gcc/testsuite/gcc.dg/pr87600-1.c
@@ -1,5 +1,5 @@
/* PR rtl-optimization/87600 */
-/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* loongarch*-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
/* { dg-options "-O2" } */
#include "pr87600.h"
diff --git a/gcc/testsuite/gcc.dg/pr87600-2.c b/gcc/testsuite/gcc.dg/pr87600-2.c
index e8a9f19..808ebe1 100644
--- a/gcc/testsuite/gcc.dg/pr87600-2.c
+++ b/gcc/testsuite/gcc.dg/pr87600-2.c
@@ -1,5 +1,5 @@
/* PR rtl-optimization/87600 */
-/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* loongarch*-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
/* { dg-options "-O2" } */
#include "pr87600.h"
diff --git a/gcc/testsuite/gcc.dg/pr87600.h b/gcc/testsuite/gcc.dg/pr87600.h
index c89071eb..29f065e 100644
--- a/gcc/testsuite/gcc.dg/pr87600.h
+++ b/gcc/testsuite/gcc.dg/pr87600.h
@@ -7,6 +7,9 @@
#elif defined (__i386__)
# define REG1 "%eax"
# define REG2 "%edx"
+#elif defined (__loongarch__)
+# define REG1 "$t0"
+# define REG2 "$t1"
#elif defined (__powerpc__) || defined (__POWERPC__) || defined (__PPC__)
# define REG1 "r3"
# define REG2 "r4"
diff --git a/gcc/testsuite/gfortran.dg/goacc/parameter-3.f90 b/gcc/testsuite/gfortran.dg/goacc/parameter-3.f90
new file mode 100644
index 0000000..2c8aa61
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/goacc/parameter-3.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+
+subroutine x
+ integer :: var
+ integer, parameter :: ilog = 0
+ integer, parameter :: array(*) = [11,22,33]
+ !$ACC DECLARE COPYIN(ilog, array, var, array) ! { dg-error "Symbol 'array' present on multiple clauses" }
+end subroutine x
+
+integer :: a
+integer, parameter :: b = 4
+integer, parameter :: c(*) = [1,2,3]
+
+!$acc parallel copy(a,c,b,c) ! { dg-error "Symbol 'c' present on multiple clauses" }
+!$acc end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/goacc/parameter-4.f90 b/gcc/testsuite/gfortran.dg/goacc/parameter-4.f90
new file mode 100644
index 0000000..aadd7cf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/goacc/parameter-4.f90
@@ -0,0 +1,26 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+subroutine x
+ integer :: var
+ integer, parameter :: ilog = 0
+ integer, parameter :: array(*) = [11,22,33]
+ !$ACC DECLARE COPYIN(ilog, array, var)
+end subroutine x
+
+integer :: a
+integer, parameter :: b = 4
+integer, parameter :: c(*) = [1,2,3]
+
+!$acc parallel copy(a,c,b)
+ a = c(2) + b
+!$acc end parallel
+
+!$acc parallel firstprivate(a,c,b)
+ a = c(2) + b
+!$acc end parallel
+end
+
+! { dg-final { scan-tree-dump-times "#pragma acc data map\\(to:var\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(tofrom:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma acc parallel firstprivate\\(a\\)" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/goacc/parameter.f95 b/gcc/testsuite/gfortran.dg/goacc/parameter.f95
index b581338..a9bde4a 100644
--- a/gcc/testsuite/gfortran.dg/goacc/parameter.f95
+++ b/gcc/testsuite/gfortran.dg/goacc/parameter.f95
@@ -1,4 +1,5 @@
! { dg-do compile }
+! { dg-additional-options "-Wsurprising" }
module test
contains
@@ -6,37 +7,37 @@ contains
implicit none
integer :: i
integer, parameter :: a = 1
- !$acc declare device_resident (a) ! { dg-error "is not a variable" }
- !$acc data copy (a) ! { dg-error "not a variable" }
+ !$acc declare device_resident (a) ! (no warning here - for semi-good reasons)
+ !$acc data copy (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as parameters need not be copied \\\[-Wsurprising\\\]" }
!$acc end data
- !$acc data deviceptr (a) ! { dg-error "not a variable" }
+ !$acc data deviceptr (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as parameters need not be copied \\\[-Wsurprising\\\]" }
!$acc end data
- !$acc parallel private (a) ! { dg-error "not a variable" }
+ !$acc parallel private (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
!$acc end parallel
- !$acc serial private (a) ! { dg-error "not a variable" }
+ !$acc serial private (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
!$acc end serial
- !$acc host_data use_device (a) ! { dg-error "not a variable" }
+ !$acc host_data use_device (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
!$acc end host_data
- !$acc parallel loop reduction(+:a) ! { dg-error "not a variable" }
+ !$acc parallel loop reduction(+:a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
do i = 1,5
enddo
!$acc end parallel loop
- !$acc serial loop reduction(+:a) ! { dg-error "not a variable" }
+ !$acc serial loop reduction(+:a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
do i = 1,5
enddo
!$acc end serial loop
!$acc parallel loop
do i = 1,5
- !$acc cache (a) ! { dg-error "not a variable" }
+ !$acc cache (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
enddo
!$acc end parallel loop
!$acc serial loop
do i = 1,5
- !$acc cache (a) ! { dg-error "not a variable" }
+ !$acc cache (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as it is a parameter \\\[-Wsurprising\\\]" }
enddo
!$acc end serial loop
- !$acc update device (a) ! { dg-error "not a variable" }
- !$acc update host (a) ! { dg-error "not a variable" }
- !$acc update self (a) ! { dg-error "not a variable" }
+ !$acc update device (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as parameters need not be copied \\\[-Wsurprising\\\]" }
+ !$acc update host (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as parameters need not be copied \\\[-Wsurprising\\\]" }
+ !$acc update self (a) ! { dg-warning "Clause for object 'a' at .1. is ignored as parameters need not be copied \\\[-Wsurprising\\\]" }
end subroutine oacc1
end module test
diff --git a/gcc/testsuite/lib/sarif.py b/gcc/testsuite/lib/sarif.py
index 384de2f..06d05c0 100644
--- a/gcc/testsuite/lib/sarif.py
+++ b/gcc/testsuite/lib/sarif.py
@@ -29,10 +29,24 @@ def get_result_by_index(sarif, idx):
results = run['results']
return results[idx]
-def get_xml_state(events, event_idx):
- xml_src = events[event_idx]['properties']['gcc/diagnostic_event/xml_state']
+def get_state_graph(events, event_idx):
+ graph = events[event_idx]['properties']['gcc/diagnostic_event/state_graph']
if 0:
- print(xml_src)
- xml = ET.fromstring(xml_src)
- assert xml.tag == 'state-diagram'
- return xml
+ print(graph)
+ assert graph is not None
+ return graph
+
+def get_state_node_attr(obj, attr_name):
+ return obj['properties']['gcc/diagnostic_state_node/%s' % attr_name]
+
+def get_state_node_kind(obj):
+ return get_state_node_attr(obj, 'kind')
+
+def get_state_node_name(obj):
+ return get_state_node_attr(obj, 'name')
+
+def get_state_node_type(obj):
+ return get_state_node_attr(obj, 'type')
+
+def get_state_node_value(obj):
+ return get_state_node_attr(obj, 'value')
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.40.2-duplicate-node-id.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.40.2-duplicate-node-id.sarif
new file mode 100644
index 0000000..a4eb9d4
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.40.2-duplicate-node-id.sarif
@@ -0,0 +1,23 @@
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": { "driver": { "name": "example" } },
+ "results": [],
+ "graphs": [{"nodes": [{"id": "a", /* { dg-message "'a' already used as node id within graph here" } */
+ "children": [{"id": "a"}]}], /* { dg-error "duplicate node id 'a' within graph \\\[SARIF v2.1.0 §3.40.2\\\]" } */
+ "edges": []}]}]}
+
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/graphs/0/nodes/0/children/0/id':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ 6 | "children": [{"id": "a"}]}],
+ | ^~~
+ { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/graphs/0/nodes/0/id':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ 5 | "graphs": [{"nodes": [{"id": "a",
+ | ^~~
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.41.4-unrecognized-node-id.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.41.4-unrecognized-node-id.sarif
new file mode 100644
index 0000000..b483346
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.41.4-unrecognized-node-id.sarif
@@ -0,0 +1,16 @@
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": { "driver": { "name": "example" } },
+ "results": [],
+ "graphs": [{"nodes": [],
+ "edges": [{"id": "edge0",
+ "sourceNodeId": "this-does-not-exist", /* { dg-error "no node with id 'this-does-not-exist' in graph \\\[SARIF v2.1.0 §3.41.4\\\]" } */
+ "targetNodeId": "neither-does-this"}]}]}]}
+
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/graphs/0/edges/0/sourceNodeId':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ 7 | "sourceNodeId": "this-does-not-exist",
+ | ^~~~~~~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py
new file mode 100644
index 0000000..63b80c9
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py
@@ -0,0 +1,46 @@
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def test_result_graph(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ diag_list = body.find('xhtml:div', ns)
+ assert diag_list is not None
+ assert diag_list.attrib['class'] == 'gcc-diagnostic-list'
+
+ diag = diag_list.find('xhtml:div', ns)
+ assert diag is not None
+
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
+ assert message.attrib['id'] == 'gcc-diag-0-message'
+
+ assert message[0].tag == make_tag('strong')
+ assert message[0].tail == ' this is a placeholder error, with graphs '
+
+ graph = diag.find("./xhtml:div[@class='gcc-directed-graph']", ns)
+ assert graph is not None
+
+ header = graph.find("./xhtml:h2", ns)
+ assert header.text == 'foo'
+
+def test_run_graph(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ graph = body.find("./xhtml:div[@class='gcc-directed-graph']", ns)
+ assert graph is not None
+
+ header = graph.find("./xhtml:h2", ns)
+ assert header.text == 'Optimization Passes'
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-sarif-roundtrip.py b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-sarif-roundtrip.py
new file mode 100644
index 0000000..4bb7535
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-sarif-roundtrip.py
@@ -0,0 +1,55 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_basics(sarif):
+ schema = sarif['$schema']
+ assert schema == "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json"
+
+ version = sarif['version']
+ assert version == "2.1.0"
+
+def test_result_graph(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+ results = run['results']
+
+ assert len(results) == 1
+
+ result = results[0]
+ assert result['level'] == 'error'
+ assert result['message']['text'] == "this is a placeholder error, with graphs"
+
+ assert len(result['graphs']) == 2
+
+ assert result['graphs'][0]['description']['text'] == 'foo'
+
+ assert len(result['graphs'][0]['nodes']) == 2
+ assert result['graphs'][0]['nodes'][0]['id'] == 'a'
+ assert result['graphs'][0]['nodes'][1]['id'] == 'b'
+ assert result['graphs'][0]['nodes'][1]['properties']['/placeholder-prefix/color'] == 'red'
+ assert len(result['graphs'][0]['nodes'][1]['children']) == 1
+ assert result['graphs'][0]['nodes'][1]['children'][0]['id'] == 'c'
+ assert result['graphs'][0]['nodes'][1]['children'][0]['label']['text'] == 'I am a node label'
+
+ assert len(result['graphs'][0]['edges']) == 1
+ result['graphs'][0]['edges'][0]['id'] == 'my-edge'
+ assert result['graphs'][0]['edges'][0]['label']['text'] == 'I am an edge label'
+ assert result['graphs'][0]['edges'][0]['sourceNodeId'] == 'a'
+ assert result['graphs'][0]['edges'][0]['targetNodeId'] == 'c'
+
+ assert result['graphs'][1]['description']['text'] == 'bar'
+
+def test_run_graph(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ assert len(run['graphs']) == 1
+
+ assert run['graphs'][0]['description']['text'] == 'Optimization Passes'
+ assert run['graphs'][0]['nodes'][0]['id'] == 'all_lowering_passes'
+ assert run['graphs'][0]['edges'][0]['id'] == 'edge0'
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs.sarif
new file mode 100644
index 0000000..da236ba
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs.sarif
@@ -0,0 +1,2445 @@
+/* Test a replay of a .sarif file generated from GCC testsuite.
+
+ The dg directives were stripped out from the generated .sarif
+ to avoid confusing DejaGnu for this test. */
+/* { dg-additional-options "-fdiagnostics-add-output=experimental-html:file=graphs.sarif.html,javascript=no" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif:file=graphs.roundtrip.sarif" } */
+
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "GNU C23",
+ "fullName": "GNU C23 (GCC) version 16.0.0 20250702 (experimental) (x86_64-pc-linux-gnu)",
+ "version": "16.0.0 20250702 (experimental)",
+ "informationUri": "https://gcc.gnu.org/gcc-16/",
+ "rules": []},
+ "extensions": [{"name": "diagnostic_plugin_test_graphs",
+ "fullName": "./diagnostic_plugin_test_graphs.so"}]},
+ "invocations": [{"arguments": ["/home/david/gcc-newgit-gcc16/build/gcc/cc1",
+ "-quiet",
+ "-iprefix",
+ "/usr/local/lib/gcc/x86_64-pc-linux-gnu/16.0.0/",
+ "-isystem",
+ "/home/david/gcc-newgit-gcc16/build/gcc/include",
+ "-isystem",
+ "/home/david/gcc-newgit-gcc16/build/gcc/include-fixed",
+ "-iplugindir=/home/david/gcc-newgit-gcc16/build/gcc/plugin",
+ "/home/david/gcc-newgit-gcc16/src/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c",
+ "-iplugindir=/home/david/gcc-newgit-gcc16/build/gcc/plugin",
+ "-quiet",
+ "-dumpbase",
+ "diagnostic-test-graphs-sarif.c",
+ "-dumpbase-ext",
+ ".c",
+ "-mtune=generic",
+ "-march=x86-64",
+ "-fdiagnostics-color=never",
+ "-fdiagnostics-urls=never",
+ "-fno-diagnostics-show-caret",
+ "-fno-diagnostics-show-line-numbers",
+ "-fdiagnostics-path-format=separate-events",
+ "-fdiagnostics-text-art-charset=none",
+ "-fno-diagnostics-show-event-links",
+ "-fplugin=./diagnostic_plugin_test_graphs.so",
+ "-fdiagnostics-add-output=sarif",
+ "-o",
+ "diagnostic-test-graphs-sarif.s"],
+ "workingDirectory": {"uri": "/home/david/gcc-newgit-gcc16/build/gcc/testsuite/gcc"},
+ "startTimeUtc": "2025-07-09T22:43:31Z",
+ "executionSuccessful": false,
+ "toolExecutionNotifications": [],
+ "endTimeUtc": "2025-07-09T22:43:31Z"}],
+ "artifacts": [{"location": {"uri": "/home/david/gcc-newgit-gcc16/src/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c"},
+ "sourceLanguage": "c",
+ "roles": ["analysisTarget"]}],
+ "results": [{"ruleId": "error",
+ "level": "error",
+ "message": {"text": "this is a placeholder error, with graphs"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "/home/david/gcc-newgit-gcc16/src/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c"},
+ "region": {"startLine": 8,
+ "startColumn": 3,
+ "endColumn": 10},
+ "contextRegion": {"startLine": 8,
+ "snippet": {"text": " here ();"}}},
+ "logicalLocations": [{"index": 0,
+ "fullyQualifiedName": "test_graphs"}]}],
+ "graphs": [{"description": {"text": "foo"},
+ "nodes": [{"id": "a"},
+ {"id": "b",
+ "properties": {"/placeholder-prefix/color": "red"},
+ "children": [{"id": "c",
+ "label": {"text": "I am a node label"}}]}],
+ "edges": [{"id": "my-edge",
+ "label": {"text": "I am an edge label"},
+ "sourceNodeId": "a",
+ "targetNodeId": "c"}]},
+ {"description": {"text": "bar"},
+ "nodes": [{"id": "a"},
+ {"id": "b",
+ "properties": {"/placeholder-prefix/color": "red"},
+ "children": [{"id": "c",
+ "label": {"text": "I am a node label"}}]}],
+ "edges": [{"id": "my-edge",
+ "label": {"text": "I am an edge label"},
+ "sourceNodeId": "a",
+ "targetNodeId": "c"}]}]}],
+ "logicalLocations": [{"name": "test_graphs",
+ "fullyQualifiedName": "test_graphs",
+ "decoratedName": "test_graphs",
+ "kind": "function",
+ "index": 0}],
+ "graphs": [{"description": {"text": "Optimization Passes"},
+ "nodes": [{"id": "all_lowering_passes",
+ "label": {"text": "all_lowering_passes"},
+ "children": [{"id": "*warn_unused_result_0x101ef3d0",
+ "label": {"text": "*warn_unused_result"}},
+ {"id": "*diagnose_omp_blocks_0x101ef430",
+ "label": {"text": "*diagnose_omp_blocks"}},
+ {"id": "*diagnose_tm_blocks_0x101ef490",
+ "label": {"text": "*diagnose_tm_blocks"}},
+ {"id": "13_omp_oacc_kernels_decompose",
+ "label": {"text": "13_omp_oacc_kernels_decompose"}},
+ {"id": "14_omplower",
+ "label": {"text": "14_omplower"}},
+ {"id": "15_lower",
+ "label": {"text": "15_lower"}},
+ {"id": "16_tmlower",
+ "label": {"text": "16_tmlower"}},
+ {"id": "17_ehopt",
+ "label": {"text": "17_ehopt"}},
+ {"id": "18_eh",
+ "label": {"text": "18_eh"}},
+ {"id": "19_coro-lower-builtins",
+ "label": {"text": "19_coro-lower-builtins"}},
+ {"id": "20_cfg",
+ "label": {"text": "20_cfg"}},
+ {"id": "*warn_function_return_0x101ef7f0",
+ "label": {"text": "*warn_function_return"}},
+ {"id": "21_coro-early-expand-ifns",
+ "label": {"text": "21_coro-early-expand-ifns"}},
+ {"id": "22_ompexp",
+ "label": {"text": "22_ompexp"}},
+ {"id": "*build_cgraph_edges_0x101ef910",
+ "label": {"text": "*build_cgraph_edges"}}]},
+ {"id": "all_small_ipa_passes",
+ "label": {"text": "all_small_ipa_passes"},
+ "children": [{"id": "23_afdo_offline",
+ "label": {"text": "23_afdo_offline"}},
+ {"id": "*free_lang_data_0x101ef9d0",
+ "label": {"text": "*free_lang_data"}},
+ {"id": "24_visibility",
+ "label": {"text": "24_visibility"}},
+ {"id": "25_strubm",
+ "label": {"text": "25_strubm"}},
+ {"id": "26_build_ssa_passes",
+ "label": {"text": "26_build_ssa_passes"}},
+ {"id": "27_fixup_cfg",
+ "label": {"text": "27_fixup_cfg"}},
+ {"id": "28_ssa",
+ "label": {"text": "28_ssa"}},
+ {"id": "376_test_graph_emission",
+ "label": {"text": "376_test_graph_emission"}},
+ {"id": "29_walloca",
+ "label": {"text": "29_walloca"}},
+ {"id": "30_warn-printf",
+ "label": {"text": "30_warn-printf"}},
+ {"id": "*nonnullcmp_0x101efce0",
+ "label": {"text": "*nonnullcmp"}},
+ {"id": "31_early_uninit",
+ "label": {"text": "31_early_uninit"}},
+ {"id": "32_waccess",
+ "label": {"text": "32_waccess"}},
+ {"id": "33_ubsan",
+ "label": {"text": "33_ubsan"}},
+ {"id": "34_nothrow",
+ "label": {"text": "34_nothrow"}},
+ {"id": "*rebuild_cgraph_edges_0x101f0020",
+ "label": {"text": "*rebuild_cgraph_edges"}},
+ {"id": "35_opt_local_passes",
+ "label": {"text": "35_opt_local_passes"}},
+ {"id": "36_fixup_cfg",
+ "label": {"text": "36_fixup_cfg"}},
+ {"id": "*rebuild_cgraph_edges_0x101f0140",
+ "label": {"text": "*rebuild_cgraph_edges"}},
+ {"id": "37_local-fnsummary",
+ "label": {"text": "37_local-fnsummary"}},
+ {"id": "38_einline",
+ "label": {"text": "38_einline"}},
+ {"id": "*infinite-recursion_0x101f0260",
+ "label": {"text": "*infinite-recursion"}},
+ {"id": "39_early_optimizations",
+ "label": {"text": "39_early_optimizations"}},
+ {"id": "*remove_cgraph_callee_edges_0x101f0340",
+ "label": {"text": "*remove_cgraph_callee_edges"}},
+ {"id": "40_early_objsz",
+ "label": {"text": "40_early_objsz"}},
+ {"id": "41_ccp",
+ "label": {"text": "41_ccp"}},
+ {"id": "42_forwprop",
+ "label": {"text": "42_forwprop"}},
+ {"id": "43_ethread",
+ "label": {"text": "43_ethread"}},
+ {"id": "44_esra",
+ "label": {"text": "44_esra"}},
+ {"id": "45_ealias",
+ "label": {"text": "45_ealias"}},
+ {"id": "46_phiprop",
+ "label": {"text": "46_phiprop"}},
+ {"id": "47_fre",
+ "label": {"text": "47_fre"}},
+ {"id": "48_evrp",
+ "label": {"text": "48_evrp"}},
+ {"id": "49_mergephi",
+ "label": {"text": "49_mergephi"}},
+ {"id": "50_dse",
+ "label": {"text": "50_dse"}},
+ {"id": "51_cddce",
+ "label": {"text": "51_cddce"}},
+ {"id": "52_phiopt",
+ "label": {"text": "52_phiopt"}},
+ {"id": "53_tailr",
+ "label": {"text": "53_tailr"}},
+ {"id": "54_iftoswitch",
+ "label": {"text": "54_iftoswitch"}},
+ {"id": "55_switchconv",
+ "label": {"text": "55_switchconv"}},
+ {"id": "56_ehcleanup",
+ "label": {"text": "56_ehcleanup"}},
+ {"id": "57_sccopy",
+ "label": {"text": "57_sccopy"}},
+ {"id": "58_profile_estimate",
+ "label": {"text": "58_profile_estimate"}},
+ {"id": "59_local-pure-const",
+ "label": {"text": "59_local-pure-const"}},
+ {"id": "60_modref",
+ "label": {"text": "60_modref"}},
+ {"id": "61_fnsplit",
+ "label": {"text": "61_fnsplit"}},
+ {"id": "*strip_predict_hints_0x101f0c60",
+ "label": {"text": "*strip_predict_hints"}},
+ {"id": "62_release_ssa",
+ "label": {"text": "62_release_ssa"}},
+ {"id": "*rebuild_cgraph_edges_0x101f0d30",
+ "label": {"text": "*rebuild_cgraph_edges"}},
+ {"id": "63_local-fnsummary",
+ "label": {"text": "63_local-fnsummary"}},
+ {"id": "64_remove_symbols",
+ "label": {"text": "64_remove_symbols"}},
+ {"id": "65_strub",
+ "label": {"text": "65_strub"}},
+ {"id": "66_ipa_oacc",
+ "label": {"text": "66_ipa_oacc"}},
+ {"id": "67_pta",
+ "label": {"text": "67_pta"}},
+ {"id": "68_ipa_oacc_kernels",
+ "label": {"text": "68_ipa_oacc_kernels"}},
+ {"id": "69_oacc_kernels",
+ "label": {"text": "69_oacc_kernels"}},
+ {"id": "70_ch",
+ "label": {"text": "70_ch"}},
+ {"id": "71_fre",
+ "label": {"text": "71_fre"}},
+ {"id": "72_lim",
+ "label": {"text": "72_lim"}},
+ {"id": "73_dom",
+ "label": {"text": "73_dom"}},
+ {"id": "74_dce",
+ "label": {"text": "74_dce"}},
+ {"id": "75_parloops",
+ "label": {"text": "75_parloops"}},
+ {"id": "76_ompexpssa",
+ "label": {"text": "76_ompexpssa"}},
+ {"id": "*rebuild_cgraph_edges_0x101f1310",
+ "label": {"text": "*rebuild_cgraph_edges"}},
+ {"id": "77_targetclone",
+ "label": {"text": "77_targetclone"}},
+ {"id": "78_afdo",
+ "label": {"text": "78_afdo"}},
+ {"id": "79_feedback_fnsplit",
+ "label": {"text": "79_feedback_fnsplit"}},
+ {"id": "80_profile",
+ "label": {"text": "80_profile"}},
+ {"id": "81_feedback_fnsplit",
+ "label": {"text": "81_feedback_fnsplit"}},
+ {"id": "82_free-fnsummary",
+ "label": {"text": "82_free-fnsummary"}},
+ {"id": "83_increase_alignment",
+ "label": {"text": "83_increase_alignment"}},
+ {"id": "84_tmipa",
+ "label": {"text": "84_tmipa"}},
+ {"id": "85_emutls",
+ "label": {"text": "85_emutls"}}]},
+ {"id": "all_regular_ipa_passes",
+ "label": {"text": "all_regular_ipa_passes"},
+ "children": [{"id": "86_analyzer",
+ "label": {"text": "86_analyzer"}},
+ {"id": "87_odr",
+ "label": {"text": "87_odr"}},
+ {"id": "88_whole-program",
+ "label": {"text": "88_whole-program"}},
+ {"id": "89_profile_estimate",
+ "label": {"text": "89_profile_estimate"}},
+ {"id": "90_icf",
+ "label": {"text": "90_icf"}},
+ {"id": "91_devirt",
+ "label": {"text": "91_devirt"}},
+ {"id": "92_cdtor",
+ "label": {"text": "92_cdtor"}},
+ {"id": "93_cp",
+ "label": {"text": "93_cp"}},
+ {"id": "94_sra",
+ "label": {"text": "94_sra"}},
+ {"id": "95_fnsummary",
+ "label": {"text": "95_fnsummary"}},
+ {"id": "96_inline",
+ "label": {"text": "96_inline"}},
+ {"id": "97_locality-clone",
+ "label": {"text": "97_locality-clone"}},
+ {"id": "98_pure-const",
+ "label": {"text": "98_pure-const"}},
+ {"id": "99_modref",
+ "label": {"text": "99_modref"}},
+ {"id": "100_free-fnsummary",
+ "label": {"text": "100_free-fnsummary"}},
+ {"id": "101_static-var",
+ "label": {"text": "101_static-var"}},
+ {"id": "102_single-use",
+ "label": {"text": "102_single-use"}},
+ {"id": "103_comdats",
+ "label": {"text": "103_comdats"}}]},
+ {"id": "all_late_ipa_passes",
+ "label": {"text": "all_late_ipa_passes"},
+ "children": [{"id": "104_pta",
+ "label": {"text": "104_pta"}},
+ {"id": "105_simdclone",
+ "label": {"text": "105_simdclone"}}]},
+ {"id": "all_passes",
+ "label": {"text": "all_passes"},
+ "children": [{"id": "106_fixup_cfg",
+ "label": {"text": "106_fixup_cfg"}},
+ {"id": "107_ehdisp",
+ "label": {"text": "107_ehdisp"}},
+ {"id": "108_oaccloops",
+ "label": {"text": "108_oaccloops"}},
+ {"id": "109_omp_oacc_neuter_broadcast",
+ "label": {"text": "109_omp_oacc_neuter_broadcast"}},
+ {"id": "110_oaccdevlow",
+ "label": {"text": "110_oaccdevlow"}},
+ {"id": "111_ompdevlow",
+ "label": {"text": "111_ompdevlow"}},
+ {"id": "112_omptargetlink",
+ "label": {"text": "112_omptargetlink"}},
+ {"id": "113_adjust_alignment",
+ "label": {"text": "113_adjust_alignment"}},
+ {"id": "114_hardcfr",
+ "label": {"text": "114_hardcfr"}},
+ {"id": "*all_optimizations_0x101f2720",
+ "label": {"text": "*all_optimizations"}},
+ {"id": "*remove_cgraph_callee_edges_0x101f2780",
+ "label": {"text": "*remove_cgraph_callee_edges"}},
+ {"id": "*strip_predict_hints_0x101f27e0",
+ "label": {"text": "*strip_predict_hints"}},
+ {"id": "115_ccp",
+ "label": {"text": "115_ccp"}},
+ {"id": "116_objsz",
+ "label": {"text": "116_objsz"}},
+ {"id": "117_post_ipa_warn",
+ "label": {"text": "117_post_ipa_warn"}},
+ {"id": "118_waccess",
+ "label": {"text": "118_waccess"}},
+ {"id": "119_rebuild_frequencies",
+ "label": {"text": "119_rebuild_frequencies"}},
+ {"id": "120_cunrolli",
+ "label": {"text": "120_cunrolli"}},
+ {"id": "121_backprop",
+ "label": {"text": "121_backprop"}},
+ {"id": "122_phiprop",
+ "label": {"text": "122_phiprop"}},
+ {"id": "123_forwprop",
+ "label": {"text": "123_forwprop"}},
+ {"id": "124_alias",
+ "label": {"text": "124_alias"}},
+ {"id": "125_retslot",
+ "label": {"text": "125_retslot"}},
+ {"id": "126_fre",
+ "label": {"text": "126_fre"}},
+ {"id": "127_mergephi",
+ "label": {"text": "127_mergephi"}},
+ {"id": "128_threadfull",
+ "label": {"text": "128_threadfull"}},
+ {"id": "129_vrp",
+ "label": {"text": "129_vrp"}},
+ {"id": "130_bounds",
+ "label": {"text": "130_bounds"}},
+ {"id": "131_dse",
+ "label": {"text": "131_dse"}},
+ {"id": "132_dce",
+ "label": {"text": "132_dce"}},
+ {"id": "133_stdarg",
+ "label": {"text": "133_stdarg"}},
+ {"id": "134_cdce",
+ "label": {"text": "134_cdce"}},
+ {"id": "135_cselim",
+ "label": {"text": "135_cselim"}},
+ {"id": "136_copyprop",
+ "label": {"text": "136_copyprop"}},
+ {"id": "137_ifcombine",
+ "label": {"text": "137_ifcombine"}},
+ {"id": "138_mergephi",
+ "label": {"text": "138_mergephi"}},
+ {"id": "139_phiopt",
+ "label": {"text": "139_phiopt"}},
+ {"id": "140_tailr",
+ "label": {"text": "140_tailr"}},
+ {"id": "141_ch",
+ "label": {"text": "141_ch"}},
+ {"id": "142_cplxlower",
+ "label": {"text": "142_cplxlower"}},
+ {"id": "143_bitintlower",
+ "label": {"text": "143_bitintlower"}},
+ {"id": "144_sra",
+ "label": {"text": "144_sra"}},
+ {"id": "145_thread",
+ "label": {"text": "145_thread"}},
+ {"id": "146_dom",
+ "label": {"text": "146_dom"}},
+ {"id": "147_copyprop",
+ "label": {"text": "147_copyprop"}},
+ {"id": "148_isolate-paths",
+ "label": {"text": "148_isolate-paths"}},
+ {"id": "149_reassoc",
+ "label": {"text": "149_reassoc"}},
+ {"id": "150_dce",
+ "label": {"text": "150_dce"}},
+ {"id": "151_forwprop",
+ "label": {"text": "151_forwprop"}},
+ {"id": "152_phiopt",
+ "label": {"text": "152_phiopt"}},
+ {"id": "153_ccp",
+ "label": {"text": "153_ccp"}},
+ {"id": "154_pow",
+ "label": {"text": "154_pow"}},
+ {"id": "155_bswap",
+ "label": {"text": "155_bswap"}},
+ {"id": "156_laddress",
+ "label": {"text": "156_laddress"}},
+ {"id": "157_lim",
+ "label": {"text": "157_lim"}},
+ {"id": "158_walloca",
+ "label": {"text": "158_walloca"}},
+ {"id": "159_pre",
+ "label": {"text": "159_pre"}},
+ {"id": "160_sink",
+ "label": {"text": "160_sink"}},
+ {"id": "161_sancov",
+ "label": {"text": "161_sancov"}},
+ {"id": "162_asan",
+ "label": {"text": "162_asan"}},
+ {"id": "163_tsan",
+ "label": {"text": "163_tsan"}},
+ {"id": "164_dse",
+ "label": {"text": "164_dse"}},
+ {"id": "165_dce",
+ "label": {"text": "165_dce"}},
+ {"id": "166_fix_loops",
+ "label": {"text": "166_fix_loops"}},
+ {"id": "167_loop",
+ "label": {"text": "167_loop"}},
+ {"id": "168_loopinit",
+ "label": {"text": "168_loopinit"}},
+ {"id": "169_unswitch",
+ "label": {"text": "169_unswitch"}},
+ {"id": "170_lsplit",
+ "label": {"text": "170_lsplit"}},
+ {"id": "171_sccp",
+ "label": {"text": "171_sccp"}},
+ {"id": "172_lversion",
+ "label": {"text": "172_lversion"}},
+ {"id": "173_unrolljam",
+ "label": {"text": "173_unrolljam"}},
+ {"id": "174_cddce",
+ "label": {"text": "174_cddce"}},
+ {"id": "175_ivcanon",
+ "label": {"text": "175_ivcanon"}},
+ {"id": "176_ldist",
+ "label": {"text": "176_ldist"}},
+ {"id": "177_crc",
+ "label": {"text": "177_crc"}},
+ {"id": "178_linterchange",
+ "label": {"text": "178_linterchange"}},
+ {"id": "179_copyprop",
+ "label": {"text": "179_copyprop"}},
+ {"id": "180_graphite0",
+ "label": {"text": "180_graphite0"}},
+ {"id": "181_graphite",
+ "label": {"text": "181_graphite"}},
+ {"id": "182_lim",
+ "label": {"text": "182_lim"}},
+ {"id": "183_copyprop",
+ "label": {"text": "183_copyprop"}},
+ {"id": "184_dce",
+ "label": {"text": "184_dce"}},
+ {"id": "185_parloops",
+ "label": {"text": "185_parloops"}},
+ {"id": "186_ompexpssa",
+ "label": {"text": "186_ompexpssa"}},
+ {"id": "187_ch_vect",
+ "label": {"text": "187_ch_vect"}},
+ {"id": "188_ifcvt",
+ "label": {"text": "188_ifcvt"}},
+ {"id": "189_vect",
+ "label": {"text": "189_vect"}},
+ {"id": "190_dce",
+ "label": {"text": "190_dce"}},
+ {"id": "191_pcom",
+ "label": {"text": "191_pcom"}},
+ {"id": "192_cunroll",
+ "label": {"text": "192_cunroll"}},
+ {"id": "*pre_slp_scalar_cleanup_0x101f4880",
+ "label": {"text": "*pre_slp_scalar_cleanup"}},
+ {"id": "193_fre",
+ "label": {"text": "193_fre"}},
+ {"id": "194_dse",
+ "label": {"text": "194_dse"}},
+ {"id": "195_slp",
+ "label": {"text": "195_slp"}},
+ {"id": "196_aprefetch",
+ "label": {"text": "196_aprefetch"}},
+ {"id": "197_ivopts",
+ "label": {"text": "197_ivopts"}},
+ {"id": "198_lim",
+ "label": {"text": "198_lim"}},
+ {"id": "199_loopdone",
+ "label": {"text": "199_loopdone"}},
+ {"id": "200_no_loop",
+ "label": {"text": "200_no_loop"}},
+ {"id": "201_slp",
+ "label": {"text": "201_slp"}},
+ {"id": "202_simduid",
+ "label": {"text": "202_simduid"}},
+ {"id": "203_veclower2",
+ "label": {"text": "203_veclower2"}},
+ {"id": "204_switchlower",
+ "label": {"text": "204_switchlower"}},
+ {"id": "205_sincos",
+ "label": {"text": "205_sincos"}},
+ {"id": "206_recip",
+ "label": {"text": "206_recip"}},
+ {"id": "207_reassoc",
+ "label": {"text": "207_reassoc"}},
+ {"id": "208_slsr",
+ "label": {"text": "208_slsr"}},
+ {"id": "209_split-paths",
+ "label": {"text": "209_split-paths"}},
+ {"id": "210_tracer",
+ "label": {"text": "210_tracer"}},
+ {"id": "211_fre",
+ "label": {"text": "211_fre"}},
+ {"id": "212_thread",
+ "label": {"text": "212_thread"}},
+ {"id": "213_dom",
+ "label": {"text": "213_dom"}},
+ {"id": "214_strlen",
+ "label": {"text": "214_strlen"}},
+ {"id": "215_threadfull",
+ "label": {"text": "215_threadfull"}},
+ {"id": "216_vrp",
+ "label": {"text": "216_vrp"}},
+ {"id": "217_ccp",
+ "label": {"text": "217_ccp"}},
+ {"id": "218_wrestrict",
+ "label": {"text": "218_wrestrict"}},
+ {"id": "219_dse",
+ "label": {"text": "219_dse"}},
+ {"id": "220_dce",
+ "label": {"text": "220_dce"}},
+ {"id": "221_forwprop",
+ "label": {"text": "221_forwprop"}},
+ {"id": "222_sink",
+ "label": {"text": "222_sink"}},
+ {"id": "223_phiopt",
+ "label": {"text": "223_phiopt"}},
+ {"id": "224_fab",
+ "label": {"text": "224_fab"}},
+ {"id": "225_widening_mul",
+ "label": {"text": "225_widening_mul"}},
+ {"id": "226_store-merging",
+ "label": {"text": "226_store-merging"}},
+ {"id": "227_cddce",
+ "label": {"text": "227_cddce"}},
+ {"id": "228_sccopy",
+ "label": {"text": "228_sccopy"}},
+ {"id": "229_tailc",
+ "label": {"text": "229_tailc"}},
+ {"id": "230_crited",
+ "label": {"text": "230_crited"}},
+ {"id": "231_uninit",
+ "label": {"text": "231_uninit"}},
+ {"id": "232_local-pure-const",
+ "label": {"text": "232_local-pure-const"}},
+ {"id": "233_modref",
+ "label": {"text": "233_modref"}},
+ {"id": "234_uncprop",
+ "label": {"text": "234_uncprop"}},
+ {"id": "*all_optimizations_g_0x101f5af0",
+ "label": {"text": "*all_optimizations_g"}},
+ {"id": "*remove_cgraph_callee_edges_0x101f5b50",
+ "label": {"text": "*remove_cgraph_callee_edges"}},
+ {"id": "*strip_predict_hints_0x101f5bb0",
+ "label": {"text": "*strip_predict_hints"}},
+ {"id": "235_cplxlower",
+ "label": {"text": "235_cplxlower"}},
+ {"id": "236_bitintlower",
+ "label": {"text": "236_bitintlower"}},
+ {"id": "237_veclower2",
+ "label": {"text": "237_veclower2"}},
+ {"id": "238_switchlower",
+ "label": {"text": "238_switchlower"}},
+ {"id": "239_ccp",
+ "label": {"text": "239_ccp"}},
+ {"id": "240_post_ipa_warn",
+ "label": {"text": "240_post_ipa_warn"}},
+ {"id": "241_objsz",
+ "label": {"text": "241_objsz"}},
+ {"id": "242_fab",
+ "label": {"text": "242_fab"}},
+ {"id": "243_strlen",
+ "label": {"text": "243_strlen"}},
+ {"id": "244_copyprop",
+ "label": {"text": "244_copyprop"}},
+ {"id": "245_dce",
+ "label": {"text": "245_dce"}},
+ {"id": "246_rebuild_frequencies",
+ "label": {"text": "246_rebuild_frequencies"}},
+ {"id": "247_sancov",
+ "label": {"text": "247_sancov"}},
+ {"id": "248_asan",
+ "label": {"text": "248_asan"}},
+ {"id": "249_tsan",
+ "label": {"text": "249_tsan"}},
+ {"id": "250_crited",
+ "label": {"text": "250_crited"}},
+ {"id": "251_uninit",
+ "label": {"text": "251_uninit"}},
+ {"id": "252_uncprop",
+ "label": {"text": "252_uncprop"}},
+ {"id": "253_assumptions",
+ "label": {"text": "253_assumptions"}},
+ {"id": "*tminit_0x101f6370",
+ "label": {"text": "*tminit"}},
+ {"id": "254_tmmark",
+ "label": {"text": "254_tmmark"}},
+ {"id": "255_tmmemopt",
+ "label": {"text": "255_tmmemopt"}},
+ {"id": "256_tmedge",
+ "label": {"text": "256_tmedge"}},
+ {"id": "257_simduid",
+ "label": {"text": "257_simduid"}},
+ {"id": "258_vtable-verify",
+ "label": {"text": "258_vtable-verify"}},
+ {"id": "259_lower_vaarg",
+ "label": {"text": "259_lower_vaarg"}},
+ {"id": "260_veclower",
+ "label": {"text": "260_veclower"}},
+ {"id": "261_cplxlower0",
+ "label": {"text": "261_cplxlower0"}},
+ {"id": "262_bitintlower0",
+ "label": {"text": "262_bitintlower0"}},
+ {"id": "263_sancov_O0",
+ "label": {"text": "263_sancov_O0"}},
+ {"id": "264_switchlower_O0",
+ "label": {"text": "264_switchlower_O0"}},
+ {"id": "265_asan0",
+ "label": {"text": "265_asan0"}},
+ {"id": "266_tsan0",
+ "label": {"text": "266_tsan0"}},
+ {"id": "267_musttail",
+ "label": {"text": "267_musttail"}},
+ {"id": "268_sanopt",
+ "label": {"text": "268_sanopt"}},
+ {"id": "269_ehcleanup",
+ "label": {"text": "269_ehcleanup"}},
+ {"id": "270_resx",
+ "label": {"text": "270_resx"}},
+ {"id": "271_nrv",
+ "label": {"text": "271_nrv"}},
+ {"id": "272_isel",
+ "label": {"text": "272_isel"}},
+ {"id": "273_hardcbr",
+ "label": {"text": "273_hardcbr"}},
+ {"id": "274_hardcmp",
+ "label": {"text": "274_hardcmp"}},
+ {"id": "275_waccess",
+ "label": {"text": "275_waccess"}},
+ {"id": "276_optimized",
+ "label": {"text": "276_optimized"}},
+ {"id": "*warn_function_noreturn_0x101f6dd0",
+ "label": {"text": "*warn_function_noreturn"}},
+ {"id": "277_expand",
+ "label": {"text": "277_expand"}},
+ {"id": "*rest_of_compilation_0x101f6e90",
+ "label": {"text": "*rest_of_compilation"}},
+ {"id": "278_vregs",
+ "label": {"text": "278_vregs"}},
+ {"id": "279_into_cfglayout",
+ "label": {"text": "279_into_cfglayout"}},
+ {"id": "280_jump",
+ "label": {"text": "280_jump"}},
+ {"id": "281_subreg1",
+ "label": {"text": "281_subreg1"}},
+ {"id": "282_dfinit",
+ "label": {"text": "282_dfinit"}},
+ {"id": "283_cse1",
+ "label": {"text": "283_cse1"}},
+ {"id": "284_fwprop1",
+ "label": {"text": "284_fwprop1"}},
+ {"id": "285_cprop",
+ "label": {"text": "285_cprop"}},
+ {"id": "286_rtl pre",
+ "label": {"text": "286_rtl pre"}},
+ {"id": "287_hoist",
+ "label": {"text": "287_hoist"}},
+ {"id": "288_hardreg_pre",
+ "label": {"text": "288_hardreg_pre"}},
+ {"id": "289_cprop",
+ "label": {"text": "289_cprop"}},
+ {"id": "290_store_motion",
+ "label": {"text": "290_store_motion"}},
+ {"id": "291_cse_local",
+ "label": {"text": "291_cse_local"}},
+ {"id": "292_ce1",
+ "label": {"text": "292_ce1"}},
+ {"id": "293_apx_nfcvt",
+ "label": {"text": "293_apx_nfcvt"}},
+ {"id": "294_reginfo",
+ "label": {"text": "294_reginfo"}},
+ {"id": "295_loop2",
+ "label": {"text": "295_loop2"}},
+ {"id": "296_loop2_init",
+ "label": {"text": "296_loop2_init"}},
+ {"id": "297_loop2_invariant",
+ "label": {"text": "297_loop2_invariant"}},
+ {"id": "298_loop2_unroll",
+ "label": {"text": "298_loop2_unroll"}},
+ {"id": "299_loop2_doloop",
+ "label": {"text": "299_loop2_doloop"}},
+ {"id": "300_loop2_done",
+ "label": {"text": "300_loop2_done"}},
+ {"id": "301_subreg2",
+ "label": {"text": "301_subreg2"}},
+ {"id": "302_web",
+ "label": {"text": "302_web"}},
+ {"id": "303_cprop",
+ "label": {"text": "303_cprop"}},
+ {"id": "304_stv",
+ "label": {"text": "304_stv"}},
+ {"id": "305_cse2",
+ "label": {"text": "305_cse2"}},
+ {"id": "306_dse1",
+ "label": {"text": "306_dse1"}},
+ {"id": "307_fwprop2",
+ "label": {"text": "307_fwprop2"}},
+ {"id": "308_auto_inc_dec",
+ "label": {"text": "308_auto_inc_dec"}},
+ {"id": "309_init-regs",
+ "label": {"text": "309_init-regs"}},
+ {"id": "310_ud_dce",
+ "label": {"text": "310_ud_dce"}},
+ {"id": "311_ext_dce",
+ "label": {"text": "311_ext_dce"}},
+ {"id": "312_combine",
+ "label": {"text": "312_combine"}},
+ {"id": "313_late_combine",
+ "label": {"text": "313_late_combine"}},
+ {"id": "314_rpad",
+ "label": {"text": "314_rpad"}},
+ {"id": "315_rrvl",
+ "label": {"text": "315_rrvl"}},
+ {"id": "316_stv",
+ "label": {"text": "316_stv"}},
+ {"id": "317_ce2",
+ "label": {"text": "317_ce2"}},
+ {"id": "318_jump_after_combine",
+ "label": {"text": "318_jump_after_combine"}},
+ {"id": "319_bbpart",
+ "label": {"text": "319_bbpart"}},
+ {"id": "320_outof_cfglayout",
+ "label": {"text": "320_outof_cfglayout"}},
+ {"id": "321_split1",
+ "label": {"text": "321_split1"}},
+ {"id": "322_subreg3",
+ "label": {"text": "322_subreg3"}},
+ {"id": "323_no-opt dfinit",
+ "label": {"text": "323_no-opt dfinit"}},
+ {"id": "*stack_ptr_mod_0x101f8050",
+ "label": {"text": "*stack_ptr_mod"}},
+ {"id": "324_mode_sw",
+ "label": {"text": "324_mode_sw"}},
+ {"id": "325_asmcons",
+ "label": {"text": "325_asmcons"}},
+ {"id": "326_sms",
+ "label": {"text": "326_sms"}},
+ {"id": "327_lr_shrinkage",
+ "label": {"text": "327_lr_shrinkage"}},
+ {"id": "328_sched1",
+ "label": {"text": "328_sched1"}},
+ {"id": "329_avoid_store_forwarding",
+ "label": {"text": "329_avoid_store_forwarding"}},
+ {"id": "330_early_remat",
+ "label": {"text": "330_early_remat"}},
+ {"id": "331_ira",
+ "label": {"text": "331_ira"}},
+ {"id": "332_reload",
+ "label": {"text": "332_reload"}},
+ {"id": "*all-postreload_0x101f8410",
+ "label": {"text": "*all-postreload"}},
+ {"id": "333_postreload",
+ "label": {"text": "333_postreload"}},
+ {"id": "334_vzeroupper",
+ "label": {"text": "334_vzeroupper"}},
+ {"id": "335_late_combine",
+ "label": {"text": "335_late_combine"}},
+ {"id": "336_gcse2",
+ "label": {"text": "336_gcse2"}},
+ {"id": "337_split2",
+ "label": {"text": "337_split2"}},
+ {"id": "338_ree",
+ "label": {"text": "338_ree"}},
+ {"id": "339_cmpelim",
+ "label": {"text": "339_cmpelim"}},
+ {"id": "340_pro_and_epilogue",
+ "label": {"text": "340_pro_and_epilogue"}},
+ {"id": "341_dse2",
+ "label": {"text": "341_dse2"}},
+ {"id": "342_csa",
+ "label": {"text": "342_csa"}},
+ {"id": "343_jump2",
+ "label": {"text": "343_jump2"}},
+ {"id": "344_compgotos",
+ "label": {"text": "344_compgotos"}},
+ {"id": "345_sched_fusion",
+ "label": {"text": "345_sched_fusion"}},
+ {"id": "346_peephole2",
+ "label": {"text": "346_peephole2"}},
+ {"id": "347_ce3",
+ "label": {"text": "347_ce3"}},
+ {"id": "348_rnreg",
+ "label": {"text": "348_rnreg"}},
+ {"id": "349_fold_mem_offsets",
+ "label": {"text": "349_fold_mem_offsets"}},
+ {"id": "350_cprop_hardreg",
+ "label": {"text": "350_cprop_hardreg"}},
+ {"id": "351_rtl_dce",
+ "label": {"text": "351_rtl_dce"}},
+ {"id": "352_bbro",
+ "label": {"text": "352_bbro"}},
+ {"id": "*leaf_regs_0x101f8bf0",
+ "label": {"text": "*leaf_regs"}},
+ {"id": "353_split3",
+ "label": {"text": "353_split3"}},
+ {"id": "354_sched2",
+ "label": {"text": "354_sched2"}},
+ {"id": "*stack_regs_0x101f8d10",
+ "label": {"text": "*stack_regs"}},
+ {"id": "355_split4",
+ "label": {"text": "355_split4"}},
+ {"id": "356_stack",
+ "label": {"text": "356_stack"}},
+ {"id": "357_late_pro_and_epilogue",
+ "label": {"text": "357_late_pro_and_epilogue"}},
+ {"id": "*all-late_compilation_0x101f8e90",
+ "label": {"text": "*all-late_compilation"}},
+ {"id": "358_zero_call_used_regs",
+ "label": {"text": "358_zero_call_used_regs"}},
+ {"id": "359_alignments",
+ "label": {"text": "359_alignments"}},
+ {"id": "360_vartrack",
+ "label": {"text": "360_vartrack"}},
+ {"id": "*free_cfg_0x101f9010",
+ "label": {"text": "*free_cfg"}},
+ {"id": "361_mach",
+ "label": {"text": "361_mach"}},
+ {"id": "362_barriers",
+ "label": {"text": "362_barriers"}},
+ {"id": "363_dbr",
+ "label": {"text": "363_dbr"}},
+ {"id": "364_split5",
+ "label": {"text": "364_split5"}},
+ {"id": "365_eh_ranges",
+ "label": {"text": "365_eh_ranges"}},
+ {"id": "366_endbr_and_patchable_area",
+ "label": {"text": "366_endbr_and_patchable_area"}},
+ {"id": "367_align_tight_loops",
+ "label": {"text": "367_align_tight_loops"}},
+ {"id": "368_shorten",
+ "label": {"text": "368_shorten"}},
+ {"id": "369_nothrow",
+ "label": {"text": "369_nothrow"}},
+ {"id": "370_dwarf2",
+ "label": {"text": "370_dwarf2"}},
+ {"id": "371_final",
+ "label": {"text": "371_final"}},
+ {"id": "372_dfinish",
+ "label": {"text": "372_dfinish"}},
+ {"id": "*clean_state_0x101f9500",
+ "label": {"text": "*clean_state"}}]}],
+ "edges": [{"id": "edge0",
+ "label": {"text": "next"},
+ "sourceNodeId": "22_ompexp",
+ "targetNodeId": "*build_cgraph_edges_0x101ef910"},
+ {"id": "edge1",
+ "label": {"text": "next"},
+ "sourceNodeId": "21_coro-early-expand-ifns",
+ "targetNodeId": "22_ompexp"},
+ {"id": "edge2",
+ "label": {"text": "next"},
+ "sourceNodeId": "*warn_function_return_0x101ef7f0",
+ "targetNodeId": "21_coro-early-expand-ifns"},
+ {"id": "edge3",
+ "label": {"text": "next"},
+ "sourceNodeId": "20_cfg",
+ "targetNodeId": "*warn_function_return_0x101ef7f0"},
+ {"id": "edge4",
+ "label": {"text": "next"},
+ "sourceNodeId": "19_coro-lower-builtins",
+ "targetNodeId": "20_cfg"},
+ {"id": "edge5",
+ "label": {"text": "next"},
+ "sourceNodeId": "18_eh",
+ "targetNodeId": "19_coro-lower-builtins"},
+ {"id": "edge6",
+ "label": {"text": "next"},
+ "sourceNodeId": "17_ehopt",
+ "targetNodeId": "18_eh"},
+ {"id": "edge7",
+ "label": {"text": "next"},
+ "sourceNodeId": "16_tmlower",
+ "targetNodeId": "17_ehopt"},
+ {"id": "edge8",
+ "label": {"text": "next"},
+ "sourceNodeId": "15_lower",
+ "targetNodeId": "16_tmlower"},
+ {"id": "edge9",
+ "label": {"text": "next"},
+ "sourceNodeId": "14_omplower",
+ "targetNodeId": "15_lower"},
+ {"id": "edge10",
+ "label": {"text": "next"},
+ "sourceNodeId": "13_omp_oacc_kernels_decompose",
+ "targetNodeId": "14_omplower"},
+ {"id": "edge11",
+ "label": {"text": "next"},
+ "sourceNodeId": "*diagnose_tm_blocks_0x101ef490",
+ "targetNodeId": "13_omp_oacc_kernels_decompose"},
+ {"id": "edge12",
+ "label": {"text": "next"},
+ "sourceNodeId": "*diagnose_omp_blocks_0x101ef430",
+ "targetNodeId": "*diagnose_tm_blocks_0x101ef490"},
+ {"id": "edge13",
+ "label": {"text": "next"},
+ "sourceNodeId": "*warn_unused_result_0x101ef3d0",
+ "targetNodeId": "*diagnose_omp_blocks_0x101ef430"},
+ {"id": "edge14",
+ "label": {"text": "next"},
+ "sourceNodeId": "34_nothrow",
+ "targetNodeId": "*rebuild_cgraph_edges_0x101f0020"},
+ {"id": "edge15",
+ "label": {"text": "next"},
+ "sourceNodeId": "33_ubsan",
+ "targetNodeId": "34_nothrow"},
+ {"id": "edge16",
+ "label": {"text": "next"},
+ "sourceNodeId": "32_waccess",
+ "targetNodeId": "33_ubsan"},
+ {"id": "edge17",
+ "label": {"text": "next"},
+ "sourceNodeId": "31_early_uninit",
+ "targetNodeId": "32_waccess"},
+ {"id": "edge18",
+ "label": {"text": "next"},
+ "sourceNodeId": "*nonnullcmp_0x101efce0",
+ "targetNodeId": "31_early_uninit"},
+ {"id": "edge19",
+ "label": {"text": "next"},
+ "sourceNodeId": "30_warn-printf",
+ "targetNodeId": "*nonnullcmp_0x101efce0"},
+ {"id": "edge20",
+ "label": {"text": "next"},
+ "sourceNodeId": "29_walloca",
+ "targetNodeId": "30_warn-printf"},
+ {"id": "edge21",
+ "label": {"text": "next"},
+ "sourceNodeId": "376_test_graph_emission",
+ "targetNodeId": "29_walloca"},
+ {"id": "edge22",
+ "label": {"text": "next"},
+ "sourceNodeId": "28_ssa",
+ "targetNodeId": "376_test_graph_emission"},
+ {"id": "edge23",
+ "label": {"text": "next"},
+ "sourceNodeId": "27_fixup_cfg",
+ "targetNodeId": "28_ssa"},
+ {"id": "edge24",
+ "label": {"text": "sub"},
+ "sourceNodeId": "26_build_ssa_passes",
+ "targetNodeId": "27_fixup_cfg"},
+ {"id": "edge25",
+ "label": {"text": "next"},
+ "sourceNodeId": "61_fnsplit",
+ "targetNodeId": "*strip_predict_hints_0x101f0c60"},
+ {"id": "edge26",
+ "label": {"text": "next"},
+ "sourceNodeId": "60_modref",
+ "targetNodeId": "61_fnsplit"},
+ {"id": "edge27",
+ "label": {"text": "next"},
+ "sourceNodeId": "59_local-pure-const",
+ "targetNodeId": "60_modref"},
+ {"id": "edge28",
+ "label": {"text": "next"},
+ "sourceNodeId": "58_profile_estimate",
+ "targetNodeId": "59_local-pure-const"},
+ {"id": "edge29",
+ "label": {"text": "next"},
+ "sourceNodeId": "57_sccopy",
+ "targetNodeId": "58_profile_estimate"},
+ {"id": "edge30",
+ "label": {"text": "next"},
+ "sourceNodeId": "56_ehcleanup",
+ "targetNodeId": "57_sccopy"},
+ {"id": "edge31",
+ "label": {"text": "next"},
+ "sourceNodeId": "55_switchconv",
+ "targetNodeId": "56_ehcleanup"},
+ {"id": "edge32",
+ "label": {"text": "next"},
+ "sourceNodeId": "54_iftoswitch",
+ "targetNodeId": "55_switchconv"},
+ {"id": "edge33",
+ "label": {"text": "next"},
+ "sourceNodeId": "53_tailr",
+ "targetNodeId": "54_iftoswitch"},
+ {"id": "edge34",
+ "label": {"text": "next"},
+ "sourceNodeId": "52_phiopt",
+ "targetNodeId": "53_tailr"},
+ {"id": "edge35",
+ "label": {"text": "next"},
+ "sourceNodeId": "51_cddce",
+ "targetNodeId": "52_phiopt"},
+ {"id": "edge36",
+ "label": {"text": "next"},
+ "sourceNodeId": "50_dse",
+ "targetNodeId": "51_cddce"},
+ {"id": "edge37",
+ "label": {"text": "next"},
+ "sourceNodeId": "49_mergephi",
+ "targetNodeId": "50_dse"},
+ {"id": "edge38",
+ "label": {"text": "next"},
+ "sourceNodeId": "48_evrp",
+ "targetNodeId": "49_mergephi"},
+ {"id": "edge39",
+ "label": {"text": "next"},
+ "sourceNodeId": "47_fre",
+ "targetNodeId": "48_evrp"},
+ {"id": "edge40",
+ "label": {"text": "next"},
+ "sourceNodeId": "46_phiprop",
+ "targetNodeId": "47_fre"},
+ {"id": "edge41",
+ "label": {"text": "next"},
+ "sourceNodeId": "45_ealias",
+ "targetNodeId": "46_phiprop"},
+ {"id": "edge42",
+ "label": {"text": "next"},
+ "sourceNodeId": "44_esra",
+ "targetNodeId": "45_ealias"},
+ {"id": "edge43",
+ "label": {"text": "next"},
+ "sourceNodeId": "43_ethread",
+ "targetNodeId": "44_esra"},
+ {"id": "edge44",
+ "label": {"text": "next"},
+ "sourceNodeId": "42_forwprop",
+ "targetNodeId": "43_ethread"},
+ {"id": "edge45",
+ "label": {"text": "next"},
+ "sourceNodeId": "41_ccp",
+ "targetNodeId": "42_forwprop"},
+ {"id": "edge46",
+ "label": {"text": "next"},
+ "sourceNodeId": "40_early_objsz",
+ "targetNodeId": "41_ccp"},
+ {"id": "edge47",
+ "label": {"text": "next"},
+ "sourceNodeId": "*remove_cgraph_callee_edges_0x101f0340",
+ "targetNodeId": "40_early_objsz"},
+ {"id": "edge48",
+ "label": {"text": "sub"},
+ "sourceNodeId": "39_early_optimizations",
+ "targetNodeId": "*remove_cgraph_callee_edges_0x101f0340"},
+ {"id": "edge49",
+ "label": {"text": "next"},
+ "sourceNodeId": "*rebuild_cgraph_edges_0x101f0d30",
+ "targetNodeId": "63_local-fnsummary"},
+ {"id": "edge50",
+ "label": {"text": "next"},
+ "sourceNodeId": "62_release_ssa",
+ "targetNodeId": "*rebuild_cgraph_edges_0x101f0d30"},
+ {"id": "edge51",
+ "label": {"text": "next"},
+ "sourceNodeId": "39_early_optimizations",
+ "targetNodeId": "62_release_ssa"},
+ {"id": "edge52",
+ "label": {"text": "next"},
+ "sourceNodeId": "*infinite-recursion_0x101f0260",
+ "targetNodeId": "39_early_optimizations"},
+ {"id": "edge53",
+ "label": {"text": "next"},
+ "sourceNodeId": "38_einline",
+ "targetNodeId": "*infinite-recursion_0x101f0260"},
+ {"id": "edge54",
+ "label": {"text": "next"},
+ "sourceNodeId": "37_local-fnsummary",
+ "targetNodeId": "38_einline"},
+ {"id": "edge55",
+ "label": {"text": "next"},
+ "sourceNodeId": "*rebuild_cgraph_edges_0x101f0140",
+ "targetNodeId": "37_local-fnsummary"},
+ {"id": "edge56",
+ "label": {"text": "next"},
+ "sourceNodeId": "36_fixup_cfg",
+ "targetNodeId": "*rebuild_cgraph_edges_0x101f0140"},
+ {"id": "edge57",
+ "label": {"text": "sub"},
+ "sourceNodeId": "35_opt_local_passes",
+ "targetNodeId": "36_fixup_cfg"},
+ {"id": "edge58",
+ "label": {"text": "next"},
+ "sourceNodeId": "76_ompexpssa",
+ "targetNodeId": "*rebuild_cgraph_edges_0x101f1310"},
+ {"id": "edge59",
+ "label": {"text": "next"},
+ "sourceNodeId": "75_parloops",
+ "targetNodeId": "76_ompexpssa"},
+ {"id": "edge60",
+ "label": {"text": "next"},
+ "sourceNodeId": "74_dce",
+ "targetNodeId": "75_parloops"},
+ {"id": "edge61",
+ "label": {"text": "next"},
+ "sourceNodeId": "73_dom",
+ "targetNodeId": "74_dce"},
+ {"id": "edge62",
+ "label": {"text": "next"},
+ "sourceNodeId": "72_lim",
+ "targetNodeId": "73_dom"},
+ {"id": "edge63",
+ "label": {"text": "next"},
+ "sourceNodeId": "71_fre",
+ "targetNodeId": "72_lim"},
+ {"id": "edge64",
+ "label": {"text": "next"},
+ "sourceNodeId": "70_ch",
+ "targetNodeId": "71_fre"},
+ {"id": "edge65",
+ "label": {"text": "sub"},
+ "sourceNodeId": "69_oacc_kernels",
+ "targetNodeId": "70_ch"},
+ {"id": "edge66",
+ "label": {"text": "sub"},
+ "sourceNodeId": "68_ipa_oacc_kernels",
+ "targetNodeId": "69_oacc_kernels"},
+ {"id": "edge67",
+ "label": {"text": "next"},
+ "sourceNodeId": "67_pta",
+ "targetNodeId": "68_ipa_oacc_kernels"},
+ {"id": "edge68",
+ "label": {"text": "sub"},
+ "sourceNodeId": "66_ipa_oacc",
+ "targetNodeId": "67_pta"},
+ {"id": "edge69",
+ "label": {"text": "sub"},
+ "sourceNodeId": "78_afdo",
+ "targetNodeId": "79_feedback_fnsplit"},
+ {"id": "edge70",
+ "label": {"text": "sub"},
+ "sourceNodeId": "80_profile",
+ "targetNodeId": "81_feedback_fnsplit"},
+ {"id": "edge71",
+ "label": {"text": "next"},
+ "sourceNodeId": "84_tmipa",
+ "targetNodeId": "85_emutls"},
+ {"id": "edge72",
+ "label": {"text": "next"},
+ "sourceNodeId": "83_increase_alignment",
+ "targetNodeId": "84_tmipa"},
+ {"id": "edge73",
+ "label": {"text": "next"},
+ "sourceNodeId": "82_free-fnsummary",
+ "targetNodeId": "83_increase_alignment"},
+ {"id": "edge74",
+ "label": {"text": "next"},
+ "sourceNodeId": "80_profile",
+ "targetNodeId": "82_free-fnsummary"},
+ {"id": "edge75",
+ "label": {"text": "next"},
+ "sourceNodeId": "78_afdo",
+ "targetNodeId": "80_profile"},
+ {"id": "edge76",
+ "label": {"text": "next"},
+ "sourceNodeId": "77_targetclone",
+ "targetNodeId": "78_afdo"},
+ {"id": "edge77",
+ "label": {"text": "next"},
+ "sourceNodeId": "66_ipa_oacc",
+ "targetNodeId": "77_targetclone"},
+ {"id": "edge78",
+ "label": {"text": "next"},
+ "sourceNodeId": "65_strub",
+ "targetNodeId": "66_ipa_oacc"},
+ {"id": "edge79",
+ "label": {"text": "next"},
+ "sourceNodeId": "64_remove_symbols",
+ "targetNodeId": "65_strub"},
+ {"id": "edge80",
+ "label": {"text": "next"},
+ "sourceNodeId": "35_opt_local_passes",
+ "targetNodeId": "64_remove_symbols"},
+ {"id": "edge81",
+ "label": {"text": "next"},
+ "sourceNodeId": "26_build_ssa_passes",
+ "targetNodeId": "35_opt_local_passes"},
+ {"id": "edge82",
+ "label": {"text": "next"},
+ "sourceNodeId": "25_strubm",
+ "targetNodeId": "26_build_ssa_passes"},
+ {"id": "edge83",
+ "label": {"text": "next"},
+ "sourceNodeId": "24_visibility",
+ "targetNodeId": "25_strubm"},
+ {"id": "edge84",
+ "label": {"text": "next"},
+ "sourceNodeId": "*free_lang_data_0x101ef9d0",
+ "targetNodeId": "24_visibility"},
+ {"id": "edge85",
+ "label": {"text": "next"},
+ "sourceNodeId": "23_afdo_offline",
+ "targetNodeId": "*free_lang_data_0x101ef9d0"},
+ {"id": "edge86",
+ "label": {"text": "next"},
+ "sourceNodeId": "102_single-use",
+ "targetNodeId": "103_comdats"},
+ {"id": "edge87",
+ "label": {"text": "next"},
+ "sourceNodeId": "101_static-var",
+ "targetNodeId": "102_single-use"},
+ {"id": "edge88",
+ "label": {"text": "next"},
+ "sourceNodeId": "100_free-fnsummary",
+ "targetNodeId": "101_static-var"},
+ {"id": "edge89",
+ "label": {"text": "next"},
+ "sourceNodeId": "99_modref",
+ "targetNodeId": "100_free-fnsummary"},
+ {"id": "edge90",
+ "label": {"text": "next"},
+ "sourceNodeId": "98_pure-const",
+ "targetNodeId": "99_modref"},
+ {"id": "edge91",
+ "label": {"text": "next"},
+ "sourceNodeId": "97_locality-clone",
+ "targetNodeId": "98_pure-const"},
+ {"id": "edge92",
+ "label": {"text": "next"},
+ "sourceNodeId": "96_inline",
+ "targetNodeId": "97_locality-clone"},
+ {"id": "edge93",
+ "label": {"text": "next"},
+ "sourceNodeId": "95_fnsummary",
+ "targetNodeId": "96_inline"},
+ {"id": "edge94",
+ "label": {"text": "next"},
+ "sourceNodeId": "94_sra",
+ "targetNodeId": "95_fnsummary"},
+ {"id": "edge95",
+ "label": {"text": "next"},
+ "sourceNodeId": "93_cp",
+ "targetNodeId": "94_sra"},
+ {"id": "edge96",
+ "label": {"text": "next"},
+ "sourceNodeId": "92_cdtor",
+ "targetNodeId": "93_cp"},
+ {"id": "edge97",
+ "label": {"text": "next"},
+ "sourceNodeId": "91_devirt",
+ "targetNodeId": "92_cdtor"},
+ {"id": "edge98",
+ "label": {"text": "next"},
+ "sourceNodeId": "90_icf",
+ "targetNodeId": "91_devirt"},
+ {"id": "edge99",
+ "label": {"text": "next"},
+ "sourceNodeId": "89_profile_estimate",
+ "targetNodeId": "90_icf"},
+ {"id": "edge100",
+ "label": {"text": "next"},
+ "sourceNodeId": "88_whole-program",
+ "targetNodeId": "89_profile_estimate"},
+ {"id": "edge101",
+ "label": {"text": "next"},
+ "sourceNodeId": "87_odr",
+ "targetNodeId": "88_whole-program"},
+ {"id": "edge102",
+ "label": {"text": "next"},
+ "sourceNodeId": "86_analyzer",
+ "targetNodeId": "87_odr"},
+ {"id": "edge103",
+ "label": {"text": "next"},
+ "sourceNodeId": "104_pta",
+ "targetNodeId": "105_simdclone"},
+ {"id": "edge104",
+ "label": {"text": "next"},
+ "sourceNodeId": "183_copyprop",
+ "targetNodeId": "184_dce"},
+ {"id": "edge105",
+ "label": {"text": "next"},
+ "sourceNodeId": "182_lim",
+ "targetNodeId": "183_copyprop"},
+ {"id": "edge106",
+ "label": {"text": "next"},
+ "sourceNodeId": "181_graphite",
+ "targetNodeId": "182_lim"},
+ {"id": "edge107",
+ "label": {"text": "sub"},
+ "sourceNodeId": "180_graphite0",
+ "targetNodeId": "181_graphite"},
+ {"id": "edge108",
+ "label": {"text": "sub"},
+ "sourceNodeId": "189_vect",
+ "targetNodeId": "190_dce"},
+ {"id": "edge109",
+ "label": {"text": "next"},
+ "sourceNodeId": "193_fre",
+ "targetNodeId": "194_dse"},
+ {"id": "edge110",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*pre_slp_scalar_cleanup_0x101f4880",
+ "targetNodeId": "193_fre"},
+ {"id": "edge111",
+ "label": {"text": "next"},
+ "sourceNodeId": "198_lim",
+ "targetNodeId": "199_loopdone"},
+ {"id": "edge112",
+ "label": {"text": "next"},
+ "sourceNodeId": "197_ivopts",
+ "targetNodeId": "198_lim"},
+ {"id": "edge113",
+ "label": {"text": "next"},
+ "sourceNodeId": "196_aprefetch",
+ "targetNodeId": "197_ivopts"},
+ {"id": "edge114",
+ "label": {"text": "next"},
+ "sourceNodeId": "195_slp",
+ "targetNodeId": "196_aprefetch"},
+ {"id": "edge115",
+ "label": {"text": "next"},
+ "sourceNodeId": "*pre_slp_scalar_cleanup_0x101f4880",
+ "targetNodeId": "195_slp"},
+ {"id": "edge116",
+ "label": {"text": "next"},
+ "sourceNodeId": "192_cunroll",
+ "targetNodeId": "*pre_slp_scalar_cleanup_0x101f4880"},
+ {"id": "edge117",
+ "label": {"text": "next"},
+ "sourceNodeId": "191_pcom",
+ "targetNodeId": "192_cunroll"},
+ {"id": "edge118",
+ "label": {"text": "next"},
+ "sourceNodeId": "189_vect",
+ "targetNodeId": "191_pcom"},
+ {"id": "edge119",
+ "label": {"text": "next"},
+ "sourceNodeId": "188_ifcvt",
+ "targetNodeId": "189_vect"},
+ {"id": "edge120",
+ "label": {"text": "next"},
+ "sourceNodeId": "187_ch_vect",
+ "targetNodeId": "188_ifcvt"},
+ {"id": "edge121",
+ "label": {"text": "next"},
+ "sourceNodeId": "186_ompexpssa",
+ "targetNodeId": "187_ch_vect"},
+ {"id": "edge122",
+ "label": {"text": "next"},
+ "sourceNodeId": "185_parloops",
+ "targetNodeId": "186_ompexpssa"},
+ {"id": "edge123",
+ "label": {"text": "next"},
+ "sourceNodeId": "180_graphite0",
+ "targetNodeId": "185_parloops"},
+ {"id": "edge124",
+ "label": {"text": "next"},
+ "sourceNodeId": "179_copyprop",
+ "targetNodeId": "180_graphite0"},
+ {"id": "edge125",
+ "label": {"text": "next"},
+ "sourceNodeId": "178_linterchange",
+ "targetNodeId": "179_copyprop"},
+ {"id": "edge126",
+ "label": {"text": "next"},
+ "sourceNodeId": "177_crc",
+ "targetNodeId": "178_linterchange"},
+ {"id": "edge127",
+ "label": {"text": "next"},
+ "sourceNodeId": "176_ldist",
+ "targetNodeId": "177_crc"},
+ {"id": "edge128",
+ "label": {"text": "next"},
+ "sourceNodeId": "175_ivcanon",
+ "targetNodeId": "176_ldist"},
+ {"id": "edge129",
+ "label": {"text": "next"},
+ "sourceNodeId": "174_cddce",
+ "targetNodeId": "175_ivcanon"},
+ {"id": "edge130",
+ "label": {"text": "next"},
+ "sourceNodeId": "173_unrolljam",
+ "targetNodeId": "174_cddce"},
+ {"id": "edge131",
+ "label": {"text": "next"},
+ "sourceNodeId": "172_lversion",
+ "targetNodeId": "173_unrolljam"},
+ {"id": "edge132",
+ "label": {"text": "next"},
+ "sourceNodeId": "171_sccp",
+ "targetNodeId": "172_lversion"},
+ {"id": "edge133",
+ "label": {"text": "next"},
+ "sourceNodeId": "170_lsplit",
+ "targetNodeId": "171_sccp"},
+ {"id": "edge134",
+ "label": {"text": "next"},
+ "sourceNodeId": "169_unswitch",
+ "targetNodeId": "170_lsplit"},
+ {"id": "edge135",
+ "label": {"text": "next"},
+ "sourceNodeId": "168_loopinit",
+ "targetNodeId": "169_unswitch"},
+ {"id": "edge136",
+ "label": {"text": "sub"},
+ "sourceNodeId": "167_loop",
+ "targetNodeId": "168_loopinit"},
+ {"id": "edge137",
+ "label": {"text": "sub"},
+ "sourceNodeId": "200_no_loop",
+ "targetNodeId": "201_slp"},
+ {"id": "edge138",
+ "label": {"text": "next"},
+ "sourceNodeId": "233_modref",
+ "targetNodeId": "234_uncprop"},
+ {"id": "edge139",
+ "label": {"text": "next"},
+ "sourceNodeId": "232_local-pure-const",
+ "targetNodeId": "233_modref"},
+ {"id": "edge140",
+ "label": {"text": "next"},
+ "sourceNodeId": "231_uninit",
+ "targetNodeId": "232_local-pure-const"},
+ {"id": "edge141",
+ "label": {"text": "next"},
+ "sourceNodeId": "230_crited",
+ "targetNodeId": "231_uninit"},
+ {"id": "edge142",
+ "label": {"text": "next"},
+ "sourceNodeId": "229_tailc",
+ "targetNodeId": "230_crited"},
+ {"id": "edge143",
+ "label": {"text": "next"},
+ "sourceNodeId": "228_sccopy",
+ "targetNodeId": "229_tailc"},
+ {"id": "edge144",
+ "label": {"text": "next"},
+ "sourceNodeId": "227_cddce",
+ "targetNodeId": "228_sccopy"},
+ {"id": "edge145",
+ "label": {"text": "next"},
+ "sourceNodeId": "226_store-merging",
+ "targetNodeId": "227_cddce"},
+ {"id": "edge146",
+ "label": {"text": "next"},
+ "sourceNodeId": "225_widening_mul",
+ "targetNodeId": "226_store-merging"},
+ {"id": "edge147",
+ "label": {"text": "next"},
+ "sourceNodeId": "224_fab",
+ "targetNodeId": "225_widening_mul"},
+ {"id": "edge148",
+ "label": {"text": "next"},
+ "sourceNodeId": "223_phiopt",
+ "targetNodeId": "224_fab"},
+ {"id": "edge149",
+ "label": {"text": "next"},
+ "sourceNodeId": "222_sink",
+ "targetNodeId": "223_phiopt"},
+ {"id": "edge150",
+ "label": {"text": "next"},
+ "sourceNodeId": "221_forwprop",
+ "targetNodeId": "222_sink"},
+ {"id": "edge151",
+ "label": {"text": "next"},
+ "sourceNodeId": "220_dce",
+ "targetNodeId": "221_forwprop"},
+ {"id": "edge152",
+ "label": {"text": "next"},
+ "sourceNodeId": "219_dse",
+ "targetNodeId": "220_dce"},
+ {"id": "edge153",
+ "label": {"text": "next"},
+ "sourceNodeId": "218_wrestrict",
+ "targetNodeId": "219_dse"},
+ {"id": "edge154",
+ "label": {"text": "next"},
+ "sourceNodeId": "217_ccp",
+ "targetNodeId": "218_wrestrict"},
+ {"id": "edge155",
+ "label": {"text": "next"},
+ "sourceNodeId": "216_vrp",
+ "targetNodeId": "217_ccp"},
+ {"id": "edge156",
+ "label": {"text": "next"},
+ "sourceNodeId": "215_threadfull",
+ "targetNodeId": "216_vrp"},
+ {"id": "edge157",
+ "label": {"text": "next"},
+ "sourceNodeId": "214_strlen",
+ "targetNodeId": "215_threadfull"},
+ {"id": "edge158",
+ "label": {"text": "next"},
+ "sourceNodeId": "213_dom",
+ "targetNodeId": "214_strlen"},
+ {"id": "edge159",
+ "label": {"text": "next"},
+ "sourceNodeId": "212_thread",
+ "targetNodeId": "213_dom"},
+ {"id": "edge160",
+ "label": {"text": "next"},
+ "sourceNodeId": "211_fre",
+ "targetNodeId": "212_thread"},
+ {"id": "edge161",
+ "label": {"text": "next"},
+ "sourceNodeId": "210_tracer",
+ "targetNodeId": "211_fre"},
+ {"id": "edge162",
+ "label": {"text": "next"},
+ "sourceNodeId": "209_split-paths",
+ "targetNodeId": "210_tracer"},
+ {"id": "edge163",
+ "label": {"text": "next"},
+ "sourceNodeId": "208_slsr",
+ "targetNodeId": "209_split-paths"},
+ {"id": "edge164",
+ "label": {"text": "next"},
+ "sourceNodeId": "207_reassoc",
+ "targetNodeId": "208_slsr"},
+ {"id": "edge165",
+ "label": {"text": "next"},
+ "sourceNodeId": "206_recip",
+ "targetNodeId": "207_reassoc"},
+ {"id": "edge166",
+ "label": {"text": "next"},
+ "sourceNodeId": "205_sincos",
+ "targetNodeId": "206_recip"},
+ {"id": "edge167",
+ "label": {"text": "next"},
+ "sourceNodeId": "204_switchlower",
+ "targetNodeId": "205_sincos"},
+ {"id": "edge168",
+ "label": {"text": "next"},
+ "sourceNodeId": "203_veclower2",
+ "targetNodeId": "204_switchlower"},
+ {"id": "edge169",
+ "label": {"text": "next"},
+ "sourceNodeId": "202_simduid",
+ "targetNodeId": "203_veclower2"},
+ {"id": "edge170",
+ "label": {"text": "next"},
+ "sourceNodeId": "200_no_loop",
+ "targetNodeId": "202_simduid"},
+ {"id": "edge171",
+ "label": {"text": "next"},
+ "sourceNodeId": "167_loop",
+ "targetNodeId": "200_no_loop"},
+ {"id": "edge172",
+ "label": {"text": "next"},
+ "sourceNodeId": "166_fix_loops",
+ "targetNodeId": "167_loop"},
+ {"id": "edge173",
+ "label": {"text": "next"},
+ "sourceNodeId": "165_dce",
+ "targetNodeId": "166_fix_loops"},
+ {"id": "edge174",
+ "label": {"text": "next"},
+ "sourceNodeId": "164_dse",
+ "targetNodeId": "165_dce"},
+ {"id": "edge175",
+ "label": {"text": "next"},
+ "sourceNodeId": "163_tsan",
+ "targetNodeId": "164_dse"},
+ {"id": "edge176",
+ "label": {"text": "next"},
+ "sourceNodeId": "162_asan",
+ "targetNodeId": "163_tsan"},
+ {"id": "edge177",
+ "label": {"text": "next"},
+ "sourceNodeId": "161_sancov",
+ "targetNodeId": "162_asan"},
+ {"id": "edge178",
+ "label": {"text": "next"},
+ "sourceNodeId": "160_sink",
+ "targetNodeId": "161_sancov"},
+ {"id": "edge179",
+ "label": {"text": "next"},
+ "sourceNodeId": "159_pre",
+ "targetNodeId": "160_sink"},
+ {"id": "edge180",
+ "label": {"text": "next"},
+ "sourceNodeId": "158_walloca",
+ "targetNodeId": "159_pre"},
+ {"id": "edge181",
+ "label": {"text": "next"},
+ "sourceNodeId": "157_lim",
+ "targetNodeId": "158_walloca"},
+ {"id": "edge182",
+ "label": {"text": "next"},
+ "sourceNodeId": "156_laddress",
+ "targetNodeId": "157_lim"},
+ {"id": "edge183",
+ "label": {"text": "next"},
+ "sourceNodeId": "155_bswap",
+ "targetNodeId": "156_laddress"},
+ {"id": "edge184",
+ "label": {"text": "next"},
+ "sourceNodeId": "154_pow",
+ "targetNodeId": "155_bswap"},
+ {"id": "edge185",
+ "label": {"text": "next"},
+ "sourceNodeId": "153_ccp",
+ "targetNodeId": "154_pow"},
+ {"id": "edge186",
+ "label": {"text": "next"},
+ "sourceNodeId": "152_phiopt",
+ "targetNodeId": "153_ccp"},
+ {"id": "edge187",
+ "label": {"text": "next"},
+ "sourceNodeId": "151_forwprop",
+ "targetNodeId": "152_phiopt"},
+ {"id": "edge188",
+ "label": {"text": "next"},
+ "sourceNodeId": "150_dce",
+ "targetNodeId": "151_forwprop"},
+ {"id": "edge189",
+ "label": {"text": "next"},
+ "sourceNodeId": "149_reassoc",
+ "targetNodeId": "150_dce"},
+ {"id": "edge190",
+ "label": {"text": "next"},
+ "sourceNodeId": "148_isolate-paths",
+ "targetNodeId": "149_reassoc"},
+ {"id": "edge191",
+ "label": {"text": "next"},
+ "sourceNodeId": "147_copyprop",
+ "targetNodeId": "148_isolate-paths"},
+ {"id": "edge192",
+ "label": {"text": "next"},
+ "sourceNodeId": "146_dom",
+ "targetNodeId": "147_copyprop"},
+ {"id": "edge193",
+ "label": {"text": "next"},
+ "sourceNodeId": "145_thread",
+ "targetNodeId": "146_dom"},
+ {"id": "edge194",
+ "label": {"text": "next"},
+ "sourceNodeId": "144_sra",
+ "targetNodeId": "145_thread"},
+ {"id": "edge195",
+ "label": {"text": "next"},
+ "sourceNodeId": "143_bitintlower",
+ "targetNodeId": "144_sra"},
+ {"id": "edge196",
+ "label": {"text": "next"},
+ "sourceNodeId": "142_cplxlower",
+ "targetNodeId": "143_bitintlower"},
+ {"id": "edge197",
+ "label": {"text": "next"},
+ "sourceNodeId": "141_ch",
+ "targetNodeId": "142_cplxlower"},
+ {"id": "edge198",
+ "label": {"text": "next"},
+ "sourceNodeId": "140_tailr",
+ "targetNodeId": "141_ch"},
+ {"id": "edge199",
+ "label": {"text": "next"},
+ "sourceNodeId": "139_phiopt",
+ "targetNodeId": "140_tailr"},
+ {"id": "edge200",
+ "label": {"text": "next"},
+ "sourceNodeId": "138_mergephi",
+ "targetNodeId": "139_phiopt"},
+ {"id": "edge201",
+ "label": {"text": "next"},
+ "sourceNodeId": "137_ifcombine",
+ "targetNodeId": "138_mergephi"},
+ {"id": "edge202",
+ "label": {"text": "next"},
+ "sourceNodeId": "136_copyprop",
+ "targetNodeId": "137_ifcombine"},
+ {"id": "edge203",
+ "label": {"text": "next"},
+ "sourceNodeId": "135_cselim",
+ "targetNodeId": "136_copyprop"},
+ {"id": "edge204",
+ "label": {"text": "next"},
+ "sourceNodeId": "134_cdce",
+ "targetNodeId": "135_cselim"},
+ {"id": "edge205",
+ "label": {"text": "next"},
+ "sourceNodeId": "133_stdarg",
+ "targetNodeId": "134_cdce"},
+ {"id": "edge206",
+ "label": {"text": "next"},
+ "sourceNodeId": "132_dce",
+ "targetNodeId": "133_stdarg"},
+ {"id": "edge207",
+ "label": {"text": "next"},
+ "sourceNodeId": "131_dse",
+ "targetNodeId": "132_dce"},
+ {"id": "edge208",
+ "label": {"text": "next"},
+ "sourceNodeId": "130_bounds",
+ "targetNodeId": "131_dse"},
+ {"id": "edge209",
+ "label": {"text": "next"},
+ "sourceNodeId": "129_vrp",
+ "targetNodeId": "130_bounds"},
+ {"id": "edge210",
+ "label": {"text": "next"},
+ "sourceNodeId": "128_threadfull",
+ "targetNodeId": "129_vrp"},
+ {"id": "edge211",
+ "label": {"text": "next"},
+ "sourceNodeId": "127_mergephi",
+ "targetNodeId": "128_threadfull"},
+ {"id": "edge212",
+ "label": {"text": "next"},
+ "sourceNodeId": "126_fre",
+ "targetNodeId": "127_mergephi"},
+ {"id": "edge213",
+ "label": {"text": "next"},
+ "sourceNodeId": "125_retslot",
+ "targetNodeId": "126_fre"},
+ {"id": "edge214",
+ "label": {"text": "next"},
+ "sourceNodeId": "124_alias",
+ "targetNodeId": "125_retslot"},
+ {"id": "edge215",
+ "label": {"text": "next"},
+ "sourceNodeId": "123_forwprop",
+ "targetNodeId": "124_alias"},
+ {"id": "edge216",
+ "label": {"text": "next"},
+ "sourceNodeId": "122_phiprop",
+ "targetNodeId": "123_forwprop"},
+ {"id": "edge217",
+ "label": {"text": "next"},
+ "sourceNodeId": "121_backprop",
+ "targetNodeId": "122_phiprop"},
+ {"id": "edge218",
+ "label": {"text": "next"},
+ "sourceNodeId": "120_cunrolli",
+ "targetNodeId": "121_backprop"},
+ {"id": "edge219",
+ "label": {"text": "next"},
+ "sourceNodeId": "119_rebuild_frequencies",
+ "targetNodeId": "120_cunrolli"},
+ {"id": "edge220",
+ "label": {"text": "next"},
+ "sourceNodeId": "118_waccess",
+ "targetNodeId": "119_rebuild_frequencies"},
+ {"id": "edge221",
+ "label": {"text": "next"},
+ "sourceNodeId": "117_post_ipa_warn",
+ "targetNodeId": "118_waccess"},
+ {"id": "edge222",
+ "label": {"text": "next"},
+ "sourceNodeId": "116_objsz",
+ "targetNodeId": "117_post_ipa_warn"},
+ {"id": "edge223",
+ "label": {"text": "next"},
+ "sourceNodeId": "115_ccp",
+ "targetNodeId": "116_objsz"},
+ {"id": "edge224",
+ "label": {"text": "next"},
+ "sourceNodeId": "*strip_predict_hints_0x101f27e0",
+ "targetNodeId": "115_ccp"},
+ {"id": "edge225",
+ "label": {"text": "next"},
+ "sourceNodeId": "*remove_cgraph_callee_edges_0x101f2780",
+ "targetNodeId": "*strip_predict_hints_0x101f27e0"},
+ {"id": "edge226",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*all_optimizations_0x101f2720",
+ "targetNodeId": "*remove_cgraph_callee_edges_0x101f2780"},
+ {"id": "edge227",
+ "label": {"text": "next"},
+ "sourceNodeId": "251_uninit",
+ "targetNodeId": "252_uncprop"},
+ {"id": "edge228",
+ "label": {"text": "next"},
+ "sourceNodeId": "250_crited",
+ "targetNodeId": "251_uninit"},
+ {"id": "edge229",
+ "label": {"text": "next"},
+ "sourceNodeId": "249_tsan",
+ "targetNodeId": "250_crited"},
+ {"id": "edge230",
+ "label": {"text": "next"},
+ "sourceNodeId": "248_asan",
+ "targetNodeId": "249_tsan"},
+ {"id": "edge231",
+ "label": {"text": "next"},
+ "sourceNodeId": "247_sancov",
+ "targetNodeId": "248_asan"},
+ {"id": "edge232",
+ "label": {"text": "next"},
+ "sourceNodeId": "246_rebuild_frequencies",
+ "targetNodeId": "247_sancov"},
+ {"id": "edge233",
+ "label": {"text": "next"},
+ "sourceNodeId": "245_dce",
+ "targetNodeId": "246_rebuild_frequencies"},
+ {"id": "edge234",
+ "label": {"text": "next"},
+ "sourceNodeId": "244_copyprop",
+ "targetNodeId": "245_dce"},
+ {"id": "edge235",
+ "label": {"text": "next"},
+ "sourceNodeId": "243_strlen",
+ "targetNodeId": "244_copyprop"},
+ {"id": "edge236",
+ "label": {"text": "next"},
+ "sourceNodeId": "242_fab",
+ "targetNodeId": "243_strlen"},
+ {"id": "edge237",
+ "label": {"text": "next"},
+ "sourceNodeId": "241_objsz",
+ "targetNodeId": "242_fab"},
+ {"id": "edge238",
+ "label": {"text": "next"},
+ "sourceNodeId": "240_post_ipa_warn",
+ "targetNodeId": "241_objsz"},
+ {"id": "edge239",
+ "label": {"text": "next"},
+ "sourceNodeId": "239_ccp",
+ "targetNodeId": "240_post_ipa_warn"},
+ {"id": "edge240",
+ "label": {"text": "next"},
+ "sourceNodeId": "238_switchlower",
+ "targetNodeId": "239_ccp"},
+ {"id": "edge241",
+ "label": {"text": "next"},
+ "sourceNodeId": "237_veclower2",
+ "targetNodeId": "238_switchlower"},
+ {"id": "edge242",
+ "label": {"text": "next"},
+ "sourceNodeId": "236_bitintlower",
+ "targetNodeId": "237_veclower2"},
+ {"id": "edge243",
+ "label": {"text": "next"},
+ "sourceNodeId": "235_cplxlower",
+ "targetNodeId": "236_bitintlower"},
+ {"id": "edge244",
+ "label": {"text": "next"},
+ "sourceNodeId": "*strip_predict_hints_0x101f5bb0",
+ "targetNodeId": "235_cplxlower"},
+ {"id": "edge245",
+ "label": {"text": "next"},
+ "sourceNodeId": "*remove_cgraph_callee_edges_0x101f5b50",
+ "targetNodeId": "*strip_predict_hints_0x101f5bb0"},
+ {"id": "edge246",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*all_optimizations_g_0x101f5af0",
+ "targetNodeId": "*remove_cgraph_callee_edges_0x101f5b50"},
+ {"id": "edge247",
+ "label": {"text": "next"},
+ "sourceNodeId": "255_tmmemopt",
+ "targetNodeId": "256_tmedge"},
+ {"id": "edge248",
+ "label": {"text": "next"},
+ "sourceNodeId": "254_tmmark",
+ "targetNodeId": "255_tmmemopt"},
+ {"id": "edge249",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*tminit_0x101f6370",
+ "targetNodeId": "254_tmmark"},
+ {"id": "edge250",
+ "label": {"text": "next"},
+ "sourceNodeId": "299_loop2_doloop",
+ "targetNodeId": "300_loop2_done"},
+ {"id": "edge251",
+ "label": {"text": "next"},
+ "sourceNodeId": "298_loop2_unroll",
+ "targetNodeId": "299_loop2_doloop"},
+ {"id": "edge252",
+ "label": {"text": "next"},
+ "sourceNodeId": "297_loop2_invariant",
+ "targetNodeId": "298_loop2_unroll"},
+ {"id": "edge253",
+ "label": {"text": "next"},
+ "sourceNodeId": "296_loop2_init",
+ "targetNodeId": "297_loop2_invariant"},
+ {"id": "edge254",
+ "label": {"text": "sub"},
+ "sourceNodeId": "295_loop2",
+ "targetNodeId": "296_loop2_init"},
+ {"id": "edge255",
+ "label": {"text": "next"},
+ "sourceNodeId": "355_split4",
+ "targetNodeId": "356_stack"},
+ {"id": "edge256",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*stack_regs_0x101f8d10",
+ "targetNodeId": "355_split4"},
+ {"id": "edge257",
+ "label": {"text": "next"},
+ "sourceNodeId": "354_sched2",
+ "targetNodeId": "*stack_regs_0x101f8d10"},
+ {"id": "edge258",
+ "label": {"text": "next"},
+ "sourceNodeId": "353_split3",
+ "targetNodeId": "354_sched2"},
+ {"id": "edge259",
+ "label": {"text": "next"},
+ "sourceNodeId": "*leaf_regs_0x101f8bf0",
+ "targetNodeId": "353_split3"},
+ {"id": "edge260",
+ "label": {"text": "next"},
+ "sourceNodeId": "352_bbro",
+ "targetNodeId": "*leaf_regs_0x101f8bf0"},
+ {"id": "edge261",
+ "label": {"text": "next"},
+ "sourceNodeId": "351_rtl_dce",
+ "targetNodeId": "352_bbro"},
+ {"id": "edge262",
+ "label": {"text": "next"},
+ "sourceNodeId": "350_cprop_hardreg",
+ "targetNodeId": "351_rtl_dce"},
+ {"id": "edge263",
+ "label": {"text": "next"},
+ "sourceNodeId": "349_fold_mem_offsets",
+ "targetNodeId": "350_cprop_hardreg"},
+ {"id": "edge264",
+ "label": {"text": "next"},
+ "sourceNodeId": "348_rnreg",
+ "targetNodeId": "349_fold_mem_offsets"},
+ {"id": "edge265",
+ "label": {"text": "next"},
+ "sourceNodeId": "347_ce3",
+ "targetNodeId": "348_rnreg"},
+ {"id": "edge266",
+ "label": {"text": "next"},
+ "sourceNodeId": "346_peephole2",
+ "targetNodeId": "347_ce3"},
+ {"id": "edge267",
+ "label": {"text": "next"},
+ "sourceNodeId": "345_sched_fusion",
+ "targetNodeId": "346_peephole2"},
+ {"id": "edge268",
+ "label": {"text": "next"},
+ "sourceNodeId": "344_compgotos",
+ "targetNodeId": "345_sched_fusion"},
+ {"id": "edge269",
+ "label": {"text": "next"},
+ "sourceNodeId": "343_jump2",
+ "targetNodeId": "344_compgotos"},
+ {"id": "edge270",
+ "label": {"text": "next"},
+ "sourceNodeId": "342_csa",
+ "targetNodeId": "343_jump2"},
+ {"id": "edge271",
+ "label": {"text": "next"},
+ "sourceNodeId": "341_dse2",
+ "targetNodeId": "342_csa"},
+ {"id": "edge272",
+ "label": {"text": "next"},
+ "sourceNodeId": "340_pro_and_epilogue",
+ "targetNodeId": "341_dse2"},
+ {"id": "edge273",
+ "label": {"text": "next"},
+ "sourceNodeId": "339_cmpelim",
+ "targetNodeId": "340_pro_and_epilogue"},
+ {"id": "edge274",
+ "label": {"text": "next"},
+ "sourceNodeId": "338_ree",
+ "targetNodeId": "339_cmpelim"},
+ {"id": "edge275",
+ "label": {"text": "next"},
+ "sourceNodeId": "337_split2",
+ "targetNodeId": "338_ree"},
+ {"id": "edge276",
+ "label": {"text": "next"},
+ "sourceNodeId": "336_gcse2",
+ "targetNodeId": "337_split2"},
+ {"id": "edge277",
+ "label": {"text": "next"},
+ "sourceNodeId": "335_late_combine",
+ "targetNodeId": "336_gcse2"},
+ {"id": "edge278",
+ "label": {"text": "next"},
+ "sourceNodeId": "334_vzeroupper",
+ "targetNodeId": "335_late_combine"},
+ {"id": "edge279",
+ "label": {"text": "next"},
+ "sourceNodeId": "333_postreload",
+ "targetNodeId": "334_vzeroupper"},
+ {"id": "edge280",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*all-postreload_0x101f8410",
+ "targetNodeId": "333_postreload"},
+ {"id": "edge281",
+ "label": {"text": "next"},
+ "sourceNodeId": "370_dwarf2",
+ "targetNodeId": "371_final"},
+ {"id": "edge282",
+ "label": {"text": "next"},
+ "sourceNodeId": "369_nothrow",
+ "targetNodeId": "370_dwarf2"},
+ {"id": "edge283",
+ "label": {"text": "next"},
+ "sourceNodeId": "368_shorten",
+ "targetNodeId": "369_nothrow"},
+ {"id": "edge284",
+ "label": {"text": "next"},
+ "sourceNodeId": "367_align_tight_loops",
+ "targetNodeId": "368_shorten"},
+ {"id": "edge285",
+ "label": {"text": "next"},
+ "sourceNodeId": "366_endbr_and_patchable_area",
+ "targetNodeId": "367_align_tight_loops"},
+ {"id": "edge286",
+ "label": {"text": "next"},
+ "sourceNodeId": "365_eh_ranges",
+ "targetNodeId": "366_endbr_and_patchable_area"},
+ {"id": "edge287",
+ "label": {"text": "next"},
+ "sourceNodeId": "364_split5",
+ "targetNodeId": "365_eh_ranges"},
+ {"id": "edge288",
+ "label": {"text": "next"},
+ "sourceNodeId": "363_dbr",
+ "targetNodeId": "364_split5"},
+ {"id": "edge289",
+ "label": {"text": "next"},
+ "sourceNodeId": "362_barriers",
+ "targetNodeId": "363_dbr"},
+ {"id": "edge290",
+ "label": {"text": "next"},
+ "sourceNodeId": "361_mach",
+ "targetNodeId": "362_barriers"},
+ {"id": "edge291",
+ "label": {"text": "next"},
+ "sourceNodeId": "*free_cfg_0x101f9010",
+ "targetNodeId": "361_mach"},
+ {"id": "edge292",
+ "label": {"text": "next"},
+ "sourceNodeId": "360_vartrack",
+ "targetNodeId": "*free_cfg_0x101f9010"},
+ {"id": "edge293",
+ "label": {"text": "next"},
+ "sourceNodeId": "359_alignments",
+ "targetNodeId": "360_vartrack"},
+ {"id": "edge294",
+ "label": {"text": "next"},
+ "sourceNodeId": "358_zero_call_used_regs",
+ "targetNodeId": "359_alignments"},
+ {"id": "edge295",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*all-late_compilation_0x101f8e90",
+ "targetNodeId": "358_zero_call_used_regs"},
+ {"id": "edge296",
+ "label": {"text": "next"},
+ "sourceNodeId": "*all-late_compilation_0x101f8e90",
+ "targetNodeId": "372_dfinish"},
+ {"id": "edge297",
+ "label": {"text": "next"},
+ "sourceNodeId": "357_late_pro_and_epilogue",
+ "targetNodeId": "*all-late_compilation_0x101f8e90"},
+ {"id": "edge298",
+ "label": {"text": "next"},
+ "sourceNodeId": "*all-postreload_0x101f8410",
+ "targetNodeId": "357_late_pro_and_epilogue"},
+ {"id": "edge299",
+ "label": {"text": "next"},
+ "sourceNodeId": "332_reload",
+ "targetNodeId": "*all-postreload_0x101f8410"},
+ {"id": "edge300",
+ "label": {"text": "next"},
+ "sourceNodeId": "331_ira",
+ "targetNodeId": "332_reload"},
+ {"id": "edge301",
+ "label": {"text": "next"},
+ "sourceNodeId": "330_early_remat",
+ "targetNodeId": "331_ira"},
+ {"id": "edge302",
+ "label": {"text": "next"},
+ "sourceNodeId": "329_avoid_store_forwarding",
+ "targetNodeId": "330_early_remat"},
+ {"id": "edge303",
+ "label": {"text": "next"},
+ "sourceNodeId": "328_sched1",
+ "targetNodeId": "329_avoid_store_forwarding"},
+ {"id": "edge304",
+ "label": {"text": "next"},
+ "sourceNodeId": "327_lr_shrinkage",
+ "targetNodeId": "328_sched1"},
+ {"id": "edge305",
+ "label": {"text": "next"},
+ "sourceNodeId": "326_sms",
+ "targetNodeId": "327_lr_shrinkage"},
+ {"id": "edge306",
+ "label": {"text": "next"},
+ "sourceNodeId": "325_asmcons",
+ "targetNodeId": "326_sms"},
+ {"id": "edge307",
+ "label": {"text": "next"},
+ "sourceNodeId": "324_mode_sw",
+ "targetNodeId": "325_asmcons"},
+ {"id": "edge308",
+ "label": {"text": "next"},
+ "sourceNodeId": "*stack_ptr_mod_0x101f8050",
+ "targetNodeId": "324_mode_sw"},
+ {"id": "edge309",
+ "label": {"text": "next"},
+ "sourceNodeId": "323_no-opt dfinit",
+ "targetNodeId": "*stack_ptr_mod_0x101f8050"},
+ {"id": "edge310",
+ "label": {"text": "next"},
+ "sourceNodeId": "322_subreg3",
+ "targetNodeId": "323_no-opt dfinit"},
+ {"id": "edge311",
+ "label": {"text": "next"},
+ "sourceNodeId": "321_split1",
+ "targetNodeId": "322_subreg3"},
+ {"id": "edge312",
+ "label": {"text": "next"},
+ "sourceNodeId": "320_outof_cfglayout",
+ "targetNodeId": "321_split1"},
+ {"id": "edge313",
+ "label": {"text": "next"},
+ "sourceNodeId": "319_bbpart",
+ "targetNodeId": "320_outof_cfglayout"},
+ {"id": "edge314",
+ "label": {"text": "next"},
+ "sourceNodeId": "318_jump_after_combine",
+ "targetNodeId": "319_bbpart"},
+ {"id": "edge315",
+ "label": {"text": "next"},
+ "sourceNodeId": "317_ce2",
+ "targetNodeId": "318_jump_after_combine"},
+ {"id": "edge316",
+ "label": {"text": "next"},
+ "sourceNodeId": "316_stv",
+ "targetNodeId": "317_ce2"},
+ {"id": "edge317",
+ "label": {"text": "next"},
+ "sourceNodeId": "315_rrvl",
+ "targetNodeId": "316_stv"},
+ {"id": "edge318",
+ "label": {"text": "next"},
+ "sourceNodeId": "314_rpad",
+ "targetNodeId": "315_rrvl"},
+ {"id": "edge319",
+ "label": {"text": "next"},
+ "sourceNodeId": "313_late_combine",
+ "targetNodeId": "314_rpad"},
+ {"id": "edge320",
+ "label": {"text": "next"},
+ "sourceNodeId": "312_combine",
+ "targetNodeId": "313_late_combine"},
+ {"id": "edge321",
+ "label": {"text": "next"},
+ "sourceNodeId": "311_ext_dce",
+ "targetNodeId": "312_combine"},
+ {"id": "edge322",
+ "label": {"text": "next"},
+ "sourceNodeId": "310_ud_dce",
+ "targetNodeId": "311_ext_dce"},
+ {"id": "edge323",
+ "label": {"text": "next"},
+ "sourceNodeId": "309_init-regs",
+ "targetNodeId": "310_ud_dce"},
+ {"id": "edge324",
+ "label": {"text": "next"},
+ "sourceNodeId": "308_auto_inc_dec",
+ "targetNodeId": "309_init-regs"},
+ {"id": "edge325",
+ "label": {"text": "next"},
+ "sourceNodeId": "307_fwprop2",
+ "targetNodeId": "308_auto_inc_dec"},
+ {"id": "edge326",
+ "label": {"text": "next"},
+ "sourceNodeId": "306_dse1",
+ "targetNodeId": "307_fwprop2"},
+ {"id": "edge327",
+ "label": {"text": "next"},
+ "sourceNodeId": "305_cse2",
+ "targetNodeId": "306_dse1"},
+ {"id": "edge328",
+ "label": {"text": "next"},
+ "sourceNodeId": "304_stv",
+ "targetNodeId": "305_cse2"},
+ {"id": "edge329",
+ "label": {"text": "next"},
+ "sourceNodeId": "303_cprop",
+ "targetNodeId": "304_stv"},
+ {"id": "edge330",
+ "label": {"text": "next"},
+ "sourceNodeId": "302_web",
+ "targetNodeId": "303_cprop"},
+ {"id": "edge331",
+ "label": {"text": "next"},
+ "sourceNodeId": "301_subreg2",
+ "targetNodeId": "302_web"},
+ {"id": "edge332",
+ "label": {"text": "next"},
+ "sourceNodeId": "295_loop2",
+ "targetNodeId": "301_subreg2"},
+ {"id": "edge333",
+ "label": {"text": "next"},
+ "sourceNodeId": "294_reginfo",
+ "targetNodeId": "295_loop2"},
+ {"id": "edge334",
+ "label": {"text": "next"},
+ "sourceNodeId": "293_apx_nfcvt",
+ "targetNodeId": "294_reginfo"},
+ {"id": "edge335",
+ "label": {"text": "next"},
+ "sourceNodeId": "292_ce1",
+ "targetNodeId": "293_apx_nfcvt"},
+ {"id": "edge336",
+ "label": {"text": "next"},
+ "sourceNodeId": "291_cse_local",
+ "targetNodeId": "292_ce1"},
+ {"id": "edge337",
+ "label": {"text": "next"},
+ "sourceNodeId": "290_store_motion",
+ "targetNodeId": "291_cse_local"},
+ {"id": "edge338",
+ "label": {"text": "next"},
+ "sourceNodeId": "289_cprop",
+ "targetNodeId": "290_store_motion"},
+ {"id": "edge339",
+ "label": {"text": "next"},
+ "sourceNodeId": "288_hardreg_pre",
+ "targetNodeId": "289_cprop"},
+ {"id": "edge340",
+ "label": {"text": "next"},
+ "sourceNodeId": "287_hoist",
+ "targetNodeId": "288_hardreg_pre"},
+ {"id": "edge341",
+ "label": {"text": "next"},
+ "sourceNodeId": "286_rtl pre",
+ "targetNodeId": "287_hoist"},
+ {"id": "edge342",
+ "label": {"text": "next"},
+ "sourceNodeId": "285_cprop",
+ "targetNodeId": "286_rtl pre"},
+ {"id": "edge343",
+ "label": {"text": "next"},
+ "sourceNodeId": "284_fwprop1",
+ "targetNodeId": "285_cprop"},
+ {"id": "edge344",
+ "label": {"text": "next"},
+ "sourceNodeId": "283_cse1",
+ "targetNodeId": "284_fwprop1"},
+ {"id": "edge345",
+ "label": {"text": "next"},
+ "sourceNodeId": "282_dfinit",
+ "targetNodeId": "283_cse1"},
+ {"id": "edge346",
+ "label": {"text": "next"},
+ "sourceNodeId": "281_subreg1",
+ "targetNodeId": "282_dfinit"},
+ {"id": "edge347",
+ "label": {"text": "next"},
+ "sourceNodeId": "280_jump",
+ "targetNodeId": "281_subreg1"},
+ {"id": "edge348",
+ "label": {"text": "next"},
+ "sourceNodeId": "279_into_cfglayout",
+ "targetNodeId": "280_jump"},
+ {"id": "edge349",
+ "label": {"text": "next"},
+ "sourceNodeId": "278_vregs",
+ "targetNodeId": "279_into_cfglayout"},
+ {"id": "edge350",
+ "label": {"text": "sub"},
+ "sourceNodeId": "*rest_of_compilation_0x101f6e90",
+ "targetNodeId": "278_vregs"},
+ {"id": "edge351",
+ "label": {"text": "next"},
+ "sourceNodeId": "*rest_of_compilation_0x101f6e90",
+ "targetNodeId": "*clean_state_0x101f9500"},
+ {"id": "edge352",
+ "label": {"text": "next"},
+ "sourceNodeId": "277_expand",
+ "targetNodeId": "*rest_of_compilation_0x101f6e90"},
+ {"id": "edge353",
+ "label": {"text": "next"},
+ "sourceNodeId": "*warn_function_noreturn_0x101f6dd0",
+ "targetNodeId": "277_expand"},
+ {"id": "edge354",
+ "label": {"text": "next"},
+ "sourceNodeId": "276_optimized",
+ "targetNodeId": "*warn_function_noreturn_0x101f6dd0"},
+ {"id": "edge355",
+ "label": {"text": "next"},
+ "sourceNodeId": "275_waccess",
+ "targetNodeId": "276_optimized"},
+ {"id": "edge356",
+ "label": {"text": "next"},
+ "sourceNodeId": "274_hardcmp",
+ "targetNodeId": "275_waccess"},
+ {"id": "edge357",
+ "label": {"text": "next"},
+ "sourceNodeId": "273_hardcbr",
+ "targetNodeId": "274_hardcmp"},
+ {"id": "edge358",
+ "label": {"text": "next"},
+ "sourceNodeId": "272_isel",
+ "targetNodeId": "273_hardcbr"},
+ {"id": "edge359",
+ "label": {"text": "next"},
+ "sourceNodeId": "271_nrv",
+ "targetNodeId": "272_isel"},
+ {"id": "edge360",
+ "label": {"text": "next"},
+ "sourceNodeId": "270_resx",
+ "targetNodeId": "271_nrv"},
+ {"id": "edge361",
+ "label": {"text": "next"},
+ "sourceNodeId": "269_ehcleanup",
+ "targetNodeId": "270_resx"},
+ {"id": "edge362",
+ "label": {"text": "next"},
+ "sourceNodeId": "268_sanopt",
+ "targetNodeId": "269_ehcleanup"},
+ {"id": "edge363",
+ "label": {"text": "next"},
+ "sourceNodeId": "267_musttail",
+ "targetNodeId": "268_sanopt"},
+ {"id": "edge364",
+ "label": {"text": "next"},
+ "sourceNodeId": "266_tsan0",
+ "targetNodeId": "267_musttail"},
+ {"id": "edge365",
+ "label": {"text": "next"},
+ "sourceNodeId": "265_asan0",
+ "targetNodeId": "266_tsan0"},
+ {"id": "edge366",
+ "label": {"text": "next"},
+ "sourceNodeId": "264_switchlower_O0",
+ "targetNodeId": "265_asan0"},
+ {"id": "edge367",
+ "label": {"text": "next"},
+ "sourceNodeId": "263_sancov_O0",
+ "targetNodeId": "264_switchlower_O0"},
+ {"id": "edge368",
+ "label": {"text": "next"},
+ "sourceNodeId": "262_bitintlower0",
+ "targetNodeId": "263_sancov_O0"},
+ {"id": "edge369",
+ "label": {"text": "next"},
+ "sourceNodeId": "261_cplxlower0",
+ "targetNodeId": "262_bitintlower0"},
+ {"id": "edge370",
+ "label": {"text": "next"},
+ "sourceNodeId": "260_veclower",
+ "targetNodeId": "261_cplxlower0"},
+ {"id": "edge371",
+ "label": {"text": "next"},
+ "sourceNodeId": "259_lower_vaarg",
+ "targetNodeId": "260_veclower"},
+ {"id": "edge372",
+ "label": {"text": "next"},
+ "sourceNodeId": "258_vtable-verify",
+ "targetNodeId": "259_lower_vaarg"},
+ {"id": "edge373",
+ "label": {"text": "next"},
+ "sourceNodeId": "257_simduid",
+ "targetNodeId": "258_vtable-verify"},
+ {"id": "edge374",
+ "label": {"text": "next"},
+ "sourceNodeId": "*tminit_0x101f6370",
+ "targetNodeId": "257_simduid"},
+ {"id": "edge375",
+ "label": {"text": "next"},
+ "sourceNodeId": "253_assumptions",
+ "targetNodeId": "*tminit_0x101f6370"},
+ {"id": "edge376",
+ "label": {"text": "next"},
+ "sourceNodeId": "*all_optimizations_g_0x101f5af0",
+ "targetNodeId": "253_assumptions"},
+ {"id": "edge377",
+ "label": {"text": "next"},
+ "sourceNodeId": "*all_optimizations_0x101f2720",
+ "targetNodeId": "*all_optimizations_g_0x101f5af0"},
+ {"id": "edge378",
+ "label": {"text": "next"},
+ "sourceNodeId": "114_hardcfr",
+ "targetNodeId": "*all_optimizations_0x101f2720"},
+ {"id": "edge379",
+ "label": {"text": "next"},
+ "sourceNodeId": "113_adjust_alignment",
+ "targetNodeId": "114_hardcfr"},
+ {"id": "edge380",
+ "label": {"text": "next"},
+ "sourceNodeId": "112_omptargetlink",
+ "targetNodeId": "113_adjust_alignment"},
+ {"id": "edge381",
+ "label": {"text": "next"},
+ "sourceNodeId": "111_ompdevlow",
+ "targetNodeId": "112_omptargetlink"},
+ {"id": "edge382",
+ "label": {"text": "next"},
+ "sourceNodeId": "110_oaccdevlow",
+ "targetNodeId": "111_ompdevlow"},
+ {"id": "edge383",
+ "label": {"text": "next"},
+ "sourceNodeId": "109_omp_oacc_neuter_broadcast",
+ "targetNodeId": "110_oaccdevlow"},
+ {"id": "edge384",
+ "label": {"text": "next"},
+ "sourceNodeId": "108_oaccloops",
+ "targetNodeId": "109_omp_oacc_neuter_broadcast"},
+ {"id": "edge385",
+ "label": {"text": "next"},
+ "sourceNodeId": "107_ehdisp",
+ "targetNodeId": "108_oaccloops"},
+ {"id": "edge386",
+ "label": {"text": "next"},
+ "sourceNodeId": "106_fixup_cfg",
+ "targetNodeId": "107_ehdisp"}]}]}]}
+
+/* { dg-begin-multiline-output "" }
+In function 'test_graphs':
+/home/david/gcc-newgit-gcc16/src/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c:8:3: error: this is a placeholder error, with graphs
+ { dg-end-multiline-output "" } */
+
+/* Use a Python script to verify various properties about the generated
+ .html file:
+ { dg-final { run-html-pytest graphs.sarif "2.1.0-valid/graphs-check-html.py" } } */
+
+/* Use a Python script to verify various properties about the *generated*
+ .sarif file:
+ { dg-final { run-sarif-pytest graphs.roundtrip "2.1.0-valid/graphs-check-sarif-roundtrip.py" } } */
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 635778a..716a516 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,56 @@
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ * libsupc++/exception_ptr.h: Implement C++26 P3748R0 - Inspecting
+ exception_ptr should be constexpr.
+ (std::exception_ptr_cast): Make constexpr, remove inline keyword. Add
+ static_asserts for Mandates. For if consteval use std::rethrow_exception,
+ catch it and return its address or nullptr.
+ * testsuite/18_support/exception_ptr/exception_ptr_cast.cc (E::~E): Add
+ constexpr.
+ (G::G): Likewise.
+ (test01): Likewise. Return bool and take bool argument, throw if the
+ argument is true. Add static_assert(test01(false)).
+ (main): Call test01(true) in try.
+
+2025-07-11 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/cpp_type_traits.h (__is_floating<__float128>):
+ Do not depend on __STRICT_ANSI__.
+ * include/bits/stl_algobase.h (__size_to_integer(__float128)):
+ Likewise.
+ * include/std/type_traits (__is_floating_point_helper<__float128>):
+ Likewise.
+
+2025-07-11 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/96710
+ * include/bits/cpp_type_traits.h (__is_integer): Define explicit
+ specializations for __int128.
+ (__memcpyable_integer): Remove explicit specializations for
+ __int128.
+ * include/bits/iterator_concepts.h (incrementable_traits):
+ Likewise.
+ (__is_signed_int128, __is_unsigned_int128, __is_int128): Remove.
+ (__is_integer_like, __is_signed_integer_like): Remove check for
+ __int128.
+ * include/bits/max_size_type.h: Remove all uses of __is_int128
+ in constraints.
+ * include/bits/ranges_base.h (__to_unsigned_like): Remove
+ overloads for __int128.
+ (ranges::ssize): Remove special case for __int128.
+ * include/bits/stl_algobase.h (__size_to_integer): Define
+ __int128 overloads for strict modes.
+ * include/ext/numeric_traits.h (__is_integer_nonstrict): Remove
+ explicit specializations for __int128.
+ * include/std/charconv (to_chars): Define overloads for
+ __int128.
+ * include/std/format (__format::make_unsigned_t): Remove.
+ (__format::to_chars): Remove.
+ * include/std/limits (numeric_limits): Define explicit
+ specializations for __int128.
+ * include/std/type_traits (__is_integral_helper): Likewise.
+ (__make_unsigned, __make_signed): Likewise.
+
2025-07-10 Jakub Jelinek <jakub@redhat.com>
PR c++/117785