aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2020-02-07 12:56:18 +0100
committerRichard Biener <rguenther@suse.de>2020-02-07 12:57:18 +0100
commit3c7a03bc360c3511fae3747a71e579e9fd0824f9 (patch)
tree80486aaaa38e31f6a148bf0e524ce795e12ad5b4 /gcc
parent5713834e4b99e4c4c99eef15698a497f091b7dc4 (diff)
downloadgcc-3c7a03bc360c3511fae3747a71e579e9fd0824f9.zip
gcc-3c7a03bc360c3511fae3747a71e579e9fd0824f9.tar.gz
gcc-3c7a03bc360c3511fae3747a71e579e9fd0824f9.tar.bz2
middle-end/93519 - avoid folding stmts in obviously unreachable code
The inliner folds stmts delayed, the following arranges things so to not fold stmts that are obviously not reachable to avoid warnings from those code regions. 2020-02-07 Richard Biener <rguenther@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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/Wrestrict-21.c18
-rw-r--r--gcc/tree-inline.c192
4 files changed, 144 insertions, 79 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 21ecb2c..d5d29f5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2020-02-07 Richard Biener <rguenther@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.
+
2020-02-07 H.J. Lu <hongjiu.lu@intel.com>
PR target/85667
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bd6610f..69f7223 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-02-07 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/93519
+ * gcc.dg/Wrestrict-21.c: New testcase.
+
2020-02-07 H.J. Lu <hongjiu.lu@intel.com>
PR target/85667
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-21.c b/gcc/testsuite/gcc.dg/Wrestrict-21.c
new file mode 100644
index 0000000..e300663
--- /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 5b0050a..23941da 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5261,86 +5261,117 @@ 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, 20> stack (n_basic_blocks_for_fn (cfun) + 2);
+ auto_sbitmap visited (last_basic_block_for_fn (cfun));
+ bitmap_clear (visited);
- 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
+ stack.quick_push (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+ while (!stack.is_empty ())
+ {
+ /* Look at the edge on the top of the stack. */
+ edge e = stack.pop ();
+ basic_block dest = e->dest;
+
+ if (dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
+ || bitmap_bit_p (visited, dest->index))
+ continue;
+
+ bitmap_set_bit (visited, dest->index);
+
+ 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;
+
+ 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);
+ 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);
- while (1)
- {
- new_stmt = gsi_stmt (i2);
- update_stmt (new_stmt);
- cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
- new_stmt);
+ }
+ }
+ }
+ 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 (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;
- }
- 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);
- }
+ if (EDGE_COUNT (dest->succs) > 0)
+ {
+ /* Avoid warnings emitted from folding statements that
+ became unreachable because of inlined function parameter
+ propagation. */
+ e = find_taken_edge (dest, NULL_TREE);
+ if (e)
+ stack.quick_push (e);
+ else
+ {
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, dest->succs)
+ stack.safe_push (e);
}
- }
+ }
+ }
+
gimple_purge_all_dead_eh_edges (to_purge);
}
@@ -5404,6 +5435,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 +5464,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);