diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 637a990da4a..d03e23a9b6e 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1615,6 +1615,9 @@ strongly_connected_components::strong_connect (unsigned index) superedge *sedge; FOR_EACH_VEC_ELT (v_snode->m_succs, i, sedge) { + if (sedge->get_kind () != SUPEREDGE_CFG_EDGE + && sedge->get_kind () != SUPEREDGE_INTRAPROCEDURAL_CALL) + continue; supernode *w_snode = sedge->m_dest; per_node_data *w = &m_per_node[w_snode->m_index]; if (w->m_index == -1) @@ -1690,7 +1693,14 @@ worklist::add_node (exploded_node *enode) /* Comparator for implementing worklist::key_t comparison operators. Return negative if KA is before KB Return positive if KA is after KB - Return 0 if they are equal. */ + Return 0 if they are equal. + + The ordering of the worklist is critical for performance and for + avoiding node explosions. Ideally we want all enodes at a CFG join-point + with the same callstring to be sorted next to each other in the worklist + so that a run of consecutive enodes can be merged and processed "in bulk" + rather than individually or pairwise, minimizing the number of new enodes + created. */ int worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) @@ -1742,6 +1752,11 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) gcc_assert (snode_a == snode_b); + /* The points might vary by callstring; try sorting by callstring. */ + int cs_cmp = call_string::cmp (call_string_a, call_string_b); + if (cs_cmp) + return cs_cmp; + /* Order within supernode via program point. */ int within_snode_cmp = function_point::cmp_within_supernode (point_a.get_function_point (), @@ -1749,11 +1764,6 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) if (within_snode_cmp) return within_snode_cmp; - /* The points might vary by callstring; try sorting by callstring. */ - int cs_cmp = call_string::cmp (call_string_a, call_string_b); - if (cs_cmp) - return cs_cmp; - /* Otherwise, we ought to have the same program_point. */ gcc_assert (point_a == point_b); diff --git a/gcc/testsuite/gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c b/gcc/testsuite/gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c index 0172c9b324c..2b0352711ae 100644 --- a/gcc/testsuite/gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c +++ b/gcc/testsuite/gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c @@ -69,5 +69,6 @@ void test(int n) free (it); - __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */ + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + // TODO: why 2 enodes here, rather than 1 } diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-vs-local-1a.c b/gcc/testsuite/gcc.dg/analyzer/malloc-vs-local-1a.c index 4e70694a33d..bf77862e67c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/malloc-vs-local-1a.c +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-vs-local-1a.c @@ -48,10 +48,10 @@ int test_repeated_predicate_1 (int n) result = do_stuff (ptr, n); - __analyzer_dump_exploded_nodes (0); /* { dg-warning "5 processed enodes" } */ - // FIXME: why 5 here? - __analyzer_dump_exploded_nodes (0); /* { dg-warning "5 processed enodes" } */ - // FIXME: why 5 here? + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + if (n > 10) free (ptr); /* { dg-bogus "not on the heap" } */ @@ -105,8 +105,8 @@ int test_explicit_flag (int n) result = do_stuff (ptr, n); - __analyzer_dump_exploded_nodes (0); /* { dg-warning "5 processed enodes" } */ - // FIXME: why 5 here? + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + if (need_to_free) free (ptr); /* { dg-bogus "not on the heap" } */ @@ -131,8 +131,8 @@ int test_pointer_comparison (int n) result = do_stuff (ptr, n); - __analyzer_dump_exploded_nodes (0); /* { dg-warning "5 processed enodes" } */ - // FIXME: why 5 here? + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + if (ptr != buf) free (ptr); /* { dg-bogus "not on the heap" } */ @@ -169,8 +169,8 @@ int test_initial_flag (int n) result = do_stuff (ptr, n); - __analyzer_dump_exploded_nodes (0); /* { dg-warning "6 processed enodes" } */ - // FIXME: why 6 here? + __analyzer_dump_exploded_nodes (0); /* { dg-warning "3 processed enodes" } */ + // FIXME: why 3 here? if (n > 10) free (ptr); /* { dg-bogus "not on the heap" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96653.c b/gcc/testsuite/gcc.dg/analyzer/pr96653.c index 494c5312c6b..e5e387c44a5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96653.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr96653.c @@ -1,8 +1,7 @@ /* Examples of switch statements with many cases (with default values). Adapted from Linux 5.9-rc1:drivers/media/v4l2-core/v4l2-ctrls.c. */ -/* { dg-additional-options "-O1 -Wno-analyzer-too-complex" } */ -// TODO: remove need for -Wno-analyzer-too-complex +/* { dg-additional-options "-O1" } */ typedef unsigned int u32; typedef long long s64;