mirror of git://gcc.gnu.org/git/gcc.git
Compare commits
5 Commits
822a139e7d
...
eb717a8f4e
Author | SHA1 | Date |
---|---|---|
![]() |
eb717a8f4e | |
![]() |
128933c9cf | |
![]() |
175bacbb25 | |
![]() |
03fed2a80b | |
![]() |
c89bd48e7e |
|
@ -1,3 +1,7 @@
|
||||||
|
2025-10-16 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
* gcc.doxy (INPUT): Add gcc/custom-sarif-properties
|
||||||
|
|
||||||
2025-10-08 Jakub Jelinek <jakub@redhat.com>
|
2025-10-08 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
* unicode/README: Add HangulSyllableType.txt file to the
|
* unicode/README: Add HangulSyllableType.txt file to the
|
||||||
|
|
|
@ -478,7 +478,7 @@ WARN_LOGFILE =
|
||||||
# directories like "/usr/src/myproject". Separate the files or directories
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
# with spaces.
|
# with spaces.
|
||||||
|
|
||||||
INPUT = gcc gcc/analyzer gcc/diagnostics gcc/text-art
|
INPUT = gcc gcc/analyzer gcc/custom-sarif-properties gcc/diagnostics gcc/text-art
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files that
|
# This tag can be used to specify the character encoding of the source files that
|
||||||
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
|
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
|
||||||
|
|
112
gcc/ChangeLog
112
gcc/ChangeLog
|
@ -1,3 +1,115 @@
|
||||||
|
2025-10-16 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
* Makefile.in (OBJS-libcommon): Add
|
||||||
|
custom-sarif-properties/digraphs.o and
|
||||||
|
custom-sarif-properties/state-graphs.o. Remove
|
||||||
|
diagnostics/state-graphs.o.
|
||||||
|
* configure: Regenerate.
|
||||||
|
* configure.ac: Add custom-sarif-properties to subdir iteration.
|
||||||
|
* custom-sarif-properties/digraphs.cc: New file.
|
||||||
|
* custom-sarif-properties/digraphs.h: New file.
|
||||||
|
* custom-sarif-properties/state-graphs.cc: New file.
|
||||||
|
* custom-sarif-properties/state-graphs.h: New file.
|
||||||
|
* diagnostics/diagnostics-selftests.cc
|
||||||
|
(run_diagnostics_selftests): Drop call of state_graphs_cc_tests.
|
||||||
|
* diagnostics/diagnostics-selftests.h (state_graphs_cc_tests):
|
||||||
|
Delete decl.
|
||||||
|
* diagnostics/digraphs.cc: Include
|
||||||
|
"custom-sarif-properties/digraphs.h". Move include of
|
||||||
|
"selftest.h" to within CHECKING_P section.
|
||||||
|
(using digraph_object): New.
|
||||||
|
(namespace properties): New.
|
||||||
|
(diagnostics::digraphs::object::get_attr): Delete.
|
||||||
|
(diagnostics::digraphs::object::set_attr): Delete.
|
||||||
|
(diagnostics::digraphs::object::set_json_attr): Delete.
|
||||||
|
(digraph_object::get_property): New definitions, for various
|
||||||
|
property types.
|
||||||
|
(digraph_object::set_property): Likewise.
|
||||||
|
(digraph_object::maybe_get_property): New.
|
||||||
|
(digraph_object::get_property_as_tristate): New.
|
||||||
|
(digraph_object::ensure_property_bag): New.
|
||||||
|
(digraph::get_graph_kind): New.
|
||||||
|
(digraph::set_graph_kind): New.
|
||||||
|
Add include of "custom-sarif-properties/state-graphs.h".
|
||||||
|
(selftest::test_simple_graph): Rewrite to use json::property
|
||||||
|
instances rather than string attribute names.
|
||||||
|
(selftest::test_property_objects): New test.
|
||||||
|
(selftest::digraphs_cc_tests): Call it.
|
||||||
|
* diagnostics/digraphs.h: Include "tristate.h".
|
||||||
|
(object::get_attr): Delete.
|
||||||
|
(object::set_attr): Delete.
|
||||||
|
(object::get_property): New decls.
|
||||||
|
(object::set_property): New decls.
|
||||||
|
(object::maybe_get_property): New.
|
||||||
|
(object::get_property_as_tristate): New.
|
||||||
|
(object::set_json_attr): Delete.
|
||||||
|
(object::ensure_property_bag): New.
|
||||||
|
(graph::get_graph_kind): New.
|
||||||
|
(graph::set_graph_kind): New.
|
||||||
|
* diagnostics/html-sink.cc
|
||||||
|
(html_generation_options::html_generation_options): Update for
|
||||||
|
field renamings.
|
||||||
|
(html_generation_options::dump): Likewise.
|
||||||
|
(html_builder::maybe_make_state_diagram): Likewise.
|
||||||
|
(html_builder::add_graph): Show SARIF and .dot src inline, if
|
||||||
|
requested.
|
||||||
|
* diagnostics/html-sink.h
|
||||||
|
(html_generation_options::m_show_state_diagrams_sarif): Rename
|
||||||
|
to...
|
||||||
|
(html_generation_options::m_show_graph_sarif): ...this.
|
||||||
|
(html_generation_options::m_show_state_diagrams_dot_src): Rename
|
||||||
|
to...
|
||||||
|
(html_generation_options::m_show_graph_dot_src0): ...this.
|
||||||
|
* diagnostics/output-spec.cc
|
||||||
|
(html_scheme_handler::maybe_handle_kv): Rename keys.
|
||||||
|
(html_scheme_handler::get_keys): Likewise.
|
||||||
|
* diagnostics/state-graphs-to-dot.cc: : Reimplement throughout to
|
||||||
|
use json::property instances found within custom_sarif_properties
|
||||||
|
throughout, rather than types in diagnostics::state_graphs.
|
||||||
|
* diagnostics/state-graphs.cc: Deleted file.
|
||||||
|
* diagnostics/state-graphs.h: Delete almost all, except decl of
|
||||||
|
diagnostics::state_graphs::make_dot_graph.
|
||||||
|
* doc/invoke.texi: Update for changes to "experimental-html" sink
|
||||||
|
keys.
|
||||||
|
* json.cc (json::object::set_string): New.
|
||||||
|
(json::object::set_integer): New.
|
||||||
|
(json::object::set_bool): New.
|
||||||
|
(json::object::set_array_of_string): New.
|
||||||
|
* json.h: Include "label-text.h".
|
||||||
|
(struct json::property): New template.
|
||||||
|
(json::string_property): New.
|
||||||
|
(json::integer_property): New.
|
||||||
|
(json::bool_property): New.
|
||||||
|
(json::json_property): New.
|
||||||
|
(using json::array_of_string_property): New.
|
||||||
|
(struct json::enum_traits): New.
|
||||||
|
(enum_json::property): New.
|
||||||
|
(json::value::dyn_cast_array): New vfunc.
|
||||||
|
(json::value::dyn_cast_integer_number): New vfunc.
|
||||||
|
(json::value::set_string): New.
|
||||||
|
(json::value::set_integer): New.
|
||||||
|
(json::value::set_bool): New.
|
||||||
|
(json::value::set_array_of_string): New.
|
||||||
|
(json::value::maybe_get_enum): New.
|
||||||
|
(json::value::set_enum): New.
|
||||||
|
(json::array::dyn_cast_array): New.
|
||||||
|
(json::integer_number::dyn_cast_integer_number): New.
|
||||||
|
(object::maybe_get_enum): New.
|
||||||
|
(object::set_enum): New.
|
||||||
|
|
||||||
|
2025-10-16 Ayappan Perumal <ayappap2@in.ibm.com>
|
||||||
|
|
||||||
|
* config/rs6000/aix.h (SUBTARGET_DRIVER_SELF_SPECS):
|
||||||
|
Error out when stack-protector option is used in AIX
|
||||||
|
as it is not supported on AIX
|
||||||
|
Approved By: Segher Boessenkool <segher@kernel.crashing.org>
|
||||||
|
|
||||||
|
2025-10-16 Richard Biener <rguenther@suse.de>
|
||||||
|
|
||||||
|
PR tree-optimization/122292
|
||||||
|
* tree-vect-loop.cc (vect_transform_reduction): Compute the
|
||||||
|
input vector type the same way the analysis phase does.
|
||||||
|
|
||||||
2025-10-15 Andrew MacLeod <amacleod@redhat.com>
|
2025-10-15 Andrew MacLeod <amacleod@redhat.com>
|
||||||
|
|
||||||
PR tree-optimization/121468
|
PR tree-optimization/121468
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
20251016
|
20251017
|
||||||
|
|
|
@ -1861,6 +1861,8 @@ OBJS = \
|
||||||
# Objects in libcommon.a, potentially used by all host binaries and with
|
# Objects in libcommon.a, potentially used by all host binaries and with
|
||||||
# no target dependencies.
|
# no target dependencies.
|
||||||
OBJS-libcommon = \
|
OBJS-libcommon = \
|
||||||
|
custom-sarif-properties/digraphs.o \
|
||||||
|
custom-sarif-properties/state-graphs.o \
|
||||||
diagnostic-global-context.o \
|
diagnostic-global-context.o \
|
||||||
diagnostics/buffering.o \
|
diagnostics/buffering.o \
|
||||||
diagnostics/changes.o \
|
diagnostics/changes.o \
|
||||||
|
@ -1880,7 +1882,6 @@ OBJS-libcommon = \
|
||||||
diagnostics/paths.o \
|
diagnostics/paths.o \
|
||||||
diagnostics/paths-output.o \
|
diagnostics/paths-output.o \
|
||||||
diagnostics/source-printing.o \
|
diagnostics/source-printing.o \
|
||||||
diagnostics/state-graphs.o \
|
|
||||||
diagnostics/state-graphs-to-dot.o \
|
diagnostics/state-graphs-to-dot.o \
|
||||||
diagnostics/selftest-context.o \
|
diagnostics/selftest-context.o \
|
||||||
diagnostics/selftest-logical-locations.o \
|
diagnostics/selftest-logical-locations.o \
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
2025-10-16 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
* ana-state-to-diagnostic-state.cc: Reimplement throughout to use
|
||||||
|
json::property instances found within custom_sarif_properties
|
||||||
|
throughout, rather than types in diagnostics::state_graphs.
|
||||||
|
* ana-state-to-diagnostic-state.h: Likewise.
|
||||||
|
* checker-event.cc: Likewise.
|
||||||
|
* sm-malloc.cc: Likewise.
|
||||||
|
|
||||||
2025-10-09 David Malcolm <dmalcolm@redhat.com>
|
2025-10-09 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
* access-diagram.cc: Update for renaming of fields of binding_key.
|
* access-diagram.cc: Update for renaming of fields of binding_key.
|
||||||
|
|
|
@ -39,38 +39,55 @@ along with GCC; see the file COPYING3. If not see
|
||||||
|
|
||||||
namespace ana {
|
namespace ana {
|
||||||
|
|
||||||
using namespace ::diagnostics::state_graphs;
|
namespace node_properties = custom_sarif_properties::state_graphs::node;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_wi_attr (state_node_ref state_node,
|
set_wi_attr (diagnostics::digraphs::node &state_node,
|
||||||
const char *attr_name,
|
const json::string_property &property,
|
||||||
const wide_int_ref &w,
|
const wide_int_ref &w,
|
||||||
signop sgn)
|
signop sgn)
|
||||||
{
|
{
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
pp_wide_int (&pp, w, sgn);
|
pp_wide_int (&pp, w, sgn);
|
||||||
state_node.set_attr (attr_name, pp_formatted_text (&pp));
|
state_node.set_property (property, pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_type_attr (state_node_ref state_node, const_tree type)
|
set_type_attr (diagnostics::digraphs::node &state_node,
|
||||||
|
const_tree type)
|
||||||
{
|
{
|
||||||
gcc_assert (type);
|
gcc_assert (type);
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
pp_format_decoder (&pp) = default_tree_printer;
|
pp_format_decoder (&pp) = default_tree_printer;
|
||||||
pp_printf (&pp, "%T", type);
|
pp_printf (&pp, "%T", type);
|
||||||
state_node.set_type (pp_formatted_text (&pp));
|
state_node.set_property (node_properties::type,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_bits_attr (state_node_ref state_node,
|
set_bits_attr (diagnostics::digraphs::node & state_node,
|
||||||
bit_range bits)
|
bit_range bits)
|
||||||
{
|
{
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
bits.dump_to_pp (&pp);
|
bits.dump_to_pp (&pp);
|
||||||
state_node.set_attr ("bits", pp_formatted_text (&pp));
|
state_node.set_property (node_properties::bits,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_value_attrs (diagnostics::digraphs::node &state_node,
|
||||||
|
const svalue &sval)
|
||||||
|
{
|
||||||
|
state_node.set_property (node_properties::value,
|
||||||
|
sval.to_json ());
|
||||||
|
pretty_printer pp;
|
||||||
|
pp_format_decoder (&pp) = default_tree_printer;
|
||||||
|
sval.dump_to_pp (&pp, true);
|
||||||
|
state_node.set_property (node_properties::value_str,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// class analyzer_state_graph : public diagnostics::digraphs::digraph
|
// class analyzer_state_graph : public diagnostics::digraphs::digraph
|
||||||
|
|
||||||
analyzer_state_graph::analyzer_state_graph (const program_state &state,
|
analyzer_state_graph::analyzer_state_graph (const program_state &state,
|
||||||
|
@ -141,34 +158,34 @@ analyzer_state_graph::analyzer_state_graph (const program_state &state,
|
||||||
|
|
||||||
/* Ensure we have a node for the dst region. This
|
/* Ensure we have a node for the dst region. This
|
||||||
could lead to additional pending edges. */
|
could lead to additional pending edges. */
|
||||||
auto dst_node = get_or_create_state_node (item.m_dst_reg);
|
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);
|
add_edge (nullptr, item.m_src_node, dst_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state_node_ref
|
diagnostics::digraphs::node &
|
||||||
analyzer_state_graph::get_or_create_state_node (const region ®)
|
analyzer_state_graph::get_or_create_state_node (const region ®)
|
||||||
{
|
{
|
||||||
auto existing = m_region_to_state_node_map.find (®);
|
auto existing = m_region_to_state_node_map.find (®);
|
||||||
if (existing != m_region_to_state_node_map.end ())
|
if (existing != m_region_to_state_node_map.end ())
|
||||||
return *existing->second;
|
return *existing->second;
|
||||||
|
|
||||||
auto ref = create_and_add_state_node (reg);
|
auto &state_node = create_and_add_state_node (reg);
|
||||||
m_region_to_state_node_map[®] = &ref.m_node;
|
m_region_to_state_node_map[®] = &state_node;
|
||||||
return ref;
|
return state_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
state_node_ref
|
diagnostics::digraphs::node &
|
||||||
analyzer_state_graph::create_and_add_state_node (const region ®)
|
analyzer_state_graph::create_and_add_state_node (const region ®)
|
||||||
{
|
{
|
||||||
auto node = create_state_node (reg);
|
auto node = create_state_node (reg);
|
||||||
|
|
||||||
state_node_ref result = *node;
|
diagnostics::digraphs::node &result = *node;
|
||||||
if (auto parent_reg = reg.get_parent_region ())
|
if (auto parent_reg = reg.get_parent_region ())
|
||||||
if (parent_reg->get_kind () != RK_ROOT)
|
if (parent_reg->get_kind () != RK_ROOT)
|
||||||
{
|
{
|
||||||
auto parent_state_node = get_or_create_state_node (*parent_reg);
|
auto &parent_state_node = get_or_create_state_node (*parent_reg);
|
||||||
parent_state_node.m_node.add_child (std::move (node));
|
parent_state_node.add_child (std::move (node));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
add_node (std::move (node));
|
add_node (std::move (node));
|
||||||
|
@ -264,19 +281,18 @@ analyzer_state_graph::make_node_id (const region ®)
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
analyzer_state_graph::
|
analyzer_state_graph::
|
||||||
make_state_node (diagnostics::state_graphs::node_kind kind,
|
make_state_node (enum node_properties::kind_t kind,
|
||||||
std::string id)
|
std::string id)
|
||||||
{
|
{
|
||||||
auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
|
auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
|
||||||
state_node_ref node_ref (*node);
|
node->set_property (node_properties::kind_prop, kind);
|
||||||
node_ref.set_node_kind (kind);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
analyzer_state_graph::
|
analyzer_state_graph::
|
||||||
make_memspace_state_node (const region ®,
|
make_memspace_state_node (const region ®,
|
||||||
diagnostics::state_graphs::node_kind kind)
|
enum node_properties::kind_t kind)
|
||||||
{
|
{
|
||||||
return make_state_node (kind, make_node_id (reg));
|
return make_state_node (kind, make_node_id (reg));
|
||||||
}
|
}
|
||||||
|
@ -296,7 +312,7 @@ analyzer_state_graph::create_state_node (const region ®)
|
||||||
const frame_region &frame_reg
|
const frame_region &frame_reg
|
||||||
= static_cast<const frame_region &> (reg);
|
= static_cast<const frame_region &> (reg);
|
||||||
|
|
||||||
node = make_state_node (diagnostics::state_graphs::node_kind::stack_frame,
|
node = make_state_node (node_properties::kind_t::stack_frame,
|
||||||
make_node_id (reg));
|
make_node_id (reg));
|
||||||
node->set_logical_loc
|
node->set_logical_loc
|
||||||
(m_logical_loc_mgr.key_from_tree (frame_reg.get_fndecl ()));
|
(m_logical_loc_mgr.key_from_tree (frame_reg.get_fndecl ()));
|
||||||
|
@ -304,58 +320,59 @@ analyzer_state_graph::create_state_node (const region ®)
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
pp_format_decoder (&pp) = default_tree_printer;
|
pp_format_decoder (&pp) = default_tree_printer;
|
||||||
pp_printf (&pp, "%E", frame_reg.get_fndecl ());
|
pp_printf (&pp, "%E", frame_reg.get_fndecl ());
|
||||||
node->set_attr (STATE_NODE_PREFIX, "function",
|
node->set_property (node_properties::function,
|
||||||
pp_formatted_text (&pp));
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RK_GLOBALS:
|
case RK_GLOBALS:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::globals);
|
node_properties::kind_t::globals);
|
||||||
break;
|
break;
|
||||||
case RK_CODE:
|
case RK_CODE:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::code);
|
node_properties::kind_t::code);
|
||||||
break;
|
break;
|
||||||
case RK_FUNCTION:
|
case RK_FUNCTION:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::function);
|
node_properties::kind_t::function);
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RK_STACK:
|
case RK_STACK:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::stack);
|
node_properties::kind_t::stack);
|
||||||
break;
|
break;
|
||||||
case RK_HEAP:
|
case RK_HEAP:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::heap_);
|
node_properties::kind_t::heap_);
|
||||||
break;
|
break;
|
||||||
case RK_THREAD_LOCAL:
|
case RK_THREAD_LOCAL:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::thread_local_);
|
node_properties::kind_t::thread_local_);
|
||||||
break;
|
break;
|
||||||
case RK_ROOT:
|
case RK_ROOT:
|
||||||
gcc_unreachable ();
|
gcc_unreachable ();
|
||||||
break;
|
break;
|
||||||
case RK_SYMBOLIC:
|
case RK_SYMBOLIC:
|
||||||
node = make_memspace_state_node (reg,
|
node = make_memspace_state_node (reg,
|
||||||
diagnostics::state_graphs::node_kind::other);
|
node_properties::kind_t::other);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RK_DECL:
|
case RK_DECL:
|
||||||
{
|
{
|
||||||
node = make_state_node (diagnostics::state_graphs::node_kind::variable,
|
node = make_state_node (node_properties::kind_t::variable,
|
||||||
make_node_id (reg));
|
make_node_id (reg));
|
||||||
const decl_region &decl_reg
|
const decl_region &decl_reg
|
||||||
= static_cast<const decl_region &> (reg);
|
= static_cast<const decl_region &> (reg);
|
||||||
state_node_ref node_ref (*node);
|
|
||||||
{
|
{
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
pp_format_decoder (&pp) = default_tree_printer;
|
pp_format_decoder (&pp) = default_tree_printer;
|
||||||
pp_printf (&pp, "%E", decl_reg.get_decl ());
|
pp_printf (&pp, "%E", decl_reg.get_decl ());
|
||||||
node_ref.set_name (pp_formatted_text (&pp));
|
node->set_property (node_properties::name,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
|
set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
|
||||||
}
|
}
|
||||||
|
@ -377,14 +394,15 @@ analyzer_state_graph::create_state_node (const region ®)
|
||||||
case RK_ERRNO:
|
case RK_ERRNO:
|
||||||
case RK_PRIVATE:
|
case RK_PRIVATE:
|
||||||
case RK_UNKNOWN:
|
case RK_UNKNOWN:
|
||||||
node = make_state_node (diagnostics::state_graphs::node_kind::other,
|
node = make_state_node (node_properties::kind_t::other,
|
||||||
make_node_id (reg));
|
make_node_id (reg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RK_HEAP_ALLOCATED:
|
case RK_HEAP_ALLOCATED:
|
||||||
case RK_ALLOCA:
|
case RK_ALLOCA:
|
||||||
node = make_memspace_state_node (reg,
|
node
|
||||||
diagnostics::state_graphs::node_kind::dynalloc_buffer);
|
= make_memspace_state_node (reg,
|
||||||
|
node_properties::kind_t::dynalloc_buffer);
|
||||||
set_attr_for_dynamic_extents (reg, *node);
|
set_attr_for_dynamic_extents (reg, *node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -425,9 +443,9 @@ create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
|
||||||
get_or_create_state_node (*reg);
|
get_or_create_state_node (*reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref = get_or_create_state_node (*cluster.get_base_region ());
|
auto &ref = get_or_create_state_node (*cluster.get_base_region ());
|
||||||
|
|
||||||
ref.m_node.add_child (create_state_node_for_conc_bindings (conc_bindings));
|
ref.add_child (create_state_node_for_conc_bindings (conc_bindings));
|
||||||
|
|
||||||
const region *typed_reg = cluster.get_base_region ();
|
const region *typed_reg = cluster.get_base_region ();
|
||||||
if (!typed_reg->get_type ())
|
if (!typed_reg->get_type ())
|
||||||
|
@ -455,23 +473,18 @@ create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
|
analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
|
||||||
{
|
{
|
||||||
auto node = make_state_node (diagnostics::state_graphs::node_kind::other,
|
auto node = make_state_node (node_properties::kind_t::other,
|
||||||
make_node_id ("concrete-bindings"));
|
make_node_id ("concrete-bindings"));
|
||||||
for (auto iter : conc_bindings)
|
for (auto iter : conc_bindings)
|
||||||
{
|
{
|
||||||
const bit_range bits = iter.first;
|
const bit_range bits = iter.first;
|
||||||
const svalue *sval = iter.second;
|
const svalue *sval = iter.second;
|
||||||
auto binding_state_node
|
auto binding_state_node
|
||||||
= make_state_node (diagnostics::state_graphs::node_kind::other,
|
= make_state_node (node_properties::kind_t::other,
|
||||||
make_node_id ("binding"));
|
make_node_id ("binding"));
|
||||||
set_bits_attr (*binding_state_node, bits);
|
set_bits_attr (*binding_state_node, bits);
|
||||||
{
|
gcc_assert (sval);
|
||||||
pretty_printer pp;
|
set_value_attrs (*binding_state_node, *sval);
|
||||||
pp_format_decoder (&pp) = default_tree_printer;
|
|
||||||
sval->dump_to_pp (&pp, true);
|
|
||||||
binding_state_node->set_attr (STATE_NODE_PREFIX, "value",
|
|
||||||
pp_formatted_text (&pp));
|
|
||||||
}
|
|
||||||
node->add_child (std::move (binding_state_node));
|
node->add_child (std::move (binding_state_node));
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
|
@ -496,27 +509,28 @@ analyzer_state_graph::get_bit_range_within_base_region (const region ®,
|
||||||
|
|
||||||
void
|
void
|
||||||
analyzer_state_graph::
|
analyzer_state_graph::
|
||||||
populate_state_node_for_typed_region (state_node_ref node,
|
populate_state_node_for_typed_region (diagnostics::digraphs::node &state_node,
|
||||||
const region ®,
|
const region ®,
|
||||||
const concrete_bindings_t &conc_bindings,
|
const concrete_bindings_t &conc_bindings,
|
||||||
bool create_all)
|
bool create_all)
|
||||||
{
|
{
|
||||||
const_tree reg_type = reg.get_type ();
|
const_tree reg_type = reg.get_type ();
|
||||||
gcc_assert (reg_type);
|
gcc_assert (reg_type);
|
||||||
set_type_attr (node, reg_type);
|
set_type_attr (state_node, reg_type);
|
||||||
|
|
||||||
bit_range bits (0, 0);
|
bit_range bits (0, 0);
|
||||||
if (get_bit_range_within_base_region (reg, bits))
|
if (get_bit_range_within_base_region (reg, bits))
|
||||||
{
|
{
|
||||||
set_bits_attr (node, bits);
|
set_bits_attr (state_node, bits);
|
||||||
|
|
||||||
auto search = conc_bindings.find (bits);
|
auto search = conc_bindings.find (bits);
|
||||||
if (search != conc_bindings.end ())
|
if (search != conc_bindings.end ())
|
||||||
{
|
{
|
||||||
const svalue *bound_sval = search->second;
|
const svalue *bound_sval = search->second;
|
||||||
node.set_json_attr ("value", bound_sval->to_json ());
|
gcc_assert (bound_sval);
|
||||||
|
set_value_attrs (state_node, *bound_sval);
|
||||||
if (const region *dst_reg = bound_sval->maybe_get_region ())
|
if (const region *dst_reg = bound_sval->maybe_get_region ())
|
||||||
m_pending_edges.push_back ({node, *dst_reg});
|
m_pending_edges.push_back ({state_node, *dst_reg});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,9 +569,10 @@ populate_state_node_for_typed_region (state_node_ref node,
|
||||||
{
|
{
|
||||||
auto child_state_node
|
auto child_state_node
|
||||||
= make_state_node
|
= make_state_node
|
||||||
(diagnostics::state_graphs::node_kind::element,
|
(node_properties::kind_t::element,
|
||||||
make_node_id (*child_reg));
|
make_node_id (*child_reg));
|
||||||
set_wi_attr (*child_state_node, "index", idx, UNSIGNED);
|
set_wi_attr (*child_state_node,
|
||||||
|
node_properties::index, idx, UNSIGNED);
|
||||||
|
|
||||||
// Recurse:
|
// Recurse:
|
||||||
gcc_assert (element_type);
|
gcc_assert (element_type);
|
||||||
|
@ -565,7 +580,7 @@ populate_state_node_for_typed_region (state_node_ref node,
|
||||||
*child_reg,
|
*child_reg,
|
||||||
conc_bindings,
|
conc_bindings,
|
||||||
create_all);
|
create_all);
|
||||||
node.m_node.add_child (std::move (child_state_node));
|
state_node.add_child (std::move (child_state_node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,11 +602,12 @@ populate_state_node_for_typed_region (state_node_ref node,
|
||||||
{
|
{
|
||||||
auto child_state_node
|
auto child_state_node
|
||||||
= make_state_node
|
= make_state_node
|
||||||
(diagnostics::state_graphs::node_kind::padding,
|
(node_properties::kind_t::padding,
|
||||||
make_node_id (*child_reg));
|
make_node_id (*child_reg));
|
||||||
set_wi_attr (*child_state_node, "num_bits",
|
set_wi_attr (*child_state_node,
|
||||||
|
node_properties::num_bits,
|
||||||
item.m_bit_range.m_size_in_bits, SIGNED);
|
item.m_bit_range.m_size_in_bits, SIGNED);
|
||||||
node.m_node.add_child (std::move (child_state_node));
|
state_node.add_child (std::move (child_state_node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -600,27 +616,27 @@ populate_state_node_for_typed_region (state_node_ref node,
|
||||||
= m_mgr.get_field_region (®,
|
= m_mgr.get_field_region (®,
|
||||||
const_cast<tree> (item.m_field));
|
const_cast<tree> (item.m_field));
|
||||||
if (show_child_state_node_for_child_region_p (*child_reg,
|
if (show_child_state_node_for_child_region_p (*child_reg,
|
||||||
conc_bindings,
|
conc_bindings,
|
||||||
create_all))
|
create_all))
|
||||||
{
|
{
|
||||||
auto child_state_node
|
auto child_state_node
|
||||||
= make_state_node
|
= make_state_node
|
||||||
(diagnostics::state_graphs::node_kind::field,
|
(node_properties::kind_t::field,
|
||||||
make_node_id (*child_reg));
|
make_node_id (*child_reg));
|
||||||
{
|
{
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
pp_format_decoder (&pp) = default_tree_printer;
|
pp_format_decoder (&pp) = default_tree_printer;
|
||||||
pp_printf (&pp, "%D", item.m_field);
|
pp_printf (&pp, "%D", item.m_field);
|
||||||
child_state_node->set_attr (STATE_NODE_PREFIX, "name",
|
child_state_node->set_property (node_properties::name,
|
||||||
pp_formatted_text (&pp));
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse:
|
// Recurse:
|
||||||
populate_state_node_for_typed_region (*child_state_node,
|
populate_state_node_for_typed_region (*child_state_node,
|
||||||
*child_reg,
|
*child_reg,
|
||||||
conc_bindings,
|
conc_bindings,
|
||||||
create_all);
|
create_all);
|
||||||
node.m_node.add_child (std::move (child_state_node));
|
state_node.add_child (std::move (child_state_node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -630,8 +646,9 @@ populate_state_node_for_typed_region (state_node_ref node,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
analyzer_state_graph::set_attr_for_dynamic_extents (const region ®,
|
analyzer_state_graph::
|
||||||
state_node_ref node_ref)
|
set_attr_for_dynamic_extents (const region ®,
|
||||||
|
diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
const svalue *sval = m_state.m_region_model->get_dynamic_extents (®);
|
const svalue *sval = m_state.m_region_model->get_dynamic_extents (®);
|
||||||
if (sval)
|
if (sval)
|
||||||
|
@ -642,15 +659,16 @@ analyzer_state_graph::set_attr_for_dynamic_extents (const region ®,
|
||||||
pp_wide_int (&pp, wi::to_wide (cst), UNSIGNED);
|
pp_wide_int (&pp, wi::to_wide (cst), UNSIGNED);
|
||||||
else
|
else
|
||||||
sval->dump_to_pp (&pp, true);
|
sval->dump_to_pp (&pp, true);
|
||||||
node_ref.set_attr ("dynamic-extents", pp_formatted_text (&pp));
|
state_node.set_property (state_node_properties::dynamic_extents,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
analyzer_state_graph::
|
analyzer_state_graph::
|
||||||
show_child_state_node_for_child_region_p (const region ®,
|
show_child_state_node_for_child_region_p (const region ®,
|
||||||
const concrete_bindings_t &conc_bindings,
|
const concrete_bindings_t &conc_bindings,
|
||||||
bool create_all)
|
bool create_all)
|
||||||
{
|
{
|
||||||
if (create_all)
|
if (create_all)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -23,34 +23,38 @@ along with GCC; see the file COPYING3. If not see
|
||||||
|
|
||||||
#include "diagnostics/state-graphs.h"
|
#include "diagnostics/state-graphs.h"
|
||||||
#include "tree-logical-location.h"
|
#include "tree-logical-location.h"
|
||||||
|
#include "custom-sarif-properties/state-graphs.h"
|
||||||
|
|
||||||
namespace ana {
|
namespace ana {
|
||||||
|
|
||||||
|
namespace state_node_properties = custom_sarif_properties::state_graphs::node;
|
||||||
|
|
||||||
class analyzer_state_graph : public diagnostics::digraphs::digraph
|
class analyzer_state_graph : public diagnostics::digraphs::digraph
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
analyzer_state_graph (const program_state &state,
|
analyzer_state_graph (const program_state &state,
|
||||||
const extrinsic_state &ext_state);
|
const extrinsic_state &ext_state);
|
||||||
diagnostics::state_graphs::state_node_ref
|
diagnostics::digraphs::node &
|
||||||
get_or_create_state_node (const region ®);
|
get_or_create_state_node (const region ®);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct pending_edge
|
struct pending_edge
|
||||||
{
|
{
|
||||||
diagnostics::state_graphs::state_node_ref m_src_node;
|
diagnostics::digraphs::node & m_src_node;
|
||||||
const region &m_dst_reg;
|
const region &m_dst_reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
diagnostics::state_graphs::state_node_ref
|
diagnostics::digraphs::node &
|
||||||
create_and_add_state_node (const region ®);
|
create_and_add_state_node (const region ®);
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
make_state_node (diagnostics::state_graphs::node_kind kind,
|
make_state_node (enum state_node_properties::kind_t kind,
|
||||||
std::string id);
|
std::string id);
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
make_memspace_state_node (const region ®,
|
make_memspace_state_node (const region ®,
|
||||||
enum diagnostics::state_graphs::node_kind kind);
|
enum state_node_properties::kind_t kind);
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<diagnostics::digraphs::node>
|
||||||
create_state_node (const region ®);
|
create_state_node (const region ®);
|
||||||
|
@ -71,14 +75,14 @@ private:
|
||||||
bit_range &out);
|
bit_range &out);
|
||||||
|
|
||||||
void
|
void
|
||||||
populate_state_node_for_typed_region (diagnostics::state_graphs::state_node_ref,
|
populate_state_node_for_typed_region (diagnostics::digraphs::node &,
|
||||||
const region ®,
|
const region ®,
|
||||||
const concrete_bindings_t &conc_bindings,
|
const concrete_bindings_t &conc_bindings,
|
||||||
bool create_all);
|
bool create_all);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_attr_for_dynamic_extents (const region ®,
|
set_attr_for_dynamic_extents (const region ®,
|
||||||
diagnostics::state_graphs::state_node_ref);
|
diagnostics::digraphs::node &);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
show_child_state_node_for_child_region_p (const region ®,
|
show_child_state_node_for_child_region_p (const region ®,
|
||||||
|
@ -95,7 +99,8 @@ private:
|
||||||
const program_state &m_state;
|
const program_state &m_state;
|
||||||
const extrinsic_state &m_ext_state;
|
const extrinsic_state &m_ext_state;
|
||||||
region_model_manager &m_mgr;
|
region_model_manager &m_mgr;
|
||||||
std::map<const region *, diagnostics::digraphs::node *> m_region_to_state_node_map;
|
std::map<const region *,
|
||||||
|
diagnostics::digraphs::node *> m_region_to_state_node_map;
|
||||||
std::map<const region *, tree> m_types_for_untyped_regions;
|
std::map<const region *, tree> m_types_for_untyped_regions;
|
||||||
unsigned m_next_id;
|
unsigned m_next_id;
|
||||||
std::vector<pending_edge> m_pending_edges;
|
std::vector<pending_edge> m_pending_edges;
|
||||||
|
|
|
@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "tree-logical-location.h"
|
#include "tree-logical-location.h"
|
||||||
#include "diagnostics/sarif-sink.h"
|
#include "diagnostics/sarif-sink.h"
|
||||||
#include "diagnostics/state-graphs.h"
|
#include "diagnostics/state-graphs.h"
|
||||||
|
#include "custom-sarif-properties/state-graphs.h"
|
||||||
|
|
||||||
#include "analyzer/analyzer-logging.h"
|
#include "analyzer/analyzer-logging.h"
|
||||||
#include "analyzer/sm.h"
|
#include "analyzer/sm.h"
|
||||||
|
@ -242,9 +243,11 @@ checker_event::maybe_make_diagnostic_state_graph (bool debug) const
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
text_art::theme *theme = global_dc->get_diagram_theme ();
|
text_art::theme *theme = global_dc->get_diagram_theme ();
|
||||||
text_art::dump_to_pp (*state, theme, &pp);
|
text_art::dump_to_pp (*state, theme, &pp);
|
||||||
result->set_attr (STATE_GRAPH_PREFIX,
|
const json::string_property program_state_property
|
||||||
"analyzer/program_state/",
|
(custom_sarif_properties::state_graphs::graph::prefix,
|
||||||
pp_formatted_text (&pp));
|
"analyzer/program_state/");
|
||||||
|
result->set_property (program_state_property,
|
||||||
|
pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -2735,7 +2735,7 @@ 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);
|
smap->set_state (model, new_ptr_sval, m_free.m_nonnull, nullptr, ext_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum diagnostics::state_graphs::node_dynalloc_state
|
static enum custom_sarif_properties::state_graphs::node::dynalloc_state_t
|
||||||
get_dynalloc_state_for_state (enum resource_state rs)
|
get_dynalloc_state_for_state (enum resource_state rs)
|
||||||
{
|
{
|
||||||
switch (rs)
|
switch (rs)
|
||||||
|
@ -2746,17 +2746,17 @@ get_dynalloc_state_for_state (enum resource_state rs)
|
||||||
case RS_NULL:
|
case RS_NULL:
|
||||||
case RS_NON_HEAP:
|
case RS_NON_HEAP:
|
||||||
case RS_STOP:
|
case RS_STOP:
|
||||||
return diagnostics::state_graphs::node_dynalloc_state::unknown;
|
return state_node_properties::dynalloc_state_t::unknown;
|
||||||
|
|
||||||
case RS_ASSUMED_NON_NULL:
|
case RS_ASSUMED_NON_NULL:
|
||||||
return diagnostics::state_graphs::node_dynalloc_state::nonnull;
|
return state_node_properties::dynalloc_state_t::nonnull;
|
||||||
|
|
||||||
case RS_UNCHECKED:
|
case RS_UNCHECKED:
|
||||||
return diagnostics::state_graphs::node_dynalloc_state::unchecked;
|
return state_node_properties::dynalloc_state_t::unchecked;
|
||||||
case RS_NONNULL:
|
case RS_NONNULL:
|
||||||
return diagnostics::state_graphs::node_dynalloc_state::nonnull;
|
return state_node_properties::dynalloc_state_t::nonnull;
|
||||||
case RS_FREED:
|
case RS_FREED:
|
||||||
return diagnostics::state_graphs::node_dynalloc_state::freed;
|
return state_node_properties::dynalloc_state_t::freed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,24 +2768,23 @@ add_state_to_state_graph (analyzer_state_graph &out_state_graph,
|
||||||
{
|
{
|
||||||
if (const region *reg = sval.maybe_get_region ())
|
if (const region *reg = sval.maybe_get_region ())
|
||||||
{
|
{
|
||||||
auto reg_node = out_state_graph.get_or_create_state_node (*reg);
|
auto ®_node = out_state_graph.get_or_create_state_node (*reg);
|
||||||
auto alloc_state = as_a_allocation_state (state);
|
auto alloc_state = as_a_allocation_state (state);
|
||||||
gcc_assert (alloc_state);
|
gcc_assert (alloc_state);
|
||||||
|
|
||||||
reg_node.set_dynalloc_state
|
reg_node.set_property (state_node_properties::dynalloc_state_prop,
|
||||||
(get_dynalloc_state_for_state (alloc_state->m_rs));
|
get_dynalloc_state_for_state (alloc_state->m_rs));
|
||||||
|
|
||||||
if (alloc_state->m_deallocators)
|
if (alloc_state->m_deallocators)
|
||||||
{
|
{
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
alloc_state->m_deallocators->dump_to_pp (&pp);
|
alloc_state->m_deallocators->dump_to_pp (&pp);
|
||||||
reg_node.m_node.set_attr (STATE_NODE_PREFIX,
|
reg_node.set_property (state_node_properties::expected_deallocators,
|
||||||
"expected-deallocators",
|
pp_formatted_text (&pp));
|
||||||
pp_formatted_text (&pp));
|
|
||||||
}
|
}
|
||||||
if (alloc_state->m_deallocator)
|
if (alloc_state->m_deallocator)
|
||||||
reg_node.m_node.set_attr (STATE_NODE_PREFIX,
|
reg_node.set_property (state_node_properties::deallocator,
|
||||||
"deallocator",
|
alloc_state->m_deallocator->m_name);
|
||||||
alloc_state->m_deallocator->m_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,13 @@
|
||||||
__asm__ volatile \
|
__asm__ volatile \
|
||||||
("{tileloaddrs\t(%0,%1,1), %%tmm"#tdst \
|
("{tileloaddrs\t(%0,%1,1), %%tmm"#tdst \
|
||||||
"|tileloaddrs\t%%tmm"#tdst", [%0+%1*1]}" \
|
"|tileloaddrs\t%%tmm"#tdst", [%0+%1*1]}" \
|
||||||
:: "r" ((const void*) (base)), "r" ((long) (stride)))
|
:: "r" ((const void*) (base)), "r" ((__PTRDIFF_TYPE__) (stride)))
|
||||||
|
|
||||||
#define _tile_loaddrst1_internal(tdst, base, stride) \
|
#define _tile_loaddrst1_internal(tdst, base, stride) \
|
||||||
__asm__ volatile \
|
__asm__ volatile \
|
||||||
("{tileloaddrst1\t(%0,%1,1), %%tmm"#tdst \
|
("{tileloaddrst1\t(%0,%1,1), %%tmm"#tdst \
|
||||||
"|tileloaddrst1\t%%tmm"#tdst", [%0+%1*1]}" \
|
"|tileloaddrst1\t%%tmm"#tdst", [%0+%1*1]}" \
|
||||||
:: "r" ((const void*) (base)), "r" ((long) (stride)))
|
:: "r" ((const void*) (base)), "r" ((__PTRDIFF_TYPE__) (stride)))
|
||||||
|
|
||||||
#define _tile_loaddrs(tdst, base, stride) \
|
#define _tile_loaddrs(tdst, base, stride) \
|
||||||
_tile_loaddrs_internal(tdst, base, stride)
|
_tile_loaddrs_internal(tdst, base, stride)
|
||||||
|
|
|
@ -36891,7 +36891,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
|
||||||
"depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;;
|
"depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;;
|
||||||
"gccdepdir":C)
|
"gccdepdir":C)
|
||||||
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
|
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
|
||||||
for lang in $subdirs c-family common analyzer diagnostics text-art rtl-ssa sym-exec
|
for lang in $subdirs c-family common analyzer custom-sarif-properties diagnostics text-art rtl-ssa sym-exec
|
||||||
do
|
do
|
||||||
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
|
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
|
||||||
done ;;
|
done ;;
|
||||||
|
|
|
@ -1368,7 +1368,7 @@ AC_CHECK_HEADERS(ext/hash_map)
|
||||||
ZW_CREATE_DEPDIR
|
ZW_CREATE_DEPDIR
|
||||||
AC_CONFIG_COMMANDS([gccdepdir],[
|
AC_CONFIG_COMMANDS([gccdepdir],[
|
||||||
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
|
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
|
||||||
for lang in $subdirs c-family common analyzer diagnostics text-art rtl-ssa sym-exec
|
for lang in $subdirs c-family common analyzer custom-sarif-properties diagnostics text-art rtl-ssa sym-exec
|
||||||
do
|
do
|
||||||
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
|
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
|
||||||
done], [subdirs="$subdirs" ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR])
|
done], [subdirs="$subdirs" ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR])
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Extra properties for digraphs in SARIF property bags.
|
||||||
|
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/>. */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "custom-sarif-properties/digraphs.h"
|
||||||
|
|
||||||
|
const json::string_property custom_sarif_properties::digraphs::digraph::kind
|
||||||
|
("gcc/digraphs/graph/kind");
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* Extra properties for digraphs in SARIF property bags.
|
||||||
|
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_CUSTOM_SARIF_PROPERTIES_DIGRAPHS_H
|
||||||
|
#define GCC_CUSTOM_SARIF_PROPERTIES_DIGRAPHS_H
|
||||||
|
|
||||||
|
/* SARIF property names relating to digraphs. */
|
||||||
|
|
||||||
|
namespace custom_sarif_properties {
|
||||||
|
namespace digraphs {
|
||||||
|
namespace digraph {
|
||||||
|
/* A hint about the kind of graph we have,
|
||||||
|
and thus what kinds of nodes and edges to expect. */
|
||||||
|
extern const json::string_property kind;
|
||||||
|
// string; values: "cfg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! GCC_CUSTOM_SARIF_PROPERTIES_DIGRAPHS_H */
|
|
@ -0,0 +1,161 @@
|
||||||
|
/* Properties for capturing state graphs in SARIF property bags.
|
||||||
|
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/>. */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "custom-sarif-properties/state-graphs.h"
|
||||||
|
|
||||||
|
/* graph. */
|
||||||
|
namespace graph = custom_sarif_properties::state_graphs::graph;
|
||||||
|
#define STATE_GRAPH_PREFIX "gcc/diagnostic_state_graph/"
|
||||||
|
const char *const graph::prefix = STATE_GRAPH_PREFIX;
|
||||||
|
#undef STATE_GRAPH_PREFIX
|
||||||
|
|
||||||
|
/* node. */
|
||||||
|
namespace node = custom_sarif_properties::state_graphs::node;
|
||||||
|
#define STATE_NODE_PREFIX "gcc/diagnostic_state_node/"
|
||||||
|
|
||||||
|
const json::enum_property<enum node::kind_t>
|
||||||
|
node::kind_prop (STATE_NODE_PREFIX "kind");
|
||||||
|
|
||||||
|
const json::string_property node::function (STATE_NODE_PREFIX "function");
|
||||||
|
|
||||||
|
const json::string_property node::dynamic_extents
|
||||||
|
(STATE_NODE_PREFIX "dynamic-extents");
|
||||||
|
|
||||||
|
const json::string_property node::name (STATE_NODE_PREFIX "name");
|
||||||
|
const json::string_property node::type (STATE_NODE_PREFIX "type");
|
||||||
|
const json::json_property node::value (STATE_NODE_PREFIX "value");
|
||||||
|
const json::string_property node::value_str (STATE_NODE_PREFIX "value_str");
|
||||||
|
|
||||||
|
const json::string_property node::index (STATE_NODE_PREFIX "index");
|
||||||
|
|
||||||
|
const json::string_property node::bits (STATE_NODE_PREFIX "bits");
|
||||||
|
|
||||||
|
const json::string_property node::num_bits (STATE_NODE_PREFIX "num_bits");
|
||||||
|
|
||||||
|
const json::string_property node::deallocator (STATE_NODE_PREFIX "deallocator");
|
||||||
|
|
||||||
|
const json::string_property node::expected_deallocators
|
||||||
|
(STATE_NODE_PREFIX "expected-deallocators");
|
||||||
|
|
||||||
|
const json::enum_property<enum node::dynalloc_state_t>
|
||||||
|
node::dynalloc_state_prop (STATE_NODE_PREFIX "dynalloc-state");
|
||||||
|
|
||||||
|
#undef STATE_NODE_PREFIX
|
||||||
|
|
||||||
|
|
||||||
|
/* edge. */
|
||||||
|
namespace edge_props = custom_sarif_properties::state_graphs::edge;
|
||||||
|
#define STATE_EDGE_PREFIX "gcc/diagnostic_state_edge/"
|
||||||
|
extern const char *const edge_props::prefix = STATE_EDGE_PREFIX;
|
||||||
|
#undef STATE_EDGE_PREFIX
|
||||||
|
|
||||||
|
// Traits for enum node:kind_t
|
||||||
|
|
||||||
|
namespace json {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
enum node::kind_t
|
||||||
|
json::enum_traits<enum node::kind_t>::get_unknown_value ()
|
||||||
|
{
|
||||||
|
return node::kind_t::other;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const node_kind_strs[] = {
|
||||||
|
"globals",
|
||||||
|
"code",
|
||||||
|
"function",
|
||||||
|
"stack",
|
||||||
|
"stack-frame",
|
||||||
|
"heap",
|
||||||
|
"thread-local",
|
||||||
|
"dynalloc-buffer",
|
||||||
|
"variable",
|
||||||
|
"field",
|
||||||
|
"padding",
|
||||||
|
"element",
|
||||||
|
"other",
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
json::enum_traits<enum node::kind_t>::
|
||||||
|
maybe_get_value_from_string (const char *str,
|
||||||
|
enum_t &out)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE (node_kind_strs); ++i)
|
||||||
|
if (!strcmp (node_kind_strs[i], str))
|
||||||
|
{
|
||||||
|
out = static_cast<enum_t> (i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
const char *
|
||||||
|
json::enum_traits<enum node::kind_t>::get_string_for_value (enum_t value)
|
||||||
|
{
|
||||||
|
return node_kind_strs[static_cast<int> (value)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traits for enum node:dynalloc_state_t
|
||||||
|
|
||||||
|
template<>
|
||||||
|
enum node::dynalloc_state_t
|
||||||
|
json::enum_traits<enum node::dynalloc_state_t>::get_unknown_value ()
|
||||||
|
{
|
||||||
|
return node::dynalloc_state_t::unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const dynalloc_state_strs[] = {
|
||||||
|
"unknown",
|
||||||
|
"nonnull",
|
||||||
|
"unchecked",
|
||||||
|
"freed"
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
json::enum_traits<enum node::dynalloc_state_t>::
|
||||||
|
maybe_get_value_from_string (const char *str,
|
||||||
|
enum_t &out)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE (dynalloc_state_strs); ++i)
|
||||||
|
if (!strcmp (dynalloc_state_strs[i], str))
|
||||||
|
{
|
||||||
|
out = static_cast<enum_t> (i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
const char *
|
||||||
|
json::enum_traits<enum node::dynalloc_state_t>::
|
||||||
|
get_string_for_value (enum_t value)
|
||||||
|
{
|
||||||
|
return dynalloc_state_strs[static_cast <size_t> (value)];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace json
|
|
@ -0,0 +1,98 @@
|
||||||
|
/* Properties for capturing state graphs in SARIF property bags.
|
||||||
|
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/>. */
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
#ifndef GCC_DIAGNOSTICS_SARIF_PROPERTIES_STATE_GRAPHS_H
|
||||||
|
#define GCC_DIAGNOSTICS_SARIF_PROPERTIES_STATE_GRAPHS_H
|
||||||
|
|
||||||
|
/* SARIF property names relating to GCC's CFGs. */
|
||||||
|
|
||||||
|
namespace custom_sarif_properties {
|
||||||
|
namespace state_graphs {
|
||||||
|
namespace graph {
|
||||||
|
extern const char *const prefix;
|
||||||
|
}
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
enum class kind_t
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class dynalloc_state_t
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
nonnull,
|
||||||
|
unchecked,
|
||||||
|
freed
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const json::enum_property<enum kind_t> kind_prop;
|
||||||
|
|
||||||
|
extern const json::string_property function;
|
||||||
|
extern const json::string_property dynamic_extents;
|
||||||
|
extern const json::string_property name;
|
||||||
|
extern const json::string_property type;
|
||||||
|
/* The value of a memory region, expressed as a json::value. */
|
||||||
|
extern const json::json_property value;
|
||||||
|
/* The value of a memory region, expressed as a string. */
|
||||||
|
extern const json::string_property value_str;
|
||||||
|
|
||||||
|
/* For element nodes, the index within the array. */
|
||||||
|
extern const json::string_property index;
|
||||||
|
|
||||||
|
/* The range of bits or bytes within the base region. */
|
||||||
|
extern const json::string_property bits;
|
||||||
|
|
||||||
|
/* The size of a padding region. */
|
||||||
|
extern const json::string_property num_bits;
|
||||||
|
|
||||||
|
extern const json::string_property deallocator;
|
||||||
|
extern const json::string_property expected_deallocators;
|
||||||
|
extern const json::enum_property<enum dynalloc_state_t>
|
||||||
|
dynalloc_state_prop;
|
||||||
|
}
|
||||||
|
namespace edge {
|
||||||
|
extern const char *const prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! GCC_DIAGNOSTICS_SARIF_PROPERTIES_STATE_GRAPHS_H */
|
|
@ -46,7 +46,6 @@ run_diagnostics_selftests ()
|
||||||
sarif_sink_cc_tests ();
|
sarif_sink_cc_tests ();
|
||||||
digraphs_cc_tests ();
|
digraphs_cc_tests ();
|
||||||
output_spec_cc_tests ();
|
output_spec_cc_tests ();
|
||||||
state_graphs_cc_tests ();
|
|
||||||
lazy_paths_cc_tests ();
|
lazy_paths_cc_tests ();
|
||||||
paths_output_cc_tests ();
|
paths_output_cc_tests ();
|
||||||
changes_cc_tests ();
|
changes_cc_tests ();
|
||||||
|
|
|
@ -44,7 +44,6 @@ extern void paths_output_cc_tests ();
|
||||||
extern void sarif_sink_cc_tests ();
|
extern void sarif_sink_cc_tests ();
|
||||||
extern void selftest_logical_locations_cc_tests ();
|
extern void selftest_logical_locations_cc_tests ();
|
||||||
extern void source_printing_cc_tests ();
|
extern void source_printing_cc_tests ();
|
||||||
extern void state_graphs_cc_tests ();
|
|
||||||
|
|
||||||
} /* end of namespace diagnostics::selftest. */
|
} /* end of namespace diagnostics::selftest. */
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,15 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "graphviz.h"
|
#include "graphviz.h"
|
||||||
#include "diagnostics/digraphs.h"
|
#include "diagnostics/digraphs.h"
|
||||||
#include "diagnostics/sarif-sink.h"
|
#include "diagnostics/sarif-sink.h"
|
||||||
|
#include "custom-sarif-properties/digraphs.h"
|
||||||
|
|
||||||
#include "selftest.h"
|
using digraph_object = diagnostics::digraphs::object;
|
||||||
|
|
||||||
using digraph = diagnostics::digraphs::digraph;
|
using digraph = diagnostics::digraphs::digraph;
|
||||||
using digraph_node = diagnostics::digraphs::node;
|
using digraph_node = diagnostics::digraphs::node;
|
||||||
using digraph_edge = diagnostics::digraphs::edge;
|
using digraph_edge = diagnostics::digraphs::edge;
|
||||||
|
|
||||||
|
namespace properties = custom_sarif_properties::digraphs;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class conversion_to_dot
|
class conversion_to_dot
|
||||||
|
@ -171,66 +173,145 @@ conversion_to_dot::has_edges_p (const digraph_node &input_node)
|
||||||
|
|
||||||
// class object
|
// class object
|
||||||
|
|
||||||
|
/* String properties. */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
diagnostics::digraphs::object::
|
digraph_object::get_property (const json::string_property &property) const
|
||||||
get_attr (const char *key_prefix, const char *key) const
|
|
||||||
{
|
{
|
||||||
if (!m_property_bag)
|
if (!m_property_bag)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
std::string prefixed_key = std::string (key_prefix) + key;
|
if (json::value *jv = m_property_bag->get (property.m_key.get ()))
|
||||||
if (json::value *jv = m_property_bag->get (prefixed_key.c_str ()))
|
|
||||||
if (json::string *jstr = jv->dyn_cast_string ())
|
if (json::string *jstr = jv->dyn_cast_string ())
|
||||||
return jstr->get_string ();
|
return jstr->get_string ();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
diagnostics::digraphs::object::
|
digraph_object::set_property (const json::string_property &property,
|
||||||
set_attr (const char *key_prefix, const char *key, const char *value)
|
const char *utf8_value)
|
||||||
{
|
{
|
||||||
set_json_attr (key_prefix, key, std::make_unique<json::string> (value));
|
auto &bag = ensure_property_bag ();
|
||||||
|
bag.set_string (property.m_key.get (), utf8_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integer properties. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
digraph_object::maybe_get_property (const json::integer_property &property,
|
||||||
|
long &out_value) const
|
||||||
|
{
|
||||||
|
if (!m_property_bag)
|
||||||
|
return false;
|
||||||
|
if (json::value *jv = m_property_bag->get (property.m_key.get ()))
|
||||||
|
if (json::integer_number *jnum = jv->dyn_cast_integer_number ())
|
||||||
|
{
|
||||||
|
out_value = jnum->get ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
diagnostics::digraphs::object::
|
digraph_object::set_property (const json::integer_property &property, long value)
|
||||||
set_json_attr (const char *key_prefix, const char *key, std::unique_ptr<json::value> value)
|
{
|
||||||
|
auto &bag = ensure_property_bag ();
|
||||||
|
bag.set_integer (property.m_key.get (), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bool properties. */
|
||||||
|
void
|
||||||
|
digraph_object::set_property (const json::bool_property &property, bool value)
|
||||||
|
{
|
||||||
|
auto &bag = ensure_property_bag ();
|
||||||
|
bag.set_bool (property.m_key.get (), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
tristate
|
||||||
|
digraph_object::
|
||||||
|
get_property_as_tristate (const json::bool_property &property) const
|
||||||
|
{
|
||||||
|
if (m_property_bag)
|
||||||
|
{
|
||||||
|
if (json::value *jv = m_property_bag->get (property.m_key.get ()))
|
||||||
|
switch (jv->get_kind ())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case json::JSON_TRUE:
|
||||||
|
return tristate (true);
|
||||||
|
case json::JSON_FALSE:
|
||||||
|
return tristate (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tristate::unknown ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Array-of-string properties. */
|
||||||
|
json::array *
|
||||||
|
digraph_object::get_property (const json::array_of_string_property &property) const
|
||||||
|
{
|
||||||
|
if (m_property_bag)
|
||||||
|
if (json::value *jv = m_property_bag->get (property.m_key.get ()))
|
||||||
|
if (json::array *arr = jv->dyn_cast_array ())
|
||||||
|
return arr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* json::value properties. */
|
||||||
|
const json::value *
|
||||||
|
digraph_object::get_property (const json::json_property &property) const
|
||||||
|
{
|
||||||
|
if (m_property_bag)
|
||||||
|
return m_property_bag->get (property.m_key.get ());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
digraph_object::set_property (const json::json_property &property,
|
||||||
|
std::unique_ptr<json::value> value)
|
||||||
|
{
|
||||||
|
auto &bag = ensure_property_bag ();
|
||||||
|
bag.set (property.m_key.get (), std::move (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
json::object &
|
||||||
|
digraph_object::ensure_property_bag ()
|
||||||
{
|
{
|
||||||
std::string prefixed_key = std::string (key_prefix) + key;
|
|
||||||
if (!m_property_bag)
|
if (!m_property_bag)
|
||||||
m_property_bag = std::make_unique<json::object> ();
|
m_property_bag = std::make_unique<sarif_property_bag> ( );
|
||||||
m_property_bag->set (prefixed_key.c_str (), std::move (value));
|
return *m_property_bag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// class digraph
|
// class digraph
|
||||||
|
|
||||||
DEBUG_FUNCTION void
|
DEBUG_FUNCTION void
|
||||||
diagnostics::digraphs::digraph::dump () const
|
digraph::dump () const
|
||||||
{
|
{
|
||||||
make_json_sarif_graph ()->dump ();
|
make_json_sarif_graph ()->dump ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<json::object>
|
std::unique_ptr<json::object>
|
||||||
diagnostics::digraphs::digraph::make_json_sarif_graph () const
|
digraph::make_json_sarif_graph () const
|
||||||
{
|
{
|
||||||
return make_sarif_graph (*this, nullptr, nullptr);
|
return make_sarif_graph (*this, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<dot::graph>
|
std::unique_ptr<dot::graph>
|
||||||
diagnostics::digraphs::digraph::make_dot_graph () const
|
digraph::make_dot_graph () const
|
||||||
{
|
{
|
||||||
conversion_to_dot to_dot;
|
conversion_to_dot converter;
|
||||||
return to_dot.make_dot_graph_from_diagnostic_graph (*this);
|
return converter.make_dot_graph_from_diagnostic_graph (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::digraph>
|
std::unique_ptr<digraph>
|
||||||
diagnostics::digraphs::digraph::clone () const
|
digraph::clone () const
|
||||||
{
|
{
|
||||||
auto result = std::make_unique<diagnostics::digraphs::digraph> ();
|
auto result = std::make_unique<diagnostics::digraphs::digraph> ();
|
||||||
|
|
||||||
if (get_property_bag ())
|
if (get_property_bag ())
|
||||||
result->set_property_bag (get_property_bag ()->clone_as_object ());
|
result->set_property_bag (get_property_bag ()->clone_as_object ());
|
||||||
|
|
||||||
std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> node_mapping;
|
std::map<digraph_node *, digraph_node *> node_mapping;
|
||||||
|
|
||||||
for (auto &iter : m_nodes)
|
for (auto &iter : m_nodes)
|
||||||
result->add_node (iter->clone (*result, node_mapping));
|
result->add_node (iter->clone (*result, node_mapping));
|
||||||
|
@ -241,10 +322,10 @@ diagnostics::digraphs::digraph::clone () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
diagnostics::digraphs::digraph::add_edge (const char *id,
|
digraph::add_edge (const char *id,
|
||||||
node &src_node,
|
node &src_node,
|
||||||
node &dst_node,
|
node &dst_node,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
auto e = std::make_unique<digraph_edge> (*this,
|
auto e = std::make_unique<digraph_edge> (*this,
|
||||||
id,
|
id,
|
||||||
|
@ -263,7 +344,7 @@ diagnostics::digraphs::digraph::add_edge (const char *id,
|
||||||
to edges by id (SARIF 2.1.0's §3.43.2 edgeId property). */
|
to edges by id (SARIF 2.1.0's §3.43.2 edgeId property). */
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
diagnostics::digraphs::digraph::make_edge_id (const char *edge_id)
|
digraph::make_edge_id (const char *edge_id)
|
||||||
{
|
{
|
||||||
/* If we have an id, use it. */
|
/* If we have an id, use it. */
|
||||||
if (edge_id)
|
if (edge_id)
|
||||||
|
@ -284,27 +365,38 @@ diagnostics::digraphs::digraph::make_edge_id (const char *edge_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
digraph::get_graph_kind () const
|
||||||
|
{
|
||||||
|
return get_property (properties::digraph::kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
digraph::set_graph_kind (const char *kind)
|
||||||
|
{
|
||||||
|
set_property (properties::digraph::kind, kind);
|
||||||
|
}
|
||||||
|
|
||||||
// class node
|
// class node
|
||||||
|
|
||||||
DEBUG_FUNCTION void
|
DEBUG_FUNCTION void
|
||||||
diagnostics::digraphs::node::dump () const
|
digraph_node::dump () const
|
||||||
{
|
{
|
||||||
to_json_sarif_node ()->dump ();
|
to_json_sarif_node ()->dump ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<json::object>
|
std::unique_ptr<json::object>
|
||||||
diagnostics::digraphs::node::to_json_sarif_node () const
|
digraph_node::to_json_sarif_node () const
|
||||||
{
|
{
|
||||||
return make_sarif_node (*this, nullptr, nullptr);
|
return make_sarif_node (*this, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<diagnostics::digraphs::node>
|
std::unique_ptr<digraph_node>
|
||||||
diagnostics::digraphs::node::clone (digraph &new_graph,
|
digraph_node::clone (digraph &new_graph,
|
||||||
std::map<node *, node *> &node_mapping) const
|
std::map<node *, node *> &node_mapping) const
|
||||||
{
|
{
|
||||||
auto result
|
auto result
|
||||||
= std::make_unique<diagnostics::digraphs::node> (new_graph,
|
= std::make_unique<digraph_node> (new_graph, get_id ());
|
||||||
get_id ());
|
|
||||||
node_mapping.insert ({const_cast <node *> (this), result.get ()});
|
node_mapping.insert ({const_cast <node *> (this), result.get ()});
|
||||||
|
|
||||||
result->set_logical_loc (m_logical_loc);
|
result->set_logical_loc (m_logical_loc);
|
||||||
|
@ -353,6 +445,9 @@ diagnostics::digraphs::edge::to_json_sarif_edge () const
|
||||||
|
|
||||||
#if CHECKING_P
|
#if CHECKING_P
|
||||||
|
|
||||||
|
#include "selftest.h"
|
||||||
|
#include "custom-sarif-properties/state-graphs.h"
|
||||||
|
|
||||||
namespace diagnostics {
|
namespace diagnostics {
|
||||||
namespace selftest {
|
namespace selftest {
|
||||||
|
|
||||||
|
@ -391,16 +486,17 @@ test_simple_graph ()
|
||||||
#define KEY_PREFIX "/placeholder/"
|
#define KEY_PREFIX "/placeholder/"
|
||||||
auto g = std::make_unique<digraph> ();
|
auto g = std::make_unique<digraph> ();
|
||||||
g->set_description ("test graph");
|
g->set_description ("test graph");
|
||||||
g->set_attr (KEY_PREFIX, "date", "1066");
|
g->set_property (json::string_property (KEY_PREFIX, "date"), "1066");
|
||||||
|
|
||||||
auto a = std::make_unique<digraph_node> (*g, "a");
|
auto a = std::make_unique<digraph_node> (*g, "a");
|
||||||
auto b = std::make_unique<digraph_node> (*g, "b");
|
auto b = std::make_unique<digraph_node> (*g, "b");
|
||||||
b->set_attr (KEY_PREFIX, "color", "red");
|
b->set_property (json::string_property (KEY_PREFIX, "color"), "red");
|
||||||
auto c = std::make_unique<digraph_node> (*g, "c");
|
auto c = std::make_unique<digraph_node> (*g, "c");
|
||||||
c->set_label ("I am a node label");
|
c->set_label ("I am a node label");
|
||||||
|
|
||||||
auto e = std::make_unique<digraph_edge> (*g, nullptr, *a, *c);
|
auto e = std::make_unique<digraph_edge> (*g, nullptr, *a, *c);
|
||||||
e->set_attr (KEY_PREFIX, "status", "copacetic");
|
e->set_property (json::string_property (KEY_PREFIX, "status"),
|
||||||
|
"copacetic");
|
||||||
e->set_label ("I am an edge label");
|
e->set_label ("I am an edge label");
|
||||||
g->add_edge (std::move (e));
|
g->add_edge (std::move (e));
|
||||||
|
|
||||||
|
@ -449,6 +545,34 @@ test_simple_graph ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_property_objects ()
|
||||||
|
{
|
||||||
|
namespace state_node_properties = custom_sarif_properties::state_graphs::node;
|
||||||
|
|
||||||
|
digraph g;
|
||||||
|
digraph_node node (g, "a");
|
||||||
|
|
||||||
|
ASSERT_EQ (node.get_property (state_node_properties::kind_prop),
|
||||||
|
state_node_properties::kind_t::other);
|
||||||
|
node.set_property (state_node_properties::kind_prop,
|
||||||
|
state_node_properties::kind_t::stack);
|
||||||
|
ASSERT_EQ (node.get_property (state_node_properties::kind_prop),
|
||||||
|
state_node_properties::kind_t::stack);
|
||||||
|
|
||||||
|
ASSERT_EQ (node.get_property (state_node_properties::dynalloc_state_prop),
|
||||||
|
state_node_properties::dynalloc_state_t::unknown);
|
||||||
|
node.set_property (state_node_properties::dynalloc_state_prop,
|
||||||
|
state_node_properties::dynalloc_state_t::freed);
|
||||||
|
ASSERT_EQ (node.get_property (state_node_properties::dynalloc_state_prop),
|
||||||
|
state_node_properties::dynalloc_state_t::freed);
|
||||||
|
|
||||||
|
ASSERT_EQ (node.get_property (state_node_properties::type), nullptr);
|
||||||
|
node.set_property (state_node_properties::type, "const char *");
|
||||||
|
ASSERT_STREQ (node.get_property (state_node_properties::type),
|
||||||
|
"const char *");
|
||||||
|
}
|
||||||
|
|
||||||
/* Run all of the selftests within this file. */
|
/* Run all of the selftests within this file. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -456,6 +580,7 @@ digraphs_cc_tests ()
|
||||||
{
|
{
|
||||||
test_empty_graph ();
|
test_empty_graph ();
|
||||||
test_simple_graph ();
|
test_simple_graph ();
|
||||||
|
test_property_objects ();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace diagnostics::selftest
|
} // namespace diagnostics::selftest
|
||||||
|
|
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#define GCC_DIAGNOSTICS_DIGRAPHS_H
|
#define GCC_DIAGNOSTICS_DIGRAPHS_H
|
||||||
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
#include "tristate.h"
|
||||||
#include "diagnostics/logical-locations.h"
|
#include "diagnostics/logical-locations.h"
|
||||||
|
|
||||||
class graphviz_out;
|
class graphviz_out;
|
||||||
|
@ -55,23 +56,57 @@ class edge;
|
||||||
class object
|
class object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const char *
|
/* String properties. */
|
||||||
get_attr (const char *key_prefix,
|
const char *get_property (const json::string_property &property) const;
|
||||||
const char *key) const;
|
void set_property (const json::string_property &property,
|
||||||
|
const char *utf8_value);
|
||||||
|
|
||||||
void
|
/* Integer properties. */
|
||||||
set_attr (const char *key_prefix,
|
bool maybe_get_property (const json::integer_property &property, long &out) const;
|
||||||
const char *key,
|
void set_property (const json::integer_property &property, long value);
|
||||||
const char *value);
|
|
||||||
|
|
||||||
|
/* Bool properties. */
|
||||||
|
tristate
|
||||||
|
get_property_as_tristate (const json::bool_property &property) const;
|
||||||
|
void set_property (const json::bool_property &property, bool value);
|
||||||
|
|
||||||
|
/* Array-of-string properties. */
|
||||||
|
json::array *
|
||||||
|
get_property (const json::array_of_string_property &property) const;
|
||||||
|
|
||||||
|
/* enum properties. */
|
||||||
|
template <typename EnumType>
|
||||||
|
EnumType
|
||||||
|
get_property (const json::enum_property<EnumType> &property) const
|
||||||
|
{
|
||||||
|
if (m_property_bag)
|
||||||
|
{
|
||||||
|
EnumType result;
|
||||||
|
if (m_property_bag->maybe_get_enum<EnumType> (property, result))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return json::enum_traits<EnumType>::get_unknown_value ();
|
||||||
|
}
|
||||||
|
template <typename EnumType>
|
||||||
void
|
void
|
||||||
set_json_attr (const char *key_prefix,
|
set_property (const json::enum_property<EnumType> &property,
|
||||||
const char *key,
|
EnumType value)
|
||||||
std::unique_ptr<json::value> value);
|
{
|
||||||
|
auto &bag = ensure_property_bag ();
|
||||||
|
bag.set_enum<EnumType> (property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* json::value properties. */
|
||||||
|
const json::value *get_property (const json::json_property &property) const;
|
||||||
|
void set_property (const json::json_property &property,
|
||||||
|
std::unique_ptr<json::value> value);
|
||||||
|
|
||||||
json::object *
|
json::object *
|
||||||
get_property_bag () const { return m_property_bag.get (); }
|
get_property_bag () const { return m_property_bag.get (); }
|
||||||
|
|
||||||
|
json::object &
|
||||||
|
ensure_property_bag ();
|
||||||
|
|
||||||
void
|
void
|
||||||
set_property_bag (std::unique_ptr<json::object> property_bag)
|
set_property_bag (std::unique_ptr<json::object> property_bag)
|
||||||
{
|
{
|
||||||
|
@ -188,6 +223,9 @@ class digraph : public object
|
||||||
|
|
||||||
std::unique_ptr<digraph> clone () const;
|
std::unique_ptr<digraph> clone () const;
|
||||||
|
|
||||||
|
const char *get_graph_kind () const;
|
||||||
|
void set_graph_kind (const char *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
add_node_id (std::string node_id, node &new_node)
|
add_node_id (std::string node_id, node &new_node)
|
||||||
|
@ -300,7 +338,7 @@ class node : public object
|
||||||
clone (digraph &new_graph,
|
clone (digraph &new_graph,
|
||||||
std::map<node *, node *> &node_mapping) const;
|
std::map<node *, node *> &node_mapping) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_id;
|
std::string m_id;
|
||||||
std::unique_ptr<std::string> m_label;
|
std::unique_ptr<std::string> m_label;
|
||||||
std::vector<std::unique_ptr<node>> m_children;
|
std::vector<std::unique_ptr<node>> m_children;
|
||||||
|
|
|
@ -57,8 +57,8 @@ html_generation_options::html_generation_options ()
|
||||||
: m_css (true),
|
: m_css (true),
|
||||||
m_javascript (true),
|
m_javascript (true),
|
||||||
m_show_state_diagrams (false),
|
m_show_state_diagrams (false),
|
||||||
m_show_state_diagrams_sarif (false),
|
m_show_graph_sarif (false),
|
||||||
m_show_state_diagrams_dot_src (false)
|
m_show_graph_dot_src (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ html_generation_options::dump (FILE *outfile, int indent) const
|
||||||
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_css);
|
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_css);
|
||||||
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_javascript);
|
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_javascript);
|
||||||
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams);
|
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams);
|
||||||
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams_sarif);
|
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_graph_sarif);
|
||||||
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams_dot_src);
|
DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_graph_dot_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
class html_builder;
|
class html_builder;
|
||||||
|
@ -640,7 +640,7 @@ html_builder::maybe_make_state_diagram (const paths::event &event)
|
||||||
the debug version. */
|
the debug version. */
|
||||||
auto state_graph
|
auto state_graph
|
||||||
= event.maybe_make_diagnostic_state_graph
|
= event.maybe_make_diagnostic_state_graph
|
||||||
(m_html_gen_opts.m_show_state_diagrams_sarif);
|
(m_html_gen_opts.m_show_graph_sarif);
|
||||||
if (!state_graph)
|
if (!state_graph)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -652,7 +652,7 @@ html_builder::maybe_make_state_diagram (const paths::event &event)
|
||||||
auto wrapper = std::make_unique<xml::element> ("div", false);
|
auto wrapper = std::make_unique<xml::element> ("div", false);
|
||||||
xml::printer xp (*wrapper);
|
xml::printer xp (*wrapper);
|
||||||
|
|
||||||
if (m_html_gen_opts.m_show_state_diagrams_sarif)
|
if (m_html_gen_opts.m_show_graph_sarif)
|
||||||
{
|
{
|
||||||
// For debugging, show the SARIF src inline:
|
// For debugging, show the SARIF src inline:
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
|
@ -660,7 +660,7 @@ html_builder::maybe_make_state_diagram (const paths::event &event)
|
||||||
print_pre_source (xp, pp_formatted_text (&pp));
|
print_pre_source (xp, pp_formatted_text (&pp));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_html_gen_opts.m_show_state_diagrams_dot_src)
|
if (m_html_gen_opts.m_show_graph_dot_src)
|
||||||
{
|
{
|
||||||
// For debugging, show the dot src inline:
|
// For debugging, show the dot src inline:
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
|
@ -1278,21 +1278,41 @@ void
|
||||||
html_builder::add_graph (const digraphs::digraph &dg,
|
html_builder::add_graph (const digraphs::digraph &dg,
|
||||||
xml::element &parent_element)
|
xml::element &parent_element)
|
||||||
{
|
{
|
||||||
|
auto div = std::make_unique<xml::element> ("div", false);
|
||||||
|
div->set_attr ("class", "gcc-directed-graph");
|
||||||
|
xml::printer xp (*div);
|
||||||
|
|
||||||
|
if (m_html_gen_opts.m_show_graph_sarif)
|
||||||
|
{
|
||||||
|
// For debugging, show the SARIF src inline:
|
||||||
|
pretty_printer pp;
|
||||||
|
dg.make_json_sarif_graph ()->print (&pp, true);
|
||||||
|
print_pre_source (xp, pp_formatted_text (&pp));
|
||||||
|
}
|
||||||
|
|
||||||
if (auto dot_graph = dg.make_dot_graph ())
|
if (auto dot_graph = dg.make_dot_graph ())
|
||||||
if (auto svg_element = dot::make_svg_from_graph (*dot_graph))
|
{
|
||||||
{
|
if (m_html_gen_opts.m_show_graph_dot_src)
|
||||||
auto div = std::make_unique<xml::element> ("div", false);
|
{
|
||||||
div->set_attr ("class", "gcc-directed-graph");
|
// For debugging, show the dot src inline:
|
||||||
xml::printer xp (*div);
|
pretty_printer pp;
|
||||||
if (const char *description = dg.get_description ())
|
dot::writer w (pp);
|
||||||
{
|
dot_graph->print (w);
|
||||||
xp.push_tag ("h2", true);
|
print_pre_source (xp, pp_formatted_text (&pp));
|
||||||
xp.add_text (description);
|
}
|
||||||
xp.pop_tag ("h2");
|
|
||||||
}
|
if (auto svg_element = dot::make_svg_from_graph (*dot_graph))
|
||||||
xp.append (std::move (svg_element));
|
{
|
||||||
parent_element.add_child (std::move (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
|
void
|
||||||
|
|
|
@ -40,11 +40,12 @@ struct html_generation_options
|
||||||
// If true, attempt to show state diagrams at events
|
// If true, attempt to show state diagrams at events
|
||||||
bool m_show_state_diagrams;
|
bool m_show_state_diagrams;
|
||||||
|
|
||||||
// If true, show the SARIF form of the state with such diagrams
|
/* If true, show the SARIF form of the state with such diagrams,
|
||||||
bool m_show_state_diagrams_sarif;
|
and of other graphs. */
|
||||||
|
bool m_show_graph_sarif;
|
||||||
|
|
||||||
// If true, show the .dot source used for the diagram
|
// If true, show the .dot source used for such graphs
|
||||||
bool m_show_state_diagrams_dot_src;
|
bool m_show_graph_dot_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern diagnostics::output_file
|
extern diagnostics::output_file
|
||||||
|
|
|
@ -650,12 +650,12 @@ html_scheme_handler::maybe_handle_kv (const context &ctxt,
|
||||||
if (key == "show-state-diagrams")
|
if (key == "show-state-diagrams")
|
||||||
return parse_bool_value (ctxt, key, value,
|
return parse_bool_value (ctxt, key, value,
|
||||||
m_html_gen_opts.m_show_state_diagrams);
|
m_html_gen_opts.m_show_state_diagrams);
|
||||||
if (key == "show-state-diagrams-dot-src")
|
if (key == "show-graph-dot-src")
|
||||||
return parse_bool_value (ctxt, key, value,
|
return parse_bool_value (ctxt, key, value,
|
||||||
m_html_gen_opts.m_show_state_diagrams_dot_src);
|
m_html_gen_opts.m_show_graph_dot_src);
|
||||||
if (key == "show-state-diagrams-sarif")
|
if (key == "show-graph-sarif")
|
||||||
return parse_bool_value (ctxt, key, value,
|
return parse_bool_value (ctxt, key, value,
|
||||||
m_html_gen_opts.m_show_state_diagrams_sarif);
|
m_html_gen_opts.m_show_graph_sarif);
|
||||||
return result::unrecognized;
|
return result::unrecognized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,8 +666,8 @@ html_scheme_handler::get_keys (auto_vec<const char *> &out) const
|
||||||
out.safe_push ("file");
|
out.safe_push ("file");
|
||||||
out.safe_push ("javascript");
|
out.safe_push ("javascript");
|
||||||
out.safe_push ("show-state-diagrams");
|
out.safe_push ("show-state-diagrams");
|
||||||
out.safe_push ("show-state-diagrams-dot-src");
|
out.safe_push ("show-graph-dot-src");
|
||||||
out.safe_push ("show-state-diagrams-sarif");
|
out.safe_push ("show-graph-sarif");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace output_spec
|
} // namespace output_spec
|
||||||
|
|
|
@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "coretypes.h"
|
#include "coretypes.h"
|
||||||
|
|
||||||
|
#include "custom-sarif-properties/state-graphs.h"
|
||||||
#include "diagnostics/state-graphs.h"
|
#include "diagnostics/state-graphs.h"
|
||||||
#include "graphviz.h"
|
#include "graphviz.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
@ -36,6 +37,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
using namespace diagnostics;
|
using namespace diagnostics;
|
||||||
using namespace diagnostics::state_graphs;
|
using namespace diagnostics::state_graphs;
|
||||||
|
|
||||||
|
namespace state_node_properties = custom_sarif_properties::state_graphs::node;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_depth (const digraphs::node &n)
|
get_depth (const digraphs::node &n)
|
||||||
{
|
{
|
||||||
|
@ -47,28 +50,28 @@ get_depth (const digraphs::node &n)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
get_color_for_dynalloc_state (enum node_dynalloc_state dynalloc_st)
|
get_color_for_dynalloc_state (enum state_node_properties::dynalloc_state_t dynalloc_st)
|
||||||
{
|
{
|
||||||
switch (dynalloc_st)
|
switch (dynalloc_st)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
gcc_unreachable ();
|
gcc_unreachable ();
|
||||||
break;
|
break;
|
||||||
case node_dynalloc_state::unknown:
|
case state_node_properties::dynalloc_state_t::unknown:
|
||||||
case node_dynalloc_state::nonnull:
|
case state_node_properties::dynalloc_state_t::nonnull:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case node_dynalloc_state::unchecked:
|
case state_node_properties::dynalloc_state_t::unchecked:
|
||||||
return "#ec7a08"; // pf-orange-400
|
return "#ec7a08"; // pf-orange-400
|
||||||
|
|
||||||
case node_dynalloc_state::freed:
|
case state_node_properties::dynalloc_state_t::freed:
|
||||||
return "#cc0000"; // pf-red-100
|
return "#cc0000"; // pf-red-100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_color_for_dynalloc_state (dot::attr_list &attrs,
|
set_color_for_dynalloc_state (dot::attr_list &attrs,
|
||||||
enum node_dynalloc_state state)
|
enum state_node_properties::dynalloc_state_t state)
|
||||||
{
|
{
|
||||||
if (const char *color = get_color_for_dynalloc_state (state))
|
if (const char *color = get_color_for_dynalloc_state (state))
|
||||||
attrs.add (dot::id ("color"), dot::id (color));
|
attrs.add (dot::id ("color"), dot::id (color));
|
||||||
|
@ -106,7 +109,7 @@ public:
|
||||||
= std::make_unique<dot::subgraph> (dot::id ("cluster_memory_regions"));
|
= std::make_unique<dot::subgraph> (dot::id ("cluster_memory_regions"));
|
||||||
for (size_t i = 0; i < input_state_graph.get_num_nodes (); ++i)
|
for (size_t i = 0; i < input_state_graph.get_num_nodes (); ++i)
|
||||||
on_input_state_node (*root_cluster,
|
on_input_state_node (*root_cluster,
|
||||||
state_node_ref (input_state_graph.get_node (i)));
|
input_state_graph.get_node (i));
|
||||||
add_stmt (std::move (root_cluster));
|
add_stmt (std::move (root_cluster));
|
||||||
|
|
||||||
/* Now create dot edges for edges in input_stage_graph. */
|
/* Now create dot edges for edges in input_stage_graph. */
|
||||||
|
@ -126,7 +129,8 @@ public:
|
||||||
auto e = std::make_unique<dot::edge_stmt> (src_port_id->second,
|
auto e = std::make_unique<dot::edge_stmt> (src_port_id->second,
|
||||||
dst_port_id->second);
|
dst_port_id->second);
|
||||||
set_color_for_dynalloc_state
|
set_color_for_dynalloc_state
|
||||||
(e->m_attrs, state_node_ref (dst_node).get_dynalloc_state ());
|
(e->m_attrs,
|
||||||
|
dst_node.get_property (state_node_properties::dynalloc_state_prop));
|
||||||
|
|
||||||
add_stmt (std::move (e));
|
add_stmt (std::move (e));
|
||||||
}
|
}
|
||||||
|
@ -147,9 +151,9 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
dot::id
|
dot::id
|
||||||
make_id (state_node_ref state_node, bool cluster)
|
make_id (const diagnostics::digraphs::node &state_node, bool cluster)
|
||||||
{
|
{
|
||||||
std::string input_node_id = state_node.m_node.get_id ();
|
std::string input_node_id = state_node.get_id ();
|
||||||
if (cluster)
|
if (cluster)
|
||||||
return std::string ("cluster_") + input_node_id;
|
return std::string ("cluster_") + input_node_id;
|
||||||
else
|
else
|
||||||
|
@ -157,44 +161,44 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
starts_node_p (state_node_ref state_node)
|
starts_node_p (const diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
switch (state_node.get_node_kind ())
|
switch (state_node.get_property (state_node_properties::kind_prop))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case node_kind::stack:
|
case state_node_properties::kind_t::stack:
|
||||||
/* We want all frames in the stack in the same table,
|
/* We want all frames in the stack in the same table,
|
||||||
so they are grouped. */
|
so they are grouped. */
|
||||||
case node_kind::dynalloc_buffer:
|
case state_node_properties::kind_t::dynalloc_buffer:
|
||||||
case node_kind::variable:
|
case state_node_properties::kind_t::variable:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
get_label_for_node (state_node_ref state_node)
|
get_label_for_node (const diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
switch (state_node.get_node_kind ())
|
switch (state_node.get_property (state_node_properties::kind_prop))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case node_kind::globals:
|
case state_node_properties::kind_t::globals:
|
||||||
return _("Globals");
|
return _("Globals");
|
||||||
case node_kind::code:
|
case state_node_properties::kind_t::code:
|
||||||
return _("Code");
|
return _("Code");
|
||||||
case node_kind::stack:
|
case state_node_properties::kind_t::stack:
|
||||||
return _("Stack");
|
return _("Stack");
|
||||||
case node_kind::heap_:
|
case state_node_properties::kind_t::heap_:
|
||||||
return _("Heap");
|
return _("Heap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_input_state_node (dot::subgraph &parent_subgraph,
|
on_input_state_node (dot::subgraph &parent_subgraph,
|
||||||
state_node_ref state_node)
|
const diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
dot::id sg_id = make_id (state_node, true);
|
dot::id sg_id = make_id (state_node, true);
|
||||||
|
|
||||||
|
@ -207,7 +211,7 @@ private:
|
||||||
xp.set_attr ("cellborder", "1");
|
xp.set_attr ("cellborder", "1");
|
||||||
xp.set_attr ("cellspacing", "0");
|
xp.set_attr ("cellspacing", "0");
|
||||||
|
|
||||||
const int max_depth = get_depth (state_node.m_node);
|
const int max_depth = get_depth (state_node);
|
||||||
const int num_columns = max_depth + 2;
|
const int num_columns = max_depth + 2;
|
||||||
|
|
||||||
dot::id id_of_dot_node = make_id (state_node, false);
|
dot::id id_of_dot_node = make_id (state_node, false);
|
||||||
|
@ -233,9 +237,9 @@ private:
|
||||||
child_subgraph->add_attr (dot::id ("label"), dot::id (label));
|
child_subgraph->add_attr (dot::id ("label"), dot::id (label));
|
||||||
|
|
||||||
// recurse:
|
// recurse:
|
||||||
for (size_t i = 0; i < state_node.m_node.get_num_children (); ++i)
|
for (size_t i = 0; i < state_node.get_num_children (); ++i)
|
||||||
on_input_state_node (*child_subgraph,
|
on_input_state_node (*child_subgraph,
|
||||||
state_node.m_node.get_child (i));
|
state_node.get_child (i));
|
||||||
parent_subgraph.m_stmt_list.add_stmt (std::move (child_subgraph));
|
parent_subgraph.m_stmt_list.add_stmt (std::move (child_subgraph));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,10 +250,10 @@ private:
|
||||||
add_title_tr (const dot::id &id_of_dot_node,
|
add_title_tr (const dot::id &id_of_dot_node,
|
||||||
xml::printer &xp,
|
xml::printer &xp,
|
||||||
int num_columns,
|
int num_columns,
|
||||||
state_node_ref state_node,
|
const diagnostics::digraphs::node &state_node,
|
||||||
std::string heading,
|
std::string heading,
|
||||||
enum style styl,
|
enum style styl,
|
||||||
enum node_dynalloc_state dynalloc_state)
|
enum state_node_properties::dynalloc_state_t dynalloc_state)
|
||||||
{
|
{
|
||||||
xp.push_tag ("tr", true);
|
xp.push_tag ("tr", true);
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
|
@ -298,48 +302,51 @@ private:
|
||||||
void
|
void
|
||||||
on_node_in_table (const dot::id &id_of_dot_node,
|
on_node_in_table (const dot::id &id_of_dot_node,
|
||||||
xml::printer &xp,
|
xml::printer &xp,
|
||||||
state_node_ref state_node,
|
const diagnostics::digraphs::node &state_node,
|
||||||
int max_depth,
|
int max_depth,
|
||||||
int depth,
|
int depth,
|
||||||
int num_columns)
|
int num_columns)
|
||||||
{
|
{
|
||||||
bool recurse = true;
|
bool recurse = true;
|
||||||
auto input_node_kind = state_node.get_node_kind ();
|
auto input_node_kind
|
||||||
|
= state_node.get_property (state_node_properties::kind_prop);
|
||||||
|
|
||||||
switch (input_node_kind)
|
switch (input_node_kind)
|
||||||
{
|
{
|
||||||
case node_kind::padding:
|
case state_node_properties::kind_t::padding:
|
||||||
case node_kind::other:
|
case state_node_properties::kind_t::other:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case node_kind::stack:
|
case state_node_properties::kind_t::stack:
|
||||||
add_title_tr (id_of_dot_node, xp, num_columns, state_node, "Stack",
|
add_title_tr (id_of_dot_node, xp, num_columns, state_node, "Stack",
|
||||||
style::h1,
|
style::h1,
|
||||||
node_dynalloc_state::unknown);
|
state_node_properties::dynalloc_state_t::unknown);
|
||||||
break;
|
break;
|
||||||
case node_kind::stack_frame:
|
case state_node_properties::kind_t::stack_frame:
|
||||||
if (auto logical_loc = state_node.get_logical_loc ())
|
if (auto logical_loc = state_node.get_logical_loc ())
|
||||||
if (const char *function
|
if (const char *function
|
||||||
= m_logical_loc_mgr.get_short_name (logical_loc))
|
= m_logical_loc_mgr.get_short_name (logical_loc))
|
||||||
add_title_tr (id_of_dot_node, xp, num_columns, state_node,
|
add_title_tr (id_of_dot_node, xp, num_columns, state_node,
|
||||||
std::string ("Frame: ") + function,
|
std::string ("Frame: ") + function,
|
||||||
style::h2,
|
style::h2,
|
||||||
node_dynalloc_state::unknown);
|
state_node_properties::dynalloc_state_t::unknown);
|
||||||
break;
|
break;
|
||||||
case node_kind::dynalloc_buffer:
|
case state_node_properties::kind_t::dynalloc_buffer:
|
||||||
{
|
{
|
||||||
enum node_dynalloc_state dynalloc_st
|
enum state_node_properties::dynalloc_state_t dynalloc_st
|
||||||
= state_node.get_dynalloc_state ();
|
= state_node.get_property
|
||||||
const char *extents = state_node.get_dynamic_extents ();
|
(state_node_properties::dynalloc_state_prop);
|
||||||
const char *type = state_node.get_type ();
|
const char *extents
|
||||||
|
= state_node.get_property (state_node_properties::dynamic_extents);
|
||||||
|
const char *type = state_node.get_property (state_node_properties::type);
|
||||||
pretty_printer pp;
|
pretty_printer pp;
|
||||||
switch (dynalloc_st)
|
switch (dynalloc_st)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
gcc_unreachable ();
|
gcc_unreachable ();
|
||||||
|
|
||||||
case node_dynalloc_state::unknown:
|
case state_node_properties::dynalloc_state_t::unknown:
|
||||||
case node_dynalloc_state::nonnull:
|
case state_node_properties::dynalloc_state_t::nonnull:
|
||||||
if (type)
|
if (type)
|
||||||
{
|
{
|
||||||
if (extents)
|
if (extents)
|
||||||
|
@ -356,7 +363,7 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case node_dynalloc_state::unchecked:
|
case state_node_properties::dynalloc_state_t::unchecked:
|
||||||
if (type)
|
if (type)
|
||||||
{
|
{
|
||||||
if (extents)
|
if (extents)
|
||||||
|
@ -371,7 +378,7 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case node_dynalloc_state::freed:
|
case state_node_properties::dynalloc_state_t::freed:
|
||||||
// TODO: show deallocator
|
// TODO: show deallocator
|
||||||
// TODO: show deallocation event
|
// TODO: show deallocation event
|
||||||
pp_printf (&pp, "Freed buffer");
|
pp_printf (&pp, "Freed buffer");
|
||||||
|
@ -404,9 +411,10 @@ private:
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case node_kind::variable:
|
case state_node_properties::kind_t::variable:
|
||||||
{
|
{
|
||||||
const char *name = state_node.get_name ();
|
const char *name
|
||||||
|
= state_node.get_property (state_node_properties::name);
|
||||||
gcc_assert (name);
|
gcc_assert (name);
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
||||||
|
@ -416,9 +424,10 @@ private:
|
||||||
xp.pop_tag ("td");
|
xp.pop_tag ("td");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case node_kind::element:
|
case state_node_properties::kind_t::element:
|
||||||
{
|
{
|
||||||
const char *index = state_node.get_index ();
|
const char *index
|
||||||
|
= state_node.get_property (state_node_properties::index);
|
||||||
gcc_assert (index);
|
gcc_assert (index);
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
||||||
|
@ -430,9 +439,10 @@ private:
|
||||||
xp.pop_tag ("td");
|
xp.pop_tag ("td");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case node_kind::field:
|
case state_node_properties::kind_t::field:
|
||||||
{
|
{
|
||||||
const char *name = state_node.get_name ();
|
const char *name
|
||||||
|
= state_node.get_property (state_node_properties::name);
|
||||||
gcc_assert (name);
|
gcc_assert (name);
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
maybe_add_dst_port (id_of_dot_node, xp, state_node);
|
||||||
|
@ -445,7 +455,8 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const char *type = state_node.get_type ())
|
if (const char *type
|
||||||
|
= state_node.get_property (state_node_properties::type))
|
||||||
{
|
{
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
xp.set_attr ("align", "right");
|
xp.set_attr ("align", "right");
|
||||||
|
@ -455,7 +466,8 @@ private:
|
||||||
xp.pop_tag ("td");
|
xp.pop_tag ("td");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const char *value = state_node.get_value ())
|
if (const char *value
|
||||||
|
= state_node.get_property (state_node_properties::value_str))
|
||||||
{
|
{
|
||||||
xp.push_tag ("td", false);
|
xp.push_tag ("td", false);
|
||||||
xp.set_attr ("align", "left");
|
xp.set_attr ("align", "left");
|
||||||
|
@ -466,15 +478,16 @@ private:
|
||||||
xp.pop_tag ("td");
|
xp.pop_tag ("td");
|
||||||
recurse = false;
|
recurse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
xp.pop_tag ("tr");
|
xp.pop_tag ("tr");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recurse)
|
if (recurse)
|
||||||
for (size_t i = 0; i < state_node.m_node.get_num_children (); ++i)
|
for (size_t i = 0; i < state_node.get_num_children (); ++i)
|
||||||
on_node_in_table (id_of_dot_node, xp,
|
on_node_in_table (id_of_dot_node, xp,
|
||||||
state_node.m_node.get_child (i),
|
state_node.get_child (i),
|
||||||
max_depth, depth + 1, num_columns);
|
max_depth, depth + 1, num_columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,9 +510,9 @@ private:
|
||||||
void
|
void
|
||||||
maybe_add_src_port (const dot::id &id_of_dot_node,
|
maybe_add_src_port (const dot::id &id_of_dot_node,
|
||||||
xml::printer &xp,
|
xml::printer &xp,
|
||||||
state_node_ref state_node)
|
const diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
auto iter = m_src_nodes.find (&state_node.m_node);
|
auto iter = m_src_nodes.find (&state_node);
|
||||||
if (iter == m_src_nodes.end ())
|
if (iter == m_src_nodes.end ())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -507,7 +520,7 @@ private:
|
||||||
dot::node_id node_id (id_of_dot_node,
|
dot::node_id node_id (id_of_dot_node,
|
||||||
dot::port (src_id,
|
dot::port (src_id,
|
||||||
dot::compass_pt::e));
|
dot::compass_pt::e));
|
||||||
m_src_node_to_port_id.insert ({&state_node.m_node, node_id});
|
m_src_node_to_port_id.insert ({&state_node, node_id});
|
||||||
xp.set_attr ("port", src_id.m_str);
|
xp.set_attr ("port", src_id.m_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,9 +530,9 @@ private:
|
||||||
void
|
void
|
||||||
maybe_add_dst_port (const dot::id &id_of_dot_node,
|
maybe_add_dst_port (const dot::id &id_of_dot_node,
|
||||||
xml::printer &xp,
|
xml::printer &xp,
|
||||||
state_node_ref state_node)
|
const diagnostics::digraphs::node &state_node)
|
||||||
{
|
{
|
||||||
auto iter = m_dst_nodes.find (&state_node.m_node);
|
auto iter = m_dst_nodes.find (&state_node);
|
||||||
if (iter == m_dst_nodes.end ())
|
if (iter == m_dst_nodes.end ())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -527,7 +540,7 @@ private:
|
||||||
dot::node_id node_id (id_of_dot_node,
|
dot::node_id node_id (id_of_dot_node,
|
||||||
dot::port (dst_id/*,
|
dot::port (dst_id/*,
|
||||||
dot::compass_pt::w*/));
|
dot::compass_pt::w*/));
|
||||||
m_dst_node_to_port_id.insert ({&state_node.m_node, node_id});
|
m_dst_node_to_port_id.insert ({&state_node, node_id});
|
||||||
xp.set_attr ("port", dst_id.m_str);
|
xp.set_attr ("port", dst_id.m_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,11 +548,11 @@ private:
|
||||||
const logical_locations::manager &m_logical_loc_mgr;
|
const logical_locations::manager &m_logical_loc_mgr;
|
||||||
|
|
||||||
/* All nodes involved in edges (and thus will need a port). */
|
/* All nodes involved in edges (and thus will need a port). */
|
||||||
std::set<digraphs::node *> m_src_nodes;
|
std::set<const digraphs::node *> m_src_nodes;
|
||||||
std::set<digraphs::node *> m_dst_nodes;
|
std::set<const digraphs::node *> m_dst_nodes;
|
||||||
|
|
||||||
std::map<digraphs::node *, dot::node_id> m_src_node_to_port_id;
|
std::map<const digraphs::node *, dot::node_id> m_src_node_to_port_id;
|
||||||
std::map<digraphs::node *, dot::node_id> m_dst_node_to_port_id;
|
std::map<const digraphs::node *, dot::node_id> m_dst_node_to_port_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<dot::graph>
|
std::unique_ptr<dot::graph>
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
/* 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 "diagnostics/state-graphs.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 diagnostics {
|
|
||||||
namespace selftest {
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_node_attrs ()
|
|
||||||
{
|
|
||||||
digraphs::digraph g;
|
|
||||||
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
|
|
||||||
state_graphs_cc_tests ()
|
|
||||||
{
|
|
||||||
test_node_attrs ();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace diagnostics::selftest
|
|
||||||
} // namespace diagnostics
|
|
||||||
|
|
||||||
#endif /* CHECKING_P */
|
|
|
@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#define GCC_DIAGNOSTICS_STATE_GRAPHS_H
|
#define GCC_DIAGNOSTICS_STATE_GRAPHS_H
|
||||||
|
|
||||||
#include "diagnostics/digraphs.h"
|
#include "diagnostics/digraphs.h"
|
||||||
#include "diagnostics/logical-locations.h"
|
|
||||||
|
|
||||||
/* diagnostics::digraphs provides support for directed graphs.
|
/* diagnostics::digraphs provides support for directed graphs.
|
||||||
|
|
||||||
|
@ -34,118 +33,11 @@ along with GCC; see the file COPYING3. If not see
|
||||||
in these nodes to stash extra properties (e.g. what kind of memory region
|
in these nodes to stash extra properties (e.g. what kind of memory region
|
||||||
a node is e.g. stack vs heap). */
|
a node is e.g. stack vs heap). */
|
||||||
|
|
||||||
class sarif_graph;
|
|
||||||
namespace dot { class graph; }
|
namespace dot { class graph; }
|
||||||
|
|
||||||
namespace diagnostics {
|
namespace diagnostics {
|
||||||
namespace state_graphs {
|
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_locations::key
|
|
||||||
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>
|
extern std::unique_ptr<dot::graph>
|
||||||
make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
|
make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
|
||||||
const logical_locations::manager &logical_loc_mgr);
|
const logical_locations::manager &logical_loc_mgr);
|
||||||
|
|
|
@ -6296,16 +6296,16 @@ These are visible by pressing ``j'' and ``k'' to single-step forward and
|
||||||
backward through events. Enabling this option will slow down
|
backward through events. Enabling this option will slow down
|
||||||
HTML generation.
|
HTML generation.
|
||||||
|
|
||||||
@item show-state-diagrams-dot-src=@r{[}yes@r{|}no@r{]}
|
@item show-graph-dot-src=@r{[}yes@r{|}no@r{]}
|
||||||
This is a debugging feature and defaults to @code{no}.
|
This is a debugging feature and defaults to @code{no}.
|
||||||
If @code{show-state-diagrams-dot-src=yes}
|
If @code{show-graph-dot-src=yes}
|
||||||
then if @code{show-state-diagrams=yes},
|
then if @code{show-state-diagrams=yes},
|
||||||
the generated state diagrams will also show the .dot source input to
|
the generated state diagrams will also show the .dot source input to
|
||||||
GraphViz used for the diagram.
|
GraphViz used for the diagram.
|
||||||
|
|
||||||
@item show-state-diagrams-sarif=@r{[}yes@r{|}no@r{]}
|
@item show-graph-sarif=@r{[}yes@r{|}no@r{]}
|
||||||
This is a debugging feature and defaults to @code{no}.
|
This is a debugging feature and defaults to @code{no}.
|
||||||
If @code{show-state-diagrams-sarif=yes}
|
If @code{show-graph-sarif=yes}
|
||||||
then if @code{show-state-diagrams=yes}, the generated state diagrams will
|
then if @code{show-state-diagrams=yes}, the generated state diagrams will
|
||||||
also show a SARIF representation of the state.
|
also show a SARIF representation of the state.
|
||||||
|
|
||||||
|
|
25
gcc/json.cc
25
gcc/json.cc
|
@ -394,6 +394,31 @@ object::set_bool (const char *key, bool v)
|
||||||
set (key, new json::literal (v));
|
set (key, new json::literal (v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
object::set_string (const string_property &property, const char *utf8_value)
|
||||||
|
{
|
||||||
|
set_string (property.m_key.get (), utf8_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
object::set_integer (const integer_property &property, long value)
|
||||||
|
{
|
||||||
|
set_integer (property.m_key.get (), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
object::set_bool (const bool_property &property, bool value)
|
||||||
|
{
|
||||||
|
set_bool (property.m_key.get (), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
object::set_array_of_string (const array_of_string_property &property,
|
||||||
|
std::unique_ptr<json::array> value)
|
||||||
|
{
|
||||||
|
set<array> (property.m_key.get (), std::move (value));
|
||||||
|
}
|
||||||
|
|
||||||
/* Subroutine of json::compare for comparing a pairs of objects. */
|
/* Subroutine of json::compare for comparing a pairs of objects. */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
82
gcc/json.h
82
gcc/json.h
|
@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#ifndef GCC_JSON_H
|
#ifndef GCC_JSON_H
|
||||||
#define GCC_JSON_H
|
#define GCC_JSON_H
|
||||||
|
|
||||||
|
#include "label-text.h"
|
||||||
|
|
||||||
/* Implementation of JSON, a lightweight data-interchange format.
|
/* Implementation of JSON, a lightweight data-interchange format.
|
||||||
|
|
||||||
See http://www.json.org/
|
See http://www.json.org/
|
||||||
|
@ -116,6 +118,41 @@ struct token
|
||||||
|
|
||||||
} // namespace json::pointer
|
} // namespace json::pointer
|
||||||
|
|
||||||
|
/* Typesafe way to work with properties in JSON objects. */
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
struct property
|
||||||
|
{
|
||||||
|
explicit property (const char *key)
|
||||||
|
: m_key (label_text::borrow (key))
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit property (const char *key_prefix, const char *key)
|
||||||
|
: m_key (label_text::take (concat (key_prefix, key, nullptr)))
|
||||||
|
{}
|
||||||
|
|
||||||
|
label_text m_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
using string_property = property<string>;
|
||||||
|
using integer_property = property<integer_number>;
|
||||||
|
using bool_property = property<literal>;
|
||||||
|
using json_property = property<value>;
|
||||||
|
using array_of_string_property = property<array>;
|
||||||
|
|
||||||
|
template <typename EnumType>
|
||||||
|
struct enum_traits
|
||||||
|
{
|
||||||
|
typedef EnumType enum_t;
|
||||||
|
|
||||||
|
static enum_t get_unknown_value ();
|
||||||
|
static bool maybe_get_value_from_string (const char *, enum_t &out);
|
||||||
|
static const char *get_string_for_value (enum_t value);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename EnumType>
|
||||||
|
using enum_property = property<enum_traits<EnumType>>;
|
||||||
|
|
||||||
/* Base class of JSON value. */
|
/* Base class of JSON value. */
|
||||||
|
|
||||||
class value
|
class value
|
||||||
|
@ -130,6 +167,8 @@ class value
|
||||||
void DEBUG_FUNCTION dump () const;
|
void DEBUG_FUNCTION dump () const;
|
||||||
|
|
||||||
virtual object *dyn_cast_object () { return nullptr; }
|
virtual object *dyn_cast_object () { return nullptr; }
|
||||||
|
virtual array *dyn_cast_array () { return nullptr; }
|
||||||
|
virtual integer_number *dyn_cast_integer_number () { return nullptr; }
|
||||||
virtual string *dyn_cast_string () { return nullptr; }
|
virtual string *dyn_cast_string () { return nullptr; }
|
||||||
|
|
||||||
static int compare (const json::value &val_a, const json::value &val_b);
|
static int compare (const json::value &val_a, const json::value &val_b);
|
||||||
|
@ -183,6 +222,19 @@ class object : public value
|
||||||
/* Set to literal true/false. */
|
/* Set to literal true/false. */
|
||||||
void set_bool (const char *key, bool v);
|
void set_bool (const char *key, bool v);
|
||||||
|
|
||||||
|
/* Typesafe access to properties by name (such as from a schema). */
|
||||||
|
void set_string (const string_property &property, const char *utf8_value);
|
||||||
|
void set_integer (const integer_property &property, long value);
|
||||||
|
void set_bool (const bool_property &property, bool value);
|
||||||
|
void set_array_of_string (const array_of_string_property &property,
|
||||||
|
std::unique_ptr<json::array> value);
|
||||||
|
template <typename EnumType>
|
||||||
|
bool maybe_get_enum (const enum_property<EnumType> &property,
|
||||||
|
EnumType &out) const;
|
||||||
|
template <typename EnumType>
|
||||||
|
void set_enum (const enum_property<EnumType> &property,
|
||||||
|
EnumType value);
|
||||||
|
|
||||||
static int compare (const json::object &obj_a, const json::object &obj_b);
|
static int compare (const json::object &obj_a, const json::object &obj_b);
|
||||||
|
|
||||||
size_t get_num_keys () const { return m_keys.length (); }
|
size_t get_num_keys () const { return m_keys.length (); }
|
||||||
|
@ -210,6 +262,8 @@ class array : public value
|
||||||
void print (pretty_printer *pp, bool formatted) const final override;
|
void print (pretty_printer *pp, bool formatted) const final override;
|
||||||
std::unique_ptr<value> clone () const final override;
|
std::unique_ptr<value> clone () const final override;
|
||||||
|
|
||||||
|
array *dyn_cast_array () final override { return this; }
|
||||||
|
|
||||||
void append (value *v);
|
void append (value *v);
|
||||||
void append_string (const char *utf8_value);
|
void append_string (const char *utf8_value);
|
||||||
|
|
||||||
|
@ -269,6 +323,8 @@ class integer_number : public value
|
||||||
void print (pretty_printer *pp, bool formatted) const final override;
|
void print (pretty_printer *pp, bool formatted) const final override;
|
||||||
std::unique_ptr<value> clone () const final override;
|
std::unique_ptr<value> clone () const final override;
|
||||||
|
|
||||||
|
integer_number *dyn_cast_integer_number () final override { return this; }
|
||||||
|
|
||||||
long get () const { return m_value; }
|
long get () const { return m_value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -317,6 +373,32 @@ class literal : public value
|
||||||
enum kind m_kind;
|
enum kind m_kind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename EnumType>
|
||||||
|
inline bool
|
||||||
|
object::maybe_get_enum (const enum_property<EnumType> &property,
|
||||||
|
EnumType &out) const
|
||||||
|
{
|
||||||
|
if (value *jv = get (property.m_key.get ()))
|
||||||
|
if (string *jstr = jv->dyn_cast_string ())
|
||||||
|
{
|
||||||
|
if (enum_traits<EnumType>::maybe_get_value_from_string
|
||||||
|
(jstr->get_string (), out))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename EnumType>
|
||||||
|
inline void
|
||||||
|
object::set_enum (const enum_property<EnumType> &property,
|
||||||
|
EnumType value)
|
||||||
|
{
|
||||||
|
const char *str
|
||||||
|
= json::enum_traits<EnumType>::get_string_for_value (value);
|
||||||
|
set_string (property.m_key.get (), str);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace json
|
} // namespace json
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
12
gcc/match.pd
12
gcc/match.pd
|
@ -6844,20 +6844,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|
||||||
(bit_and:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
|
(bit_and:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
|
||||||
(ne @0 @1))
|
(ne @0 @1))
|
||||||
(simplify
|
(simplify
|
||||||
(bit_ior:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
|
(bit_ior:c (ne:c @0 @1) (ne (bit_ior@2 @0 @1) integer_zerop@3))
|
||||||
(ne (bit_ior @0 @1) { integer_zero_node; }))
|
(ne @2 @3))
|
||||||
(simplify
|
(simplify
|
||||||
(bit_and:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
|
(bit_and:c (eq:c @0 @1) (eq (bit_ior@2 @0 @1) integer_zerop@3))
|
||||||
(eq (bit_ior @0 @1) { integer_zero_node; }))
|
(eq @2 @3))
|
||||||
(simplify
|
(simplify
|
||||||
(bit_ior:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
|
(bit_ior:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
|
||||||
(eq @0 @1))
|
(eq @0 @1))
|
||||||
(simplify
|
(simplify
|
||||||
(bit_and:c (ne:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
|
(bit_and:c (ne:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
|
||||||
{ build_zero_cst (type); })
|
{ constant_boolean_node (false, type); })
|
||||||
(simplify
|
(simplify
|
||||||
(bit_ior:c (eq:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
|
(bit_ior:c (eq:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
|
||||||
{ build_one_cst (type); })
|
{ constant_boolean_node (true, type); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These was part of minmax phiopt. */
|
/* These was part of minmax phiopt. */
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2025-10-16 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
* gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
|
||||||
|
(report_diag_with_graphs): Port from set_attr to set_property.
|
||||||
|
|
||||||
2025-10-15 Andrew MacLeod <amacleod@redhat.com>
|
2025-10-15 Andrew MacLeod <amacleod@redhat.com>
|
||||||
|
|
||||||
PR tree-optimization/121468
|
PR tree-optimization/121468
|
||||||
|
|
|
@ -210,9 +210,8 @@ report_diag_with_graphs (location_t loc)
|
||||||
g->set_description (desc);
|
g->set_description (desc);
|
||||||
auto a = std::make_unique<diagnostic_node> (*g, "a");
|
auto a = std::make_unique<diagnostic_node> (*g, "a");
|
||||||
auto b = std::make_unique<diagnostic_node> (*g, "b");
|
auto b = std::make_unique<diagnostic_node> (*g, "b");
|
||||||
#define KEY_PREFIX "/placeholder-prefix/"
|
const json::string_property color ("/placeholder-prefix/color");
|
||||||
b->set_attr (KEY_PREFIX, "color", "red");
|
b->set_property (color, "red");
|
||||||
#undef KEY_PREFIX
|
|
||||||
auto c = std::make_unique<diagnostic_node> (*g, "c");
|
auto c = std::make_unique<diagnostic_node> (*g, "c");
|
||||||
c->set_label ("I am a node label");
|
c->set_label ("I am a node label");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* PR tree-optimization/122296 */
|
||||||
|
|
||||||
|
typedef unsigned type1;
|
||||||
|
typedef unsigned __attribute__((vector_size(sizeof(unsigned) ))) type2;
|
||||||
|
type1 g(type1 a, type1 b)
|
||||||
|
{
|
||||||
|
type1 c = a == b;
|
||||||
|
type1 d = (a|b) == 0;
|
||||||
|
return c & d;
|
||||||
|
}
|
||||||
|
|
||||||
|
type1 f(type1 a, type1 b)
|
||||||
|
{
|
||||||
|
type1 c = a != b;
|
||||||
|
type1 d = (a|b) != 0;
|
||||||
|
return c | d;
|
||||||
|
}
|
||||||
|
type2 g2(type2 a, type2 b)
|
||||||
|
{
|
||||||
|
type2 c = a == b;
|
||||||
|
type2 d = (a|b) == 0;
|
||||||
|
return c & d;
|
||||||
|
}
|
||||||
|
|
||||||
|
type2 f2(type2 a, type2 b)
|
||||||
|
{
|
||||||
|
type2 c = a != b;
|
||||||
|
type2 d = (a|b) != 0;
|
||||||
|
return c | d;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O1 -fdump-tree-forwprop1 -fdump-tree-optimized" } */
|
||||||
|
|
||||||
|
/* PR tree-optimization/122296 */
|
||||||
|
|
||||||
|
typedef unsigned type1 __attribute__((vector_size(sizeof(unsigned))));
|
||||||
|
|
||||||
|
type1 f(type1 a, type1 b)
|
||||||
|
{
|
||||||
|
type1 c = a == b;
|
||||||
|
type1 d = (a|b) != 0;
|
||||||
|
return c | d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR " "optimized" } } */
|
||||||
|
/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR " "forwprop1" } } */
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2025-10-16 David Faust <david.faust@oracle.com>
|
||||||
|
|
||||||
|
* dwarf2.def (DW_TAG_GNU_annotation): Add link to wiki page
|
||||||
|
documenting the extension.
|
||||||
|
(DW_AT_GNU_annotation): Likewise.
|
||||||
|
|
||||||
2025-10-10 Tobias Burnus <tburnus@baylibre.com>
|
2025-10-10 Tobias Burnus <tburnus@baylibre.com>
|
||||||
|
|
||||||
* hsa_ext_amd.h (enum hsa_amd_agent_info_s): Add
|
* hsa_ext_amd.h (enum hsa_amd_agent_info_s): Add
|
||||||
|
|
|
@ -1,3 +1,36 @@
|
||||||
|
2025-10-16 Tobias Burnus <tburnus@baylibre.com>
|
||||||
|
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx10-3-generic.c: Add
|
||||||
|
dg-excess-errors to handle possible missing libgomp multi lib.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1030.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1036.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx11-generic.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1100.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1103.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx9-4-generic.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx9-generic.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx900.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx906.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx908.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx90a.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx90c.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx942.c: Likewise.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1031.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1032.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1033.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1034.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1035.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1101.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1102.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1150.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1151.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1152.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx1153.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx902.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx904.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx909.c: New test.
|
||||||
|
* testsuite/libgomp.c/declare-variant-4-gfx950.c: New test.
|
||||||
|
|
||||||
2025-10-15 Tobias Burnus <tburnus@baylibre.com>
|
2025-10-15 Tobias Burnus <tburnus@baylibre.com>
|
||||||
|
|
||||||
* libgomp.texi (OpenMP Context Selectors): Add note that there is
|
* libgomp.texi (OpenMP Context Selectors): Add note that there is
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
2025-10-16 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
* include/std/stacktrace
|
||||||
|
(operator<<(ostream&, const stacktrace_entry&)): Improve output
|
||||||
|
when description() or source_file() returns an empty string,
|
||||||
|
or the stacktrace_entry is invalid. Append frame address to
|
||||||
|
output.
|
||||||
|
(operator<<(ostream&, const basic_stacktrace<A>&)): Use the
|
||||||
|
size_type of the correct specialization.
|
||||||
|
|
||||||
2025-10-15 Jonathan Wakely <jwakely@redhat.com>
|
2025-10-15 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* python/libstdcxx/v6/printers.py (StdStacktraceEntryPrinter):
|
* python/libstdcxx/v6/printers.py (StdStacktraceEntryPrinter):
|
||||||
|
|
Loading…
Reference in New Issue