Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-phiprop.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/tree-ssa-phiprop.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/tree-ssa-phiprop.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,5 +1,5 @@ /* Backward propagation of indirect loads through PHIs. - Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2007-2017 Free Software Foundation, Inc. Contributed by Richard Guenther <rguenther@suse.de> This file is part of GCC. @@ -21,18 +21,18 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.h" #include "tree.h" -#include "tm_p.h" -#include "basic-block.h" -#include "timevar.h" -#include "tree-pretty-print.h" +#include "gimple.h" +#include "tree-pass.h" +#include "ssa.h" #include "gimple-pretty-print.h" -#include "tree-flow.h" -#include "tree-pass.h" -#include "tree-dump.h" -#include "langhooks.h" -#include "flags.h" +#include "fold-const.h" +#include "tree-eh.h" +#include "gimplify.h" +#include "gimple-iterator.h" +#include "stor-layout.h" +#include "tree-ssa-loop.h" /* This pass propagates indirect loads through the PHI node for its address to make the load source possibly non-addressable and to @@ -104,7 +104,7 @@ phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb) { tree vuse = phivn[SSA_NAME_VERSION (name)].vuse; - gimple use_stmt; + gimple *use_stmt; imm_use_iterator ui2; bool ok = true; @@ -130,11 +130,11 @@ BB with the virtual operands from USE_STMT. */ static tree -phiprop_insert_phi (basic_block bb, gimple phi, gimple use_stmt, +phiprop_insert_phi (basic_block bb, gphi *phi, gimple *use_stmt, struct phiprop_d *phivn, size_t n) { tree res; - gimple new_phi; + gphi *new_phi = NULL; edge_iterator ei; edge e; @@ -144,12 +144,13 @@ /* Build a new PHI node to replace the definition of the indirect reference lhs. */ res = gimple_assign_lhs (use_stmt); - SSA_NAME_DEF_STMT (res) = new_phi = create_phi_node (res, bb); + if (TREE_CODE (res) == SSA_NAME) + new_phi = create_phi_node (res, bb); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserting PHI for result of load "); - print_gimple_stmt (dump_file, use_stmt, 0, 0); + print_gimple_stmt (dump_file, use_stmt, 0); } /* Add PHI arguments for each edge inserting loads of the @@ -157,7 +158,7 @@ FOR_EACH_EDGE (e, ei, bb->preds) { tree old_arg, new_var; - gimple tmp; + gassign *tmp; source_location locus; old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e); @@ -166,7 +167,7 @@ && (SSA_NAME_VERSION (old_arg) >= n || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE)) { - gimple def_stmt = SSA_NAME_DEF_STMT (old_arg); + gimple *def_stmt = SSA_NAME_DEF_STMT (old_arg); old_arg = gimple_assign_rhs1 (def_stmt); locus = gimple_location (def_stmt); } @@ -176,10 +177,10 @@ if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, " for edge defining "); - print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0); + print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e)); fprintf (dump_file, " reusing PHI result "); print_generic_expr (dump_file, - phivn[SSA_NAME_VERSION (old_arg)].value, 0); + phivn[SSA_NAME_VERSION (old_arg)].value); fprintf (dump_file, "\n"); } /* Reuse a formerly created dereference. */ @@ -189,7 +190,10 @@ { tree rhs = gimple_assign_rhs1 (use_stmt); gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR); - new_var = create_tmp_reg (TREE_TYPE (rhs), NULL); + if (TREE_CODE (res) == SSA_NAME) + new_var = make_ssa_name (TREE_TYPE (rhs)); + else + new_var = unshare_expr (res); if (!is_gimple_min_invariant (old_arg)) old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e); else @@ -198,10 +202,6 @@ fold_build2 (MEM_REF, TREE_TYPE (rhs), old_arg, TREE_OPERAND (rhs, 1))); - gcc_assert (is_gimple_reg (new_var)); - add_referenced_var (new_var); - new_var = make_ssa_name (new_var, tmp); - gimple_assign_set_lhs (tmp, new_var); gimple_set_location (tmp, locus); gsi_insert_on_edge (e, tmp); @@ -210,21 +210,38 @@ if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, " for edge defining "); - print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0); + print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e)); fprintf (dump_file, " inserting load "); - print_gimple_stmt (dump_file, tmp, 0, 0); + print_gimple_stmt (dump_file, tmp, 0); } } - add_phi_arg (new_phi, new_var, e, locus); + if (new_phi) + add_phi_arg (new_phi, new_var, e, locus); + } + + if (new_phi) + { + update_stmt (new_phi); + + if (dump_file && (dump_flags & TDF_DETAILS)) + print_gimple_stmt (dump_file, new_phi, 0); } - update_stmt (new_phi); + return res; +} + +/* Verify if *idx is available at *DATA. */ - if (dump_file && (dump_flags & TDF_DETAILS)) - print_gimple_stmt (dump_file, new_phi, 0, 0); - - return res; +static bool +chk_uses (tree, tree *idx, void *data) +{ + basic_block dom = (basic_block) data; + if (TREE_CODE (*idx) == SSA_NAME) + return (SSA_NAME_IS_DEFAULT_DEF (*idx) + || ! dominated_by_p (CDI_DOMINATORS, + gimple_bb (SSA_NAME_DEF_STMT (*idx)), dom)); + return true; } /* Propagate between the phi node arguments of PHI in BB and phi result @@ -242,11 +259,11 @@ with aliasing issues as we are moving memory reads. */ static bool -propagate_with_phi (basic_block bb, gimple phi, struct phiprop_d *phivn, +propagate_with_phi (basic_block bb, gphi *phi, struct phiprop_d *phivn, size_t n) { tree ptr = PHI_RESULT (phi); - gimple use_stmt; + gimple *use_stmt; tree res = NULL_TREE; gimple_stmt_iterator gsi; imm_use_iterator ui; @@ -254,10 +271,10 @@ ssa_op_iter i; bool phi_inserted; tree type = NULL_TREE; - bool one_invariant = false; if (!POINTER_TYPE_P (TREE_TYPE (ptr)) - || !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))) + || (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))) + && TYPE_MODE (TREE_TYPE (TREE_TYPE (ptr))) == BLKmode)) return false; /* Check if we can "cheaply" dereference all phi arguments. */ @@ -272,7 +289,7 @@ && (SSA_NAME_VERSION (arg) >= n || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE)) { - gimple def_stmt = SSA_NAME_DEF_STMT (arg); + gimple *def_stmt = SSA_NAME_DEF_STMT (arg); if (!gimple_assign_single_p (def_stmt)) return false; arg = gimple_assign_rhs1 (def_stmt); @@ -289,17 +306,8 @@ if (!type && TREE_CODE (arg) == SSA_NAME) type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value); - if (TREE_CODE (arg) == ADDR_EXPR - && is_gimple_min_invariant (arg)) - one_invariant = true; } - /* If we neither have an address of a decl nor can reuse a previously - inserted load, do not hoist anything. */ - if (!one_invariant - && !type) - return false; - /* Find a dereferencing use. First follow (single use) ssa copy chains for ptr. */ while (single_imm_use (ptr, &use, &use_stmt) @@ -311,12 +319,17 @@ phi_inserted = false; FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr) { - gimple def_stmt; + gimple *def_stmt; tree vuse; + /* Only replace loads in blocks that post-dominate the PHI node. That + makes sure we don't end up speculating loads. */ + if (!dominated_by_p (CDI_POST_DOMINATORS, + bb, gimple_bb (use_stmt))) + continue; + /* Check whether this is a load of *ptr. */ if (!(is_gimple_assign (use_stmt) - && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME && gimple_assign_rhs_code (use_stmt) == MEM_REF && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1)) @@ -328,18 +341,74 @@ continue; /* Check if we can move the loads. The def stmt of the virtual use - needs to be in a different basic block dominating bb. */ + needs to be in a different basic block dominating bb. When the + def is an edge-inserted one we know it dominates us. */ vuse = gimple_vuse (use_stmt); def_stmt = SSA_NAME_DEF_STMT (vuse); if (!SSA_NAME_IS_DEFAULT_DEF (vuse) && (gimple_bb (def_stmt) == bb - || !dominated_by_p (CDI_DOMINATORS, - bb, gimple_bb (def_stmt)))) + || (gimple_bb (def_stmt) + && !dominated_by_p (CDI_DOMINATORS, + bb, gimple_bb (def_stmt))))) goto next; + /* Found a proper dereference with an aggregate copy. Just + insert aggregate copies on the edges instead. */ + if (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))) + { + if (!gimple_vdef (use_stmt)) + goto next; + + /* As we replicate the lhs on each incoming edge all + used SSA names have to be available there. */ + if (! for_each_index (gimple_assign_lhs_ptr (use_stmt), + chk_uses, + get_immediate_dominator (CDI_DOMINATORS, + gimple_bb (phi)))) + goto next; + + gimple *vuse_stmt; + imm_use_iterator vui; + use_operand_p vuse_p; + /* In order to move the aggregate copies earlier, make sure + there are no statements that could read from memory + aliasing the lhs in between the start of bb and use_stmt. + As we require use_stmt to have a VDEF above, loads after + use_stmt will use a different virtual SSA_NAME. */ + FOR_EACH_IMM_USE_FAST (vuse_p, vui, vuse) + { + vuse_stmt = USE_STMT (vuse_p); + if (vuse_stmt == use_stmt) + continue; + if (!dominated_by_p (CDI_DOMINATORS, + gimple_bb (vuse_stmt), bb)) + continue; + if (ref_maybe_used_by_stmt_p (vuse_stmt, + gimple_assign_lhs (use_stmt))) + goto next; + } + + phiprop_insert_phi (bb, phi, use_stmt, phivn, n); + + /* Remove old stmt. The phi is taken care of by DCE. */ + gsi = gsi_for_stmt (use_stmt); + /* Unlinking the VDEF here is fine as we are sure that we process + stmts in execution order due to aggregate copies having VDEFs + and we emit loads on the edges in the very same order. + We get multiple copies (or intermediate register loads) handled + only by walking PHIs or immediate uses in a lucky order though, + so we could signal the caller to re-start iterating over PHIs + when we come here which would make it quadratic in the number + of PHIs. */ + unlink_stmt_vdef (use_stmt); + gsi_remove (&gsi, true); + + phi_inserted = true; + } + /* Found a proper dereference. Insert a phi node if this is the first load transformation. */ - if (!phi_inserted) + else if (!phi_inserted) { res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n); type = TREE_TYPE (res); @@ -373,62 +442,73 @@ /* Main entry for phiprop pass. */ -static unsigned int -tree_ssa_phiprop (void) +namespace { + +const pass_data pass_data_phiprop = { - VEC(basic_block, heap) *bbs; + GIMPLE_PASS, /* type */ + "phiprop", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_PHIPROP, /* tv_id */ + ( PROP_cfg | PROP_ssa ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_phiprop : public gimple_opt_pass +{ +public: + pass_phiprop (gcc::context *ctxt) + : gimple_opt_pass (pass_data_phiprop, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) { return flag_tree_phiprop; } + virtual unsigned int execute (function *); + +}; // class pass_phiprop + +unsigned int +pass_phiprop::execute (function *fun) +{ + vec<basic_block> bbs; struct phiprop_d *phivn; bool did_something = false; basic_block bb; - gimple_stmt_iterator gsi; + gphi_iterator gsi; unsigned i; size_t n; calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); n = num_ssa_names; phivn = XCNEWVEC (struct phiprop_d, n); /* Walk the dominator tree in preorder. */ bbs = get_all_dominated_blocks (CDI_DOMINATORS, - single_succ (ENTRY_BLOCK_PTR)); - FOR_EACH_VEC_ELT (basic_block, bbs, i, bb) + single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun))); + FOR_EACH_VEC_ELT (bbs, i, bb) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n); + did_something |= propagate_with_phi (bb, gsi.phi (), phivn, n); if (did_something) gsi_commit_edge_inserts (); - VEC_free (basic_block, heap, bbs); + bbs.release (); free (phivn); + free_dominance_info (CDI_POST_DOMINATORS); + return 0; } -static bool -gate_phiprop (void) -{ - return flag_tree_phiprop; -} +} // anon namespace -struct gimple_opt_pass pass_phiprop = +gimple_opt_pass * +make_pass_phiprop (gcc::context *ctxt) { - { - GIMPLE_PASS, - "phiprop", /* name */ - gate_phiprop, /* gate */ - tree_ssa_phiprop, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_TREE_PHIPROP, /* tv_id */ - PROP_cfg | PROP_ssa, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func - | TODO_ggc_collect - | TODO_update_ssa - | TODO_verify_ssa /* todo_flags_finish */ - } -}; + return new pass_phiprop (ctxt); +}