xref: /dflybsd-src/contrib/gcc-8.0/gcc/tree-ssa-phiprop.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Backward propagation of indirect loads through PHIs.
238fd1498Szrj    Copyright (C) 2007-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Richard Guenther <rguenther@suse.de>
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify
838fd1498Szrj it under the terms of the GNU General Public License as published by
938fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
1038fd1498Szrj any later version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful,
1338fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1438fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1538fd1498Szrj GNU General Public License for more details.
1638fd1498Szrj 
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3.  If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>.  */
2038fd1498Szrj 
2138fd1498Szrj #include "config.h"
2238fd1498Szrj #include "system.h"
2338fd1498Szrj #include "coretypes.h"
2438fd1498Szrj #include "backend.h"
2538fd1498Szrj #include "tree.h"
2638fd1498Szrj #include "gimple.h"
2738fd1498Szrj #include "tree-pass.h"
2838fd1498Szrj #include "ssa.h"
2938fd1498Szrj #include "gimple-pretty-print.h"
3038fd1498Szrj #include "fold-const.h"
3138fd1498Szrj #include "tree-eh.h"
3238fd1498Szrj #include "gimplify.h"
3338fd1498Szrj #include "gimple-iterator.h"
3438fd1498Szrj #include "stor-layout.h"
3538fd1498Szrj #include "tree-ssa-loop.h"
3638fd1498Szrj 
3738fd1498Szrj /* This pass propagates indirect loads through the PHI node for its
3838fd1498Szrj    address to make the load source possibly non-addressable and to
3938fd1498Szrj    allow for PHI optimization to trigger.
4038fd1498Szrj 
4138fd1498Szrj    For example the pass changes
4238fd1498Szrj 
4338fd1498Szrj      # addr_1 = PHI <&a, &b>
4438fd1498Szrj      tmp_1 = *addr_1;
4538fd1498Szrj 
4638fd1498Szrj    to
4738fd1498Szrj 
4838fd1498Szrj      # tmp_1 = PHI <a, b>
4938fd1498Szrj 
5038fd1498Szrj    but also handles more complex scenarios like
5138fd1498Szrj 
5238fd1498Szrj      D.2077_2 = &this_1(D)->a1;
5338fd1498Szrj      ...
5438fd1498Szrj 
5538fd1498Szrj      # b_12 = PHI <&c(2), D.2077_2(3)>
5638fd1498Szrj      D.2114_13 = *b_12;
5738fd1498Szrj      ...
5838fd1498Szrj 
5938fd1498Szrj      # b_15 = PHI <b_12(4), &b(5)>
6038fd1498Szrj      D.2080_5 = &this_1(D)->a0;
6138fd1498Szrj      ...
6238fd1498Szrj 
6338fd1498Szrj      # b_18 = PHI <D.2080_5(6), &c(7)>
6438fd1498Szrj      ...
6538fd1498Szrj 
6638fd1498Szrj      # b_21 = PHI <b_15(8), b_18(9)>
6738fd1498Szrj      D.2076_8 = *b_21;
6838fd1498Szrj 
6938fd1498Szrj    where the addresses loaded are defined by PHIs itself.
7038fd1498Szrj    The above happens for
7138fd1498Szrj 
7238fd1498Szrj      std::max(std::min(a0, c), std::min(std::max(a1, c), b))
7338fd1498Szrj 
7438fd1498Szrj    where this pass transforms it to a form later PHI optimization
7538fd1498Szrj    recognizes and transforms it to the simple
7638fd1498Szrj 
7738fd1498Szrj      D.2109_10 = this_1(D)->a1;
7838fd1498Szrj      D.2110_11 = c;
7938fd1498Szrj      D.2114_31 = MAX_EXPR <D.2109_10, D.2110_11>;
8038fd1498Szrj      D.2115_14 = b;
8138fd1498Szrj      D.2125_17 = MIN_EXPR <D.2115_14, D.2114_31>;
8238fd1498Szrj      D.2119_16 = this_1(D)->a0;
8338fd1498Szrj      D.2124_32 = MIN_EXPR <D.2110_11, D.2119_16>;
8438fd1498Szrj      D.2076_33 = MAX_EXPR <D.2125_17, D.2124_32>;
8538fd1498Szrj 
8638fd1498Szrj    The pass does a dominator walk processing loads using a basic-block
8738fd1498Szrj    local analysis and stores the result for use by transformations on
8838fd1498Szrj    dominated basic-blocks.  */
8938fd1498Szrj 
9038fd1498Szrj 
9138fd1498Szrj /* Structure to keep track of the value of a dereferenced PHI result
9238fd1498Szrj    and the virtual operand used for that dereference.  */
9338fd1498Szrj 
9438fd1498Szrj struct phiprop_d
9538fd1498Szrj {
9638fd1498Szrj   tree value;
9738fd1498Szrj   tree vuse;
9838fd1498Szrj };
9938fd1498Szrj 
10038fd1498Szrj /* Verify if the value recorded for NAME in PHIVN is still valid at
10138fd1498Szrj    the start of basic block BB.  */
10238fd1498Szrj 
10338fd1498Szrj static bool
phivn_valid_p(struct phiprop_d * phivn,tree name,basic_block bb)10438fd1498Szrj phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
10538fd1498Szrj {
10638fd1498Szrj   tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
10738fd1498Szrj   gimple *use_stmt;
10838fd1498Szrj   imm_use_iterator ui2;
10938fd1498Szrj   bool ok = true;
11038fd1498Szrj 
11138fd1498Szrj   /* The def stmts of the virtual uses need to be dominated by bb.  */
11238fd1498Szrj   gcc_assert (vuse != NULL_TREE);
11338fd1498Szrj 
11438fd1498Szrj   FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
11538fd1498Szrj     {
11638fd1498Szrj       /* If BB does not dominate a VDEF, the value is invalid.  */
11738fd1498Szrj       if ((gimple_vdef (use_stmt) != NULL_TREE
11838fd1498Szrj 	   || gimple_code (use_stmt) == GIMPLE_PHI)
11938fd1498Szrj 	  && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
12038fd1498Szrj 	{
12138fd1498Szrj 	  ok = false;
12238fd1498Szrj 	  BREAK_FROM_IMM_USE_STMT (ui2);
12338fd1498Szrj 	}
12438fd1498Szrj     }
12538fd1498Szrj 
12638fd1498Szrj   return ok;
12738fd1498Szrj }
12838fd1498Szrj 
12938fd1498Szrj /* Insert a new phi node for the dereference of PHI at basic_block
13038fd1498Szrj    BB with the virtual operands from USE_STMT.  */
13138fd1498Szrj 
13238fd1498Szrj static tree
phiprop_insert_phi(basic_block bb,gphi * phi,gimple * use_stmt,struct phiprop_d * phivn,size_t n)13338fd1498Szrj phiprop_insert_phi (basic_block bb, gphi *phi, gimple *use_stmt,
13438fd1498Szrj 		    struct phiprop_d *phivn, size_t n)
13538fd1498Szrj {
13638fd1498Szrj   tree res;
13738fd1498Szrj   gphi *new_phi = NULL;
13838fd1498Szrj   edge_iterator ei;
13938fd1498Szrj   edge e;
14038fd1498Szrj 
14138fd1498Szrj   gcc_assert (is_gimple_assign (use_stmt)
14238fd1498Szrj 	      && gimple_assign_rhs_code (use_stmt) == MEM_REF);
14338fd1498Szrj 
14438fd1498Szrj   /* Build a new PHI node to replace the definition of
14538fd1498Szrj      the indirect reference lhs.  */
14638fd1498Szrj   res = gimple_assign_lhs (use_stmt);
14738fd1498Szrj   if (TREE_CODE (res) == SSA_NAME)
14838fd1498Szrj     new_phi = create_phi_node (res, bb);
14938fd1498Szrj 
15038fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
15138fd1498Szrj     {
15238fd1498Szrj       fprintf (dump_file, "Inserting PHI for result of load ");
15338fd1498Szrj       print_gimple_stmt (dump_file, use_stmt, 0);
15438fd1498Szrj     }
15538fd1498Szrj 
15638fd1498Szrj   /* Add PHI arguments for each edge inserting loads of the
15738fd1498Szrj      addressable operands.  */
15838fd1498Szrj   FOR_EACH_EDGE (e, ei, bb->preds)
15938fd1498Szrj     {
16038fd1498Szrj       tree old_arg, new_var;
16138fd1498Szrj       gassign *tmp;
16238fd1498Szrj       source_location locus;
16338fd1498Szrj 
16438fd1498Szrj       old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
16538fd1498Szrj       locus = gimple_phi_arg_location_from_edge (phi, e);
16638fd1498Szrj       while (TREE_CODE (old_arg) == SSA_NAME
16738fd1498Szrj 	     && (SSA_NAME_VERSION (old_arg) >= n
16838fd1498Szrj 	         || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
16938fd1498Szrj 	{
17038fd1498Szrj 	  gimple *def_stmt = SSA_NAME_DEF_STMT (old_arg);
17138fd1498Szrj 	  old_arg = gimple_assign_rhs1 (def_stmt);
17238fd1498Szrj 	  locus = gimple_location (def_stmt);
17338fd1498Szrj 	}
17438fd1498Szrj 
17538fd1498Szrj       if (TREE_CODE (old_arg) == SSA_NAME)
17638fd1498Szrj 	{
17738fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
17838fd1498Szrj 	    {
17938fd1498Szrj 	      fprintf (dump_file, "  for edge defining ");
18038fd1498Szrj 	      print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
18138fd1498Szrj 	      fprintf (dump_file, " reusing PHI result ");
18238fd1498Szrj 	      print_generic_expr (dump_file,
18338fd1498Szrj 				  phivn[SSA_NAME_VERSION (old_arg)].value);
18438fd1498Szrj 	      fprintf (dump_file, "\n");
18538fd1498Szrj 	    }
18638fd1498Szrj 	  /* Reuse a formerly created dereference.  */
18738fd1498Szrj 	  new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
18838fd1498Szrj 	}
18938fd1498Szrj       else
19038fd1498Szrj 	{
19138fd1498Szrj 	  tree rhs = gimple_assign_rhs1 (use_stmt);
19238fd1498Szrj 	  gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
19338fd1498Szrj 	  if (TREE_CODE (res) == SSA_NAME)
19438fd1498Szrj 	    new_var = make_ssa_name (TREE_TYPE (rhs));
19538fd1498Szrj 	  else
19638fd1498Szrj 	    new_var = unshare_expr (res);
19738fd1498Szrj 	  if (!is_gimple_min_invariant (old_arg))
19838fd1498Szrj 	    old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
19938fd1498Szrj 	  else
20038fd1498Szrj 	    old_arg = unshare_expr (old_arg);
20138fd1498Szrj 	  tmp = gimple_build_assign (new_var,
20238fd1498Szrj 				     fold_build2 (MEM_REF, TREE_TYPE (rhs),
20338fd1498Szrj 						  old_arg,
20438fd1498Szrj 						  TREE_OPERAND (rhs, 1)));
20538fd1498Szrj 	  gimple_set_location (tmp, locus);
20638fd1498Szrj 
20738fd1498Szrj 	  gsi_insert_on_edge (e, tmp);
20838fd1498Szrj 	  update_stmt (tmp);
20938fd1498Szrj 
21038fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
21138fd1498Szrj 	    {
21238fd1498Szrj 	      fprintf (dump_file, "  for edge defining ");
21338fd1498Szrj 	      print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
21438fd1498Szrj 	      fprintf (dump_file, " inserting load ");
21538fd1498Szrj 	      print_gimple_stmt (dump_file, tmp, 0);
21638fd1498Szrj 	    }
21738fd1498Szrj 	}
21838fd1498Szrj 
21938fd1498Szrj       if (new_phi)
22038fd1498Szrj 	add_phi_arg (new_phi, new_var, e, locus);
22138fd1498Szrj     }
22238fd1498Szrj 
22338fd1498Szrj   if (new_phi)
22438fd1498Szrj     {
22538fd1498Szrj       update_stmt (new_phi);
22638fd1498Szrj 
22738fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
22838fd1498Szrj 	print_gimple_stmt (dump_file, new_phi, 0);
22938fd1498Szrj     }
23038fd1498Szrj 
23138fd1498Szrj   return res;
23238fd1498Szrj }
23338fd1498Szrj 
23438fd1498Szrj /* Verify if *idx is available at *DATA.  */
23538fd1498Szrj 
23638fd1498Szrj static bool
chk_uses(tree,tree * idx,void * data)23738fd1498Szrj chk_uses (tree, tree *idx, void *data)
23838fd1498Szrj {
23938fd1498Szrj   basic_block dom = (basic_block) data;
24038fd1498Szrj   if (TREE_CODE (*idx) == SSA_NAME)
24138fd1498Szrj     return (SSA_NAME_IS_DEFAULT_DEF (*idx)
24238fd1498Szrj 	    || ! dominated_by_p (CDI_DOMINATORS,
24338fd1498Szrj 				 gimple_bb (SSA_NAME_DEF_STMT (*idx)), dom));
24438fd1498Szrj   return true;
24538fd1498Szrj }
24638fd1498Szrj 
24738fd1498Szrj /* Propagate between the phi node arguments of PHI in BB and phi result
24838fd1498Szrj    users.  For now this matches
24938fd1498Szrj         # p_2 = PHI <&x, &y>
25038fd1498Szrj       <Lx>:;
25138fd1498Szrj 	p_3 = p_2;
25238fd1498Szrj 	z_2 = *p_3;
25338fd1498Szrj    and converts it to
25438fd1498Szrj 	# z_2 = PHI <x, y>
25538fd1498Szrj       <Lx>:;
25638fd1498Szrj    Returns true if a transformation was done and edge insertions
25738fd1498Szrj    need to be committed.  Global data PHIVN and N is used to track
25838fd1498Szrj    past transformation results.  We need to be especially careful here
25938fd1498Szrj    with aliasing issues as we are moving memory reads.  */
26038fd1498Szrj 
26138fd1498Szrj static bool
propagate_with_phi(basic_block bb,gphi * phi,struct phiprop_d * phivn,size_t n)26238fd1498Szrj propagate_with_phi (basic_block bb, gphi *phi, struct phiprop_d *phivn,
26338fd1498Szrj 		    size_t n)
26438fd1498Szrj {
26538fd1498Szrj   tree ptr = PHI_RESULT (phi);
26638fd1498Szrj   gimple *use_stmt;
26738fd1498Szrj   tree res = NULL_TREE;
26838fd1498Szrj   gimple_stmt_iterator gsi;
26938fd1498Szrj   imm_use_iterator ui;
27038fd1498Szrj   use_operand_p arg_p, use;
27138fd1498Szrj   ssa_op_iter i;
27238fd1498Szrj   bool phi_inserted;
27338fd1498Szrj   bool changed;
27438fd1498Szrj   tree type = NULL_TREE;
27538fd1498Szrj 
27638fd1498Szrj   if (!POINTER_TYPE_P (TREE_TYPE (ptr))
27738fd1498Szrj       || (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))
27838fd1498Szrj 	  && TYPE_MODE (TREE_TYPE (TREE_TYPE (ptr))) == BLKmode))
27938fd1498Szrj     return false;
28038fd1498Szrj 
28138fd1498Szrj   /* Check if we can "cheaply" dereference all phi arguments.  */
28238fd1498Szrj   FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_USE)
28338fd1498Szrj     {
28438fd1498Szrj       tree arg = USE_FROM_PTR (arg_p);
28538fd1498Szrj       /* Walk the ssa chain until we reach a ssa name we already
28638fd1498Szrj 	 created a value for or we reach a definition of the form
28738fd1498Szrj 	 ssa_name_n = &var;  */
28838fd1498Szrj       while (TREE_CODE (arg) == SSA_NAME
28938fd1498Szrj 	     && !SSA_NAME_IS_DEFAULT_DEF (arg)
29038fd1498Szrj 	     && (SSA_NAME_VERSION (arg) >= n
29138fd1498Szrj 	         || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
29238fd1498Szrj 	{
29338fd1498Szrj 	  gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
29438fd1498Szrj 	  if (!gimple_assign_single_p (def_stmt))
29538fd1498Szrj 	    return false;
29638fd1498Szrj 	  arg = gimple_assign_rhs1 (def_stmt);
29738fd1498Szrj 	}
29838fd1498Szrj       if (TREE_CODE (arg) != ADDR_EXPR
29938fd1498Szrj 	  && !(TREE_CODE (arg) == SSA_NAME
30038fd1498Szrj 	       && SSA_NAME_VERSION (arg) < n
30138fd1498Szrj 	       && phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
30238fd1498Szrj 	       && (!type
30338fd1498Szrj 		   || types_compatible_p
30438fd1498Szrj 		       (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value)))
30538fd1498Szrj 	       && phivn_valid_p (phivn, arg, bb)))
30638fd1498Szrj 	return false;
30738fd1498Szrj       if (!type
30838fd1498Szrj 	  && TREE_CODE (arg) == SSA_NAME)
30938fd1498Szrj 	type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
31038fd1498Szrj     }
31138fd1498Szrj 
31238fd1498Szrj   /* Find a dereferencing use.  First follow (single use) ssa
31338fd1498Szrj      copy chains for ptr.  */
31438fd1498Szrj   while (single_imm_use (ptr, &use, &use_stmt)
31538fd1498Szrj 	 && gimple_assign_ssa_name_copy_p (use_stmt))
31638fd1498Szrj     ptr = gimple_assign_lhs (use_stmt);
31738fd1498Szrj 
31838fd1498Szrj   /* Replace the first dereference of *ptr if there is one and if we
31938fd1498Szrj      can move the loads to the place of the ptr phi node.  */
32038fd1498Szrj   phi_inserted = false;
32138fd1498Szrj   changed = false;
32238fd1498Szrj   FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
32338fd1498Szrj     {
32438fd1498Szrj       gimple *def_stmt;
32538fd1498Szrj       tree vuse;
32638fd1498Szrj 
32738fd1498Szrj       /* Only replace loads in blocks that post-dominate the PHI node.  That
32838fd1498Szrj          makes sure we don't end up speculating loads.  */
32938fd1498Szrj       if (!dominated_by_p (CDI_POST_DOMINATORS,
33038fd1498Szrj 			   bb, gimple_bb (use_stmt)))
33138fd1498Szrj 	continue;
33238fd1498Szrj 
33338fd1498Szrj       /* Check whether this is a load of *ptr.  */
33438fd1498Szrj       if (!(is_gimple_assign (use_stmt)
33538fd1498Szrj 	    && gimple_assign_rhs_code (use_stmt) == MEM_REF
33638fd1498Szrj 	    && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
33738fd1498Szrj 	    && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
33838fd1498Szrj 	    && (!type
33938fd1498Szrj 		|| types_compatible_p
34038fd1498Szrj 		     (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
34138fd1498Szrj 	    /* We cannot replace a load that may throw or is volatile.  */
34238fd1498Szrj 	    && !stmt_can_throw_internal (use_stmt)))
34338fd1498Szrj 	continue;
34438fd1498Szrj 
34538fd1498Szrj       /* Check if we can move the loads.  The def stmt of the virtual use
34638fd1498Szrj 	 needs to be in a different basic block dominating bb.  When the
34738fd1498Szrj 	 def is an edge-inserted one we know it dominates us.  */
34838fd1498Szrj       vuse = gimple_vuse (use_stmt);
34938fd1498Szrj       def_stmt = SSA_NAME_DEF_STMT (vuse);
35038fd1498Szrj       if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
35138fd1498Szrj 	  && (gimple_bb (def_stmt) == bb
35238fd1498Szrj 	      || (gimple_bb (def_stmt)
35338fd1498Szrj 		  && !dominated_by_p (CDI_DOMINATORS,
35438fd1498Szrj 				      bb, gimple_bb (def_stmt)))))
35538fd1498Szrj 	goto next;
35638fd1498Szrj 
35738fd1498Szrj       /* Found a proper dereference with an aggregate copy.  Just
35838fd1498Szrj          insert aggregate copies on the edges instead.  */
35938fd1498Szrj       if (!is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (use_stmt))))
36038fd1498Szrj 	{
36138fd1498Szrj 	  if (!gimple_vdef (use_stmt))
36238fd1498Szrj 	    goto next;
36338fd1498Szrj 
36438fd1498Szrj 	  /* As we replicate the lhs on each incoming edge all
36538fd1498Szrj 	     used SSA names have to be available there.  */
36638fd1498Szrj 	  if (! for_each_index (gimple_assign_lhs_ptr (use_stmt),
36738fd1498Szrj 				chk_uses,
36838fd1498Szrj 				get_immediate_dominator (CDI_DOMINATORS,
36938fd1498Szrj 							 gimple_bb (phi))))
37038fd1498Szrj 	    goto next;
37138fd1498Szrj 
37238fd1498Szrj 	  gimple *vuse_stmt;
37338fd1498Szrj 	  imm_use_iterator vui;
37438fd1498Szrj 	  use_operand_p vuse_p;
37538fd1498Szrj 	  /* In order to move the aggregate copies earlier, make sure
37638fd1498Szrj 	     there are no statements that could read from memory
37738fd1498Szrj 	     aliasing the lhs in between the start of bb and use_stmt.
37838fd1498Szrj 	     As we require use_stmt to have a VDEF above, loads after
37938fd1498Szrj 	     use_stmt will use a different virtual SSA_NAME.  */
38038fd1498Szrj 	  FOR_EACH_IMM_USE_FAST (vuse_p, vui, vuse)
38138fd1498Szrj 	    {
38238fd1498Szrj 	      vuse_stmt = USE_STMT (vuse_p);
38338fd1498Szrj 	      if (vuse_stmt == use_stmt)
38438fd1498Szrj 		continue;
38538fd1498Szrj 	      if (!dominated_by_p (CDI_DOMINATORS,
38638fd1498Szrj 				   gimple_bb (vuse_stmt), bb))
38738fd1498Szrj 		continue;
38838fd1498Szrj 	      if (ref_maybe_used_by_stmt_p (vuse_stmt,
38938fd1498Szrj 					    gimple_assign_lhs (use_stmt)))
39038fd1498Szrj 		goto next;
39138fd1498Szrj 	    }
39238fd1498Szrj 
39338fd1498Szrj 	  phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
39438fd1498Szrj 
39538fd1498Szrj 	  /* Remove old stmt.  The phi is taken care of by DCE.  */
39638fd1498Szrj 	  gsi = gsi_for_stmt (use_stmt);
39738fd1498Szrj 	  /* Unlinking the VDEF here is fine as we are sure that we process
39838fd1498Szrj 	     stmts in execution order due to aggregate copies having VDEFs
39938fd1498Szrj 	     and we emit loads on the edges in the very same order.
40038fd1498Szrj 	     We get multiple copies (or intermediate register loads) handled
40138fd1498Szrj 	     only by walking PHIs or immediate uses in a lucky order though,
40238fd1498Szrj 	     so we could signal the caller to re-start iterating over PHIs
40338fd1498Szrj 	     when we come here which would make it quadratic in the number
40438fd1498Szrj 	     of PHIs.  */
40538fd1498Szrj 	  unlink_stmt_vdef (use_stmt);
40638fd1498Szrj 	  gsi_remove (&gsi, true);
40738fd1498Szrj 
40838fd1498Szrj 	  changed = true;
40938fd1498Szrj 	}
41038fd1498Szrj 
41138fd1498Szrj       /* Found a proper dereference.  Insert a phi node if this
41238fd1498Szrj 	 is the first load transformation.  */
41338fd1498Szrj       else if (!phi_inserted)
41438fd1498Szrj 	{
41538fd1498Szrj 	  res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
41638fd1498Szrj 	  type = TREE_TYPE (res);
41738fd1498Szrj 
41838fd1498Szrj 	  /* Remember the value we created for *ptr.  */
41938fd1498Szrj 	  phivn[SSA_NAME_VERSION (ptr)].value = res;
42038fd1498Szrj 	  phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
42138fd1498Szrj 
42238fd1498Szrj 	  /* Remove old stmt.  The phi is taken care of by DCE, if we
42338fd1498Szrj 	     want to delete it here we also have to delete all intermediate
42438fd1498Szrj 	     copies.  */
42538fd1498Szrj 	  gsi = gsi_for_stmt (use_stmt);
42638fd1498Szrj 	  gsi_remove (&gsi, true);
42738fd1498Szrj 
42838fd1498Szrj 	  phi_inserted = true;
42938fd1498Szrj 	  changed = true;
43038fd1498Szrj 	}
43138fd1498Szrj       else
43238fd1498Szrj 	{
43338fd1498Szrj 	  /* Further replacements are easy, just make a copy out of the
43438fd1498Szrj 	     load.  */
43538fd1498Szrj 	  gimple_assign_set_rhs1 (use_stmt, res);
43638fd1498Szrj 	  update_stmt (use_stmt);
43738fd1498Szrj 	  changed = true;
43838fd1498Szrj 	}
43938fd1498Szrj 
44038fd1498Szrj next:;
44138fd1498Szrj       /* Continue searching for a proper dereference.  */
44238fd1498Szrj     }
44338fd1498Szrj 
44438fd1498Szrj   return changed;
44538fd1498Szrj }
44638fd1498Szrj 
44738fd1498Szrj /* Main entry for phiprop pass.  */
44838fd1498Szrj 
44938fd1498Szrj namespace {
45038fd1498Szrj 
45138fd1498Szrj const pass_data pass_data_phiprop =
45238fd1498Szrj {
45338fd1498Szrj   GIMPLE_PASS, /* type */
45438fd1498Szrj   "phiprop", /* name */
45538fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
45638fd1498Szrj   TV_TREE_PHIPROP, /* tv_id */
45738fd1498Szrj   ( PROP_cfg | PROP_ssa ), /* properties_required */
45838fd1498Szrj   0, /* properties_provided */
45938fd1498Szrj   0, /* properties_destroyed */
46038fd1498Szrj   0, /* todo_flags_start */
46138fd1498Szrj   TODO_update_ssa, /* todo_flags_finish */
46238fd1498Szrj };
46338fd1498Szrj 
46438fd1498Szrj class pass_phiprop : public gimple_opt_pass
46538fd1498Szrj {
46638fd1498Szrj public:
pass_phiprop(gcc::context * ctxt)46738fd1498Szrj   pass_phiprop (gcc::context *ctxt)
46838fd1498Szrj     : gimple_opt_pass (pass_data_phiprop, ctxt)
46938fd1498Szrj   {}
47038fd1498Szrj 
47138fd1498Szrj   /* opt_pass methods: */
gate(function *)47238fd1498Szrj   virtual bool gate (function *) { return flag_tree_phiprop; }
47338fd1498Szrj   virtual unsigned int execute (function *);
47438fd1498Szrj 
47538fd1498Szrj }; // class pass_phiprop
47638fd1498Szrj 
47738fd1498Szrj unsigned int
execute(function * fun)47838fd1498Szrj pass_phiprop::execute (function *fun)
47938fd1498Szrj {
48038fd1498Szrj   vec<basic_block> bbs;
48138fd1498Szrj   struct phiprop_d *phivn;
48238fd1498Szrj   bool did_something = false;
48338fd1498Szrj   basic_block bb;
48438fd1498Szrj   gphi_iterator gsi;
48538fd1498Szrj   unsigned i;
48638fd1498Szrj   size_t n;
48738fd1498Szrj 
48838fd1498Szrj   calculate_dominance_info (CDI_DOMINATORS);
48938fd1498Szrj   calculate_dominance_info (CDI_POST_DOMINATORS);
49038fd1498Szrj 
49138fd1498Szrj   n = num_ssa_names;
49238fd1498Szrj   phivn = XCNEWVEC (struct phiprop_d, n);
49338fd1498Szrj 
49438fd1498Szrj   /* Walk the dominator tree in preorder.  */
49538fd1498Szrj   bbs = get_all_dominated_blocks (CDI_DOMINATORS,
49638fd1498Szrj 				  single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
49738fd1498Szrj   FOR_EACH_VEC_ELT (bbs, i, bb)
498*58e805e6Szrj     {
499*58e805e6Szrj       /* Since we're going to move dereferences across predecessor
500*58e805e6Szrj          edges avoid blocks with abnormal predecessors.  */
501*58e805e6Szrj       if (bb_has_abnormal_pred (bb))
502*58e805e6Szrj 	continue;
50338fd1498Szrj       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
50438fd1498Szrj 	did_something |= propagate_with_phi (bb, gsi.phi (), phivn, n);
505*58e805e6Szrj     }
50638fd1498Szrj 
50738fd1498Szrj   if (did_something)
50838fd1498Szrj     gsi_commit_edge_inserts ();
50938fd1498Szrj 
51038fd1498Szrj   bbs.release ();
51138fd1498Szrj   free (phivn);
51238fd1498Szrj 
51338fd1498Szrj   free_dominance_info (CDI_POST_DOMINATORS);
51438fd1498Szrj 
51538fd1498Szrj   return 0;
51638fd1498Szrj }
51738fd1498Szrj 
51838fd1498Szrj } // anon namespace
51938fd1498Szrj 
52038fd1498Szrj gimple_opt_pass *
make_pass_phiprop(gcc::context * ctxt)52138fd1498Szrj make_pass_phiprop (gcc::context *ctxt)
52238fd1498Szrj {
52338fd1498Szrj   return new pass_phiprop (ctxt);
52438fd1498Szrj }
525