OK?
Thanks,
Richard.
2020-02-06 Richard Biener <rguent...@suse.de>
PR middle-end/93519
* tree-inline.c (fold_marked_statements): Do a PRE walk,
skipping unreachable regions.
(optimize_inline_calls): Skip folding stmts when we didn't
inline.
* gcc.dg/Wrestrict-21.c: New testcase.
---
gcc/testsuite/gcc.dg/Wrestrict-21.c | 18 +++
gcc/tree-inline.c | 195 ++++++++++++++++------------
2 files changed, 133 insertions(+), 80 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/Wrestrict-21.c
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-21.c
b/gcc/testsuite/gcc.dg/Wrestrict-21.c
new file mode 100644
index 00000000000..e300663758e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-21.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wrestrict" } */
+
+static char *
+str_numth(char *dest, char *num, int type)
+{
+ if (dest != num)
+ __builtin_strcpy(dest, num); /* { dg-bogus "is the same" } */
+ __builtin_strcat(dest, "foo");
+ return dest;
+}
+
+void
+DCH_to_char(char *in, char *out, int collid)
+{
+ char *s = out;
+ str_numth(s, s, 42);
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 5b0050a53d2..19154bb843e 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5261,86 +5261,118 @@ static void
fold_marked_statements (int first, hash_set<gimple *> *statements)
{
auto_bitmap to_purge;
- for (; first < last_basic_block_for_fn (cfun); first++)
- if (BASIC_BLOCK_FOR_FN (cfun, first))
- {
- gimple_stmt_iterator gsi;
- for (gsi = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
- !gsi_end_p (gsi);
- gsi_next (&gsi))
- if (statements->contains (gsi_stmt (gsi)))
- {
- gimple *old_stmt = gsi_stmt (gsi);
- tree old_decl
- = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
+ auto_vec<edge_iterator, 20> stack (n_basic_blocks_for_fn (cfun) + 2);
+ auto_sbitmap visited (last_basic_block_for_fn (cfun));
+ bitmap_clear (visited);
+
+ stack.quick_push (ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs));
+ while (!stack.is_empty ())
+ {
+ /* Look at the edge on the top of the stack. */
+ edge_iterator ei = stack.last ();
+ basic_block dest = ei_edge (ei)->dest;
+ edge known_taken;
+
+ if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
+ && !bitmap_bit_p (visited, dest->index)
+ /* Avoid walking unreachable edges, the iteration scheme
+ using edge iterators doesn't allow to not push them so
+ ignore them here instead (FIXME: use an edge flag at least?). */
+ && !((known_taken = find_taken_edge (ei_edge (ei)->src, NULL_TREE))
+ && known_taken != ei_edge (ei)))
+ {
+ bitmap_set_bit (visited, dest->index);
- if (old_decl && fndecl_built_in_p (old_decl))
- {
- /* Folding builtins can create multiple instructions,
- we need to look at all of them. */
- gimple_stmt_iterator i2 = gsi;
- gsi_prev (&i2);
- if (fold_stmt (&gsi))
- {
- gimple *new_stmt;
- /* If a builtin at the end of a bb folded into nothing,
- the following loop won't work. */
- if (gsi_end_p (gsi))
- {
- cgraph_update_edges_for_call_stmt (old_stmt,
- old_decl, NULL);
- break;
- }
- if (gsi_end_p (i2))
- i2 = gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, first));
- else
- gsi_next (&i2);
- while (1)
- {
- new_stmt = gsi_stmt (i2);
- update_stmt (new_stmt);
- cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
- new_stmt);
+ if (dest->index >= first)
+ for (gimple_stmt_iterator gsi = gsi_start_bb (dest);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ if (!statements->contains (gsi_stmt (gsi)))
+ continue;
- if (new_stmt == gsi_stmt (gsi))
- {
- /* It is okay to check only for the very last
- of these statements. If it is a throwing
- statement nothing will change. If it isn't
- this can remove EH edges. If that weren't
- correct then because some intermediate stmts
- throw, but not the last one. That would mean
- we'd have to split the block, which we can't
- here and we'd loose anyway. And as builtins
- probably never throw, this all
- is mood anyway. */
- if (maybe_clean_or_replace_eh_stmt (old_stmt,
- new_stmt))
- bitmap_set_bit (to_purge, first);
- break;
- }
+ gimple *old_stmt = gsi_stmt (gsi);
+ tree old_decl = (is_gimple_call (old_stmt)
+ ? gimple_call_fndecl (old_stmt) : 0);
+ if (old_decl && fndecl_built_in_p (old_decl))
+ {
+ /* Folding builtins can create multiple instructions,
+ we need to look at all of them. */
+ gimple_stmt_iterator i2 = gsi;
+ gsi_prev (&i2);
+ if (fold_stmt (&gsi))
+ {
+ gimple *new_stmt;
+ /* If a builtin at the end of a bb folded into nothing,
+ the following loop won't work. */
+ if (gsi_end_p (gsi))
+ {
+ cgraph_update_edges_for_call_stmt (old_stmt,
+ old_decl, NULL);
+ break;
+ }
+ if (gsi_end_p (i2))
+ i2 = gsi_start_bb (dest);
+ else
gsi_next (&i2);
- }
- }
- }
- else if (fold_stmt (&gsi))
- {
- /* Re-read the statement from GSI as fold_stmt() may
- have changed it. */
- gimple *new_stmt = gsi_stmt (gsi);
- update_stmt (new_stmt);
-
- if (is_gimple_call (old_stmt)
- || is_gimple_call (new_stmt))
- cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
- new_stmt);
-
- if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
- bitmap_set_bit (to_purge, first);
- }
- }
- }
+ while (1)
+ {
+ new_stmt = gsi_stmt (i2);
+ update_stmt (new_stmt);
+ cgraph_update_edges_for_call_stmt (old_stmt,
+ old_decl,
+ new_stmt);
+
+ if (new_stmt == gsi_stmt (gsi))
+ {
+ /* It is okay to check only for the very last
+ of these statements. If it is a throwing
+ statement nothing will change. If it isn't
+ this can remove EH edges. If that weren't
+ correct then because some intermediate stmts
+ throw, but not the last one. That would mean
+ we'd have to split the block, which we can't
+ here and we'd loose anyway. And as builtins
+ probably never throw, this all
+ is mood anyway. */
+ if (maybe_clean_or_replace_eh_stmt (old_stmt,
+ new_stmt))
+ bitmap_set_bit (to_purge, dest->index);
+ break;
+ }
+ gsi_next (&i2);
+ }
+ }
+ }
+ else if (fold_stmt (&gsi))
+ {
+ /* Re-read the statement from GSI as fold_stmt() may
+ have changed it. */
+ gimple *new_stmt = gsi_stmt (gsi);
+ update_stmt (new_stmt);
+
+ if (is_gimple_call (old_stmt)
+ || is_gimple_call (new_stmt))
+ cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+ new_stmt);
+
+ if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
+ bitmap_set_bit (to_purge, dest->index);
+ }
+ }
+
+ if (EDGE_COUNT (dest->succs) > 0)
+ stack.quick_push (ei_start (dest->succs));
+ }
+ else
+ {
+ if (!ei_one_before_end_p (ei))
+ ei_next (&stack.last ());
+ else
+ stack.pop ();
+ }
+ }
+
gimple_purge_all_dead_eh_edges (to_purge);
}
@@ -5404,6 +5436,13 @@ optimize_inline_calls (tree fn)
gcc_assert (e->inline_failed);
}
+ /* If we didn't inline into the function there is nothing to do. */
+ if (!inlined_p)
+ {
+ delete id.statements_to_fold;
+ return 0;
+ }
+
/* Fold queued statements. */
update_max_bb_count ();
fold_marked_statements (last, id.statements_to_fold);
@@ -5426,10 +5465,6 @@ optimize_inline_calls (tree fn)
gcc_assert (!id.debug_stmts.exists ());
- /* If we didn't inline into the function there is nothing to do. */
- if (!inlined_p)
- return 0;
-
/* Renumber the lexical scoping (non-code) blocks consecutively. */
number_blocks (fn);