From patchwork Wed Aug 14 13:36:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 1147057 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-506938-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="UwtFSUyL"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 467rGm3ptnz9s7T for ; Wed, 14 Aug 2019 23:37:02 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=tSCuymr82ynqPakP0Dux7sg0AaNA2MuyIA6M7M+eKxN/2XeSOt3Cu S1sX6kEwo9VL9kWq1kwNXnPw8Drm4BcN5deOync1Xb35nCSH1uy6yC7KJ0SSPxKi Ie6y3qSS/Y32BTXzoNsTl+Ke4xluL+zRWHFFaIOp4GU6yuwvPKAt30= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=rxGguhVL/ZFT8976iRz6y/ehGUk=; b=UwtFSUyLR0luF3LqPNix ujLV/PRo+XTZmNf704hneqkMgpC9cnGJR2G/GbThxgL9t85RxxXqpERC6IZ4w5t3 iYqT8QLzUD/lREq7bRi492mcPOM35U2FnA5mD2uEIKyM5/ISlK8cR39VtVAE1MRi Q0YJtB+Z0I+4nfGlwfgjkcA= Received: (qmail 63818 invoked by alias); 14 Aug 2019 13:36:53 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 63376 invoked by uid 89); 14 Aug 2019 13:36:52 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.4 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 14 Aug 2019 13:36:42 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 410F0AE48 for ; Wed, 14 Aug 2019 13:36:40 +0000 (UTC) Date: Wed, 14 Aug 2019 15:36:40 +0200 (CEST) From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH] Make GIMPLE forwprop DCE dead stmts Message-ID: User-Agent: Alpine 2.20 (LSU 67 2015-01-07) MIME-Version: 1.0 The following patch makes forwprop DCE the stmts that become dead because of propagation of copies and constants. For this to work we actually have to do that reliably rather than relying on fold_stmt doing this for us. This hits fortran/trans-intrinsic.c in a way that we do "interesting" jump threading exposing a bogus uninit warning. I'll open a PR for this with an (unreduced) testcase after committing. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. I've done this when seeing the number of copyprop passes we have and knowing the expense of the SSA propagation machinery so eventually forwprop (in a cheaper mode, not folding all stmts) could replace copyprop. Richard. 2019-08-14 Richard Biener * tree-ssa-forwprop.c (pass_forwprop::execute): Fully propagate lattice, DCE stmts that became dead because of that. fortran/ * trans-intrinsic.c (gfc_conv_intrinsic_findloc): Initialize forward_branch to avoid bogus uninitialized warning. * gcc.dg/tree-ssa/forwprop-31.c: Adjust. Index: gcc/tree-ssa-forwprop.c =================================================================== --- gcc/tree-ssa-forwprop.c (revision 274422) +++ gcc/tree-ssa-forwprop.c (working copy) @@ -2299,13 +2299,14 @@ pass_forwprop::execute (function *fun) int postorder_num = pre_and_rev_post_order_compute_fn (cfun, NULL, postorder, false); auto_vec to_fixup; + auto_vec to_remove; to_purge = BITMAP_ALLOC (NULL); for (int i = 0; i < postorder_num; ++i) { gimple_stmt_iterator gsi; basic_block bb = BASIC_BLOCK_FOR_FN (fun, postorder[i]); - /* Propagate into PHIs and record degenerate ones in the lattice. */ + /* Record degenerate PHIs in the lattice. */ for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { @@ -2321,17 +2322,20 @@ pass_forwprop::execute (function *fun) FOR_EACH_PHI_ARG (use_p, phi, it, SSA_OP_USE) { tree use = USE_FROM_PTR (use_p); - tree tem = fwprop_ssa_val (use); if (! first) - first = tem; - else if (! operand_equal_p (first, tem, 0)) - all_same = false; - if (tem != use - && may_propagate_copy (use, tem)) - propagate_value (use_p, tem); + first = use; + else if (! operand_equal_p (first, use, 0)) + { + all_same = false; + break; + } } if (all_same) - fwprop_set_lattice_val (res, first); + { + if (may_propagate_copy (res, first)) + to_remove.safe_push (phi); + fwprop_set_lattice_val (res, first); + } } /* Apply forward propagation to all stmts in the basic-block. @@ -2648,148 +2652,227 @@ pass_forwprop::execute (function *fun) /* Combine stmts with the stmts defining their operands. Note we update GSI within the loop as necessary. */ - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - gimple *orig_stmt = stmt; - bool changed = false; - bool was_noreturn = (is_gimple_call (stmt) - && gimple_call_noreturn_p (stmt)); /* Mark stmt as potentially needing revisiting. */ gimple_set_plf (stmt, GF_PLF_1, false); - if (fold_stmt (&gsi, fwprop_ssa_val)) - { - changed = true; - stmt = gsi_stmt (gsi); - if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) - bitmap_set_bit (to_purge, bb->index); - if (!was_noreturn - && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) - to_fixup.safe_push (stmt); - /* Cleanup the CFG if we simplified a condition to - true or false. */ - if (gcond *cond = dyn_cast (stmt)) - if (gimple_cond_true_p (cond) - || gimple_cond_false_p (cond)) - cfg_changed = true; - update_stmt (stmt); - } - - switch (gimple_code (stmt)) - { - case GIMPLE_ASSIGN: - { - tree rhs1 = gimple_assign_rhs1 (stmt); - enum tree_code code = gimple_assign_rhs_code (stmt); + /* Substitute from our lattice. We need to do so only once. */ + bool substituted_p = false; + use_operand_p usep; + ssa_op_iter iter; + FOR_EACH_SSA_USE_OPERAND (usep, stmt, iter, SSA_OP_USE) + { + tree use = USE_FROM_PTR (usep); + tree val = fwprop_ssa_val (use); + if (val && val != use && may_propagate_copy (use, val)) + { + propagate_value (usep, val); + substituted_p = true; + } + } + if (substituted_p + && is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == ADDR_EXPR) + recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt)); + + bool changed; + do + { + gimple *orig_stmt = stmt = gsi_stmt (gsi); + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); + changed = false; + + if (fold_stmt (&gsi, fwprop_ssa_val)) + { + changed = true; + stmt = gsi_stmt (gsi); + /* Cleanup the CFG if we simplified a condition to + true or false. */ + if (gcond *cond = dyn_cast (stmt)) + if (gimple_cond_true_p (cond) + || gimple_cond_false_p (cond)) + cfg_changed = true; + } + + if (changed || substituted_p) + { + if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) + bitmap_set_bit (to_purge, bb->index); + if (!was_noreturn + && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) + to_fixup.safe_push (stmt); + update_stmt (stmt); + substituted_p = false; + } - if (code == COND_EXPR - || code == VEC_COND_EXPR) + switch (gimple_code (stmt)) + { + case GIMPLE_ASSIGN: { - /* In this case the entire COND_EXPR is in rhs1. */ - if (forward_propagate_into_cond (&gsi)) + tree rhs1 = gimple_assign_rhs1 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); + + if (code == COND_EXPR + || code == VEC_COND_EXPR) + { + /* In this case the entire COND_EXPR is in rhs1. */ + if (forward_propagate_into_cond (&gsi)) + { + changed = true; + stmt = gsi_stmt (gsi); + } + } + else if (TREE_CODE_CLASS (code) == tcc_comparison) { - changed = true; - stmt = gsi_stmt (gsi); + int did_something; + did_something = forward_propagate_into_comparison (&gsi); + if (maybe_clean_or_replace_eh_stmt (stmt, gsi_stmt (gsi))) + bitmap_set_bit (to_purge, bb->index); + if (did_something == 2) + cfg_changed = true; + changed = did_something != 0; } + else if ((code == PLUS_EXPR + || code == BIT_IOR_EXPR + || code == BIT_XOR_EXPR) + && simplify_rotate (&gsi)) + changed = true; + else if (code == VEC_PERM_EXPR) + { + int did_something = simplify_permutation (&gsi); + if (did_something == 2) + cfg_changed = true; + changed = did_something != 0; + } + else if (code == BIT_FIELD_REF) + changed = simplify_bitfield_ref (&gsi); + else if (code == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE) + changed = simplify_vector_constructor (&gsi); + break; } - else if (TREE_CODE_CLASS (code) == tcc_comparison) + + case GIMPLE_SWITCH: + changed = simplify_gimple_switch (as_a (stmt)); + break; + + case GIMPLE_COND: { - int did_something; - did_something = forward_propagate_into_comparison (&gsi); - if (maybe_clean_or_replace_eh_stmt (stmt, gsi_stmt (gsi))) - bitmap_set_bit (to_purge, bb->index); + int did_something = forward_propagate_into_gimple_cond + (as_a (stmt)); if (did_something == 2) cfg_changed = true; changed = did_something != 0; + break; } - else if ((code == PLUS_EXPR - || code == BIT_IOR_EXPR - || code == BIT_XOR_EXPR) - && simplify_rotate (&gsi)) - changed = true; - else if (code == VEC_PERM_EXPR) + + case GIMPLE_CALL: { - int did_something = simplify_permutation (&gsi); - if (did_something == 2) - cfg_changed = true; - changed = did_something != 0; + tree callee = gimple_call_fndecl (stmt); + if (callee != NULL_TREE + && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) + changed = simplify_builtin_call (&gsi, callee); + break; } - else if (code == BIT_FIELD_REF) - changed = simplify_bitfield_ref (&gsi); - else if (code == CONSTRUCTOR - && TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE) - changed = simplify_vector_constructor (&gsi); - break; - } - - case GIMPLE_SWITCH: - changed = simplify_gimple_switch (as_a (stmt)); - break; - - case GIMPLE_COND: - { - int did_something - = forward_propagate_into_gimple_cond (as_a (stmt)); - if (did_something == 2) - cfg_changed = true; - changed = did_something != 0; - break; - } - - case GIMPLE_CALL: - { - tree callee = gimple_call_fndecl (stmt); - if (callee != NULL_TREE - && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) - changed = simplify_builtin_call (&gsi, callee); - break; - } - - default:; - } - - if (changed) - { - /* If the stmt changed then re-visit it and the statements - inserted before it. */ - for (; !gsi_end_p (gsi); gsi_prev (&gsi)) - if (gimple_plf (gsi_stmt (gsi), GF_PLF_1)) - break; - if (gsi_end_p (gsi)) - gsi = gsi_start_bb (bb); - else - gsi_next (&gsi); - } - else - { - /* Stmt no longer needs to be revisited. */ - gimple_set_plf (stmt, GF_PLF_1, true); - /* Fill up the lattice. */ - if (gimple_assign_single_p (stmt)) + default:; + } + + if (changed) { - tree lhs = gimple_assign_lhs (stmt); - tree rhs = gimple_assign_rhs1 (stmt); - if (TREE_CODE (lhs) == SSA_NAME) - { - tree val = lhs; - if (TREE_CODE (rhs) == SSA_NAME) - val = fwprop_ssa_val (rhs); - else if (is_gimple_min_invariant (rhs)) - val = rhs; - fwprop_set_lattice_val (lhs, val); - } + /* If the stmt changed then re-visit it and the statements + inserted before it. We need to go back at least one + stmt since transforms above could have removed the + current stmt itself and thus advance to the next stmt + with undefined GF_PLF_1. But beware of that being + the last stmt. */ + if (gsi_end_p (gsi)) + gsi = gsi_last_bb (bb); + else + gsi_prev (&gsi); + for (; !gsi_end_p (gsi); gsi_prev (&gsi)) + if (gimple_plf (gsi_stmt (gsi), GF_PLF_1)) + break; + if (gsi_end_p (gsi)) + gsi = gsi_start_bb (bb); + else + gsi_next (&gsi); } + } + while (changed); - gsi_next (&gsi); + /* Stmt no longer needs to be revisited. */ + gimple_set_plf (stmt, GF_PLF_1, true); + + /* Fill up the lattice. */ + if (gimple_assign_single_p (stmt)) + { + tree lhs = gimple_assign_lhs (stmt); + tree rhs = gimple_assign_rhs1 (stmt); + if (TREE_CODE (lhs) == SSA_NAME) + { + tree val = lhs; + if (TREE_CODE (rhs) == SSA_NAME) + val = fwprop_ssa_val (rhs); + else if (is_gimple_min_invariant (rhs)) + val = rhs; + /* If we can propagate the lattice-value mark the + stmt for removal. */ + if (val != lhs + && may_propagate_copy (lhs, val)) + to_remove.safe_push (stmt); + fwprop_set_lattice_val (lhs, val); + } } } + + /* Substitute in destination PHI arguments. */ + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->succs) + for (gphi_iterator gsi = gsi_start_phis (e->dest); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gphi *phi = gsi.phi (); + use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e); + tree arg = USE_FROM_PTR (use_p); + if (TREE_CODE (arg) != SSA_NAME + || virtual_operand_p (arg)) + continue; + tree val = fwprop_ssa_val (arg); + if (val != arg + && may_propagate_copy (arg, val)) + propagate_value (use_p, val); + } } free (postorder); lattice.release (); + /* Remove stmts in reverse order to make debug stmt creation possible. */ + while (!to_remove.is_empty()) + { + gimple *stmt = to_remove.pop (); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Removing dead stmt "); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "\n"); + } + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + if (gimple_code (stmt) == GIMPLE_PHI) + remove_phi_node (&gsi, true); + else + { + unlink_stmt_vdef (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + } + } + /* Fixup stmts that became noreturn calls. This may require splitting blocks and thus isn't possible during the walk. Do this in reverse order so we don't inadvertedly remove a stmt we want to Index: gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c (revision 274422) +++ gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c (working copy) @@ -9,7 +9,6 @@ int foo (int x) return w - z; /* becomes 0 */ } -/* The original y = 0 stmt is also retained. */ -/* { dg-final { scan-tree-dump-times "= 0;" 2 "forwprop1" } } */ -/* { dg-final { scan-tree-dump-times "-" 0 "forwprop1" } } */ -/* { dg-final { scan-tree-dump-times "\\+" 1 "forwprop1" } } */ +/* Only z = x + 1 is retained. */ +/* { dg-final { scan-tree-dump-times " = " 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump "return 0;" "forwprop1" } } */ Index: gcc/fortran/trans-intrinsic.c =================================================================== --- gcc/fortran/trans-intrinsic.c (revision 274479) +++ gcc/fortran/trans-intrinsic.c (working copy) @@ -5428,7 +5428,7 @@ gfc_conv_intrinsic_findloc (gfc_se *se, tree type; tree tmp; tree found; - tree forward_branch; + tree forward_branch = NULL_TREE; tree back_branch; gfc_loopinfo loop; gfc_ss *arrayss;