From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 78005 invoked by alias); 6 Feb 2020 14:52:56 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 77997 invoked by uid 89); 6 Feb 2020 14:52:56 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.6 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy=UD:pop X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Feb 2020 14:52:54 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 0497AADFF; Thu, 6 Feb 2020 14:52:51 +0000 (UTC) Date: Thu, 06 Feb 2020 14:52:00 -0000 From: Richard Biener To: gcc-patches@gcc.gnu.org cc: law@redhat.com Subject: [PATCH] middle-end/93519 - avoid folding stmts in obviously unreachable code Message-ID: User-Agent: Alpine 2.21 (LSU 202 2017-01-01) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-SW-Source: 2020-02/txt/msg00368.txt.bz2 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. Bootstrapped and tested on x86_64-unknown-linux-gnu. OK? Thanks, Richard. 2020-02-06 Richard Biener 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 *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 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); -- 2.23.0