tree-ssa-phiprop.c 12.3 KB
Newer Older
1
/* Backward propagation of indirect loads through PHIs.
2
   Copyright (C) 2007-2014 Free Software Foundation, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   Contributed by Richard Guenther <rguenther@suse.de>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "tm_p.h"
#include "basic-block.h"
28
#include "gimple-pretty-print.h"
29 30 31 32 33
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "tree-eh.h"
#include "gimple-expr.h"
#include "is-a.h"
34
#include "gimple.h"
35
#include "gimplify.h"
36
#include "gimple-iterator.h"
37 38 39
#include "gimple-ssa.h"
#include "tree-phinodes.h"
#include "ssa-iterators.h"
40
#include "stringpool.h"
41
#include "tree-ssanames.h"
42 43 44 45 46
#include "tree-pass.h"
#include "langhooks.h"
#include "flags.h"

/* This pass propagates indirect loads through the PHI node for its
47
   address to make the load source possibly non-addressable and to
48 49 50 51 52 53 54 55 56 57 58
   allow for PHI optimization to trigger.

   For example the pass changes

     # addr_1 = PHI <&a, &b>
     tmp_1 = *addr_1;

   to

     # tmp_1 = PHI <a, b>

59
   but also handles more complex scenarios like
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

     D.2077_2 = &this_1(D)->a1;
     ...

     # b_12 = PHI <&c(2), D.2077_2(3)>
     D.2114_13 = *b_12;
     ...

     # b_15 = PHI <b_12(4), &b(5)>
     D.2080_5 = &this_1(D)->a0;
     ...

     # b_18 = PHI <D.2080_5(6), &c(7)>
     ...

     # b_21 = PHI <b_15(8), b_18(9)>
     D.2076_8 = *b_21;

   where the addresses loaded are defined by PHIs itself.
   The above happens for

     std::max(std::min(a0, c), std::min(std::max(a1, c), b))

   where this pass transforms it to a form later PHI optimization
   recognizes and transforms it to the simple

     D.2109_10 = this_1(D)->a1;
     D.2110_11 = c;
     D.2114_31 = MAX_EXPR <D.2109_10, D.2110_11>;
     D.2115_14 = b;
     D.2125_17 = MIN_EXPR <D.2115_14, D.2114_31>;
     D.2119_16 = this_1(D)->a0;
     D.2124_32 = MIN_EXPR <D.2110_11, D.2119_16>;
     D.2076_33 = MAX_EXPR <D.2125_17, D.2124_32>;

   The pass does a dominator walk processing loads using a basic-block
   local analysis and stores the result for use by transformations on
   dominated basic-blocks.  */


/* Structure to keep track of the value of a dereferenced PHI result
101
   and the virtual operand used for that dereference.  */
102 103 104 105

struct phiprop_d
{
  tree value;
106
  tree vuse;
107 108 109 110 111 112 113 114
};

/* Verify if the value recorded for NAME in PHIVN is still valid at
   the start of basic block BB.  */

static bool
phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
{
115 116 117 118
  tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
  gimple use_stmt;
  imm_use_iterator ui2;
  bool ok = true;
119

120 121
  /* The def stmts of the virtual uses need to be dominated by bb.  */
  gcc_assert (vuse != NULL_TREE);
122

123 124 125 126 127 128
  FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
    {
      /* If BB does not dominate a VDEF, the value is invalid.  */
      if ((gimple_vdef (use_stmt) != NULL_TREE
	   || gimple_code (use_stmt) == GIMPLE_PHI)
	  && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
129
	{
130 131
	  ok = false;
	  BREAK_FROM_IMM_USE_STMT (ui2);
132 133 134
	}
    }

135
  return ok;
136 137 138 139 140 141
}

/* Insert a new phi node for the dereference of PHI at basic_block
   BB with the virtual operands from USE_STMT.  */

static tree
142
phiprop_insert_phi (basic_block bb, gimple phi, gimple use_stmt,
143 144
		    struct phiprop_d *phivn, size_t n)
{
145 146
  tree res;
  gimple new_phi;
147 148 149
  edge_iterator ei;
  edge e;

150
  gcc_assert (is_gimple_assign (use_stmt)
151
	      && gimple_assign_rhs_code (use_stmt) == MEM_REF);
152

153 154
  /* Build a new PHI node to replace the definition of
     the indirect reference lhs.  */
155
  res = gimple_assign_lhs (use_stmt);
156
  new_phi = create_phi_node (res, bb);
157

158 159 160 161 162 163
  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);
    }

164 165 166 167
  /* Add PHI arguments for each edge inserting loads of the
     addressable operands.  */
  FOR_EACH_EDGE (e, ei, bb->preds)
    {
168 169
      tree old_arg, new_var;
      gimple tmp;
170
      source_location locus;
171 172

      old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
173
      locus = gimple_phi_arg_location_from_edge (phi, e);
174 175 176 177
      while (TREE_CODE (old_arg) == SSA_NAME
	     && (SSA_NAME_VERSION (old_arg) >= n
	         || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
	{
178 179
	  gimple def_stmt = SSA_NAME_DEF_STMT (old_arg);
	  old_arg = gimple_assign_rhs1 (def_stmt);
180
	  locus = gimple_location (def_stmt);
181 182 183
	}

      if (TREE_CODE (old_arg) == SSA_NAME)
184 185 186 187 188 189 190 191 192 193 194 195 196
	{
	  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);
	      fprintf (dump_file, " reusing PHI result ");
	      print_generic_expr (dump_file,
				  phivn[SSA_NAME_VERSION (old_arg)].value, 0);
	      fprintf (dump_file, "\n");
	    }
	  /* Reuse a formerly created dereference.  */
	  new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
	}
197 198
      else
	{
199
	  tree rhs = gimple_assign_rhs1 (use_stmt);
200
	  gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
201
	  new_var = make_ssa_name (TREE_TYPE (rhs), NULL);
202 203 204 205 206 207 208 209
	  if (!is_gimple_min_invariant (old_arg))
	    old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
	  else
	    old_arg = unshare_expr (old_arg);
	  tmp = gimple_build_assign (new_var,
				     fold_build2 (MEM_REF, TREE_TYPE (rhs),
						  old_arg,
						  TREE_OPERAND (rhs, 1)));
210
	  gimple_set_location (tmp, locus);
211

212
	  gsi_insert_on_edge (e, tmp);
213
	  update_stmt (tmp);
214 215 216 217 218 219 220 221

	  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);
	      fprintf (dump_file, " inserting load ");
	      print_gimple_stmt (dump_file, tmp, 0, 0);
	    }
222 223
	}

224
      add_phi_arg (new_phi, new_var, e, locus);
225 226 227 228
    }

  update_stmt (new_phi);

229 230 231
  if (dump_file && (dump_flags & TDF_DETAILS))
    print_gimple_stmt (dump_file, new_phi, 0, 0);

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  return res;
}

/* Propagate between the phi node arguments of PHI in BB and phi result
   users.  For now this matches
        # p_2 = PHI <&x, &y>
      <Lx>:;
	p_3 = p_2;
	z_2 = *p_3;
   and converts it to
	# z_2 = PHI <x, y>
      <Lx>:;
   Returns true if a transformation was done and edge insertions
   need to be committed.  Global data PHIVN and N is used to track
   past transformation results.  We need to be especially careful here
   with aliasing issues as we are moving memory reads.  */

static bool
250 251
propagate_with_phi (basic_block bb, gimple phi, struct phiprop_d *phivn,
		    size_t n)
252 253
{
  tree ptr = PHI_RESULT (phi);
254 255 256
  gimple use_stmt;
  tree res = NULL_TREE;
  gimple_stmt_iterator gsi;
257 258 259 260
  imm_use_iterator ui;
  use_operand_p arg_p, use;
  ssa_op_iter i;
  bool phi_inserted;
261
  tree type = NULL_TREE;
262

263
  if (!POINTER_TYPE_P (TREE_TYPE (ptr))
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
      || !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
    return false;

  /* Check if we can "cheaply" dereference all phi arguments.  */
  FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_USE)
    {
      tree arg = USE_FROM_PTR (arg_p);
      /* Walk the ssa chain until we reach a ssa name we already
	 created a value for or we reach a definition of the form
	 ssa_name_n = &var;  */
      while (TREE_CODE (arg) == SSA_NAME
	     && !SSA_NAME_IS_DEFAULT_DEF (arg)
	     && (SSA_NAME_VERSION (arg) >= n
	         || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
	{
279
	  gimple def_stmt = SSA_NAME_DEF_STMT (arg);
280
	  if (!gimple_assign_single_p (def_stmt))
281
	    return false;
282
	  arg = gimple_assign_rhs1 (def_stmt);
283
	}
284
      if (TREE_CODE (arg) != ADDR_EXPR
285
	  && !(TREE_CODE (arg) == SSA_NAME
286
	       && SSA_NAME_VERSION (arg) < n
287
	       && phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
288 289 290
	       && (!type
		   || types_compatible_p
		       (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value)))
291 292
	       && phivn_valid_p (phivn, arg, bb)))
	return false;
293 294 295
      if (!type
	  && TREE_CODE (arg) == SSA_NAME)
	type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
296 297 298 299 300
    }

  /* Find a dereferencing use.  First follow (single use) ssa
     copy chains for ptr.  */
  while (single_imm_use (ptr, &use, &use_stmt)
301 302
	 && gimple_assign_ssa_name_copy_p (use_stmt))
    ptr = gimple_assign_lhs (use_stmt);
303 304 305 306 307 308

  /* Replace the first dereference of *ptr if there is one and if we
     can move the loads to the place of the ptr phi node.  */
  phi_inserted = false;
  FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
    {
309
      gimple def_stmt;
310 311 312
      tree vuse;

      /* Check whether this is a load of *ptr.  */
313
      if (!(is_gimple_assign (use_stmt)
H.J. Lu committed
314
	    && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
315
	    && gimple_assign_rhs_code (use_stmt) == MEM_REF
316
	    && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
317
	    && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
318 319 320
	    && (!type
		|| types_compatible_p
		     (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
321
	    /* We cannot replace a load that may throw or is volatile.  */
322
	    && !stmt_can_throw_internal (use_stmt)))
323 324
	continue;

325 326 327 328 329 330 331 332 333
      /* Check if we can move the loads.  The def stmt of the virtual use
	 needs to be in a different basic block dominating bb.  */
      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))))
	goto next;
334 335 336 337 338 339

      /* Found a proper dereference.  Insert a phi node if this
	 is the first load transformation.  */
      if (!phi_inserted)
	{
	  res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
340
	  type = TREE_TYPE (res);
341 342 343

	  /* Remember the value we created for *ptr.  */
	  phivn[SSA_NAME_VERSION (ptr)].value = res;
344
	  phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
345 346 347 348

	  /* Remove old stmt.  The phi is taken care of by DCE, if we
	     want to delete it here we also have to delete all intermediate
	     copies.  */
349
	  gsi = gsi_for_stmt (use_stmt);
350
	  gsi_remove (&gsi, true);
351 352 353 354 355 356 357

	  phi_inserted = true;
	}
      else
	{
	  /* Further replacements are easy, just make a copy out of the
	     load.  */
358
	  gimple_assign_set_rhs1 (use_stmt, res);
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	  update_stmt (use_stmt);
	}

next:;
      /* Continue searching for a proper dereference.  */
    }

  return phi_inserted;
}

/* Main entry for phiprop pass.  */

static unsigned int
tree_ssa_phiprop (void)
{
374
  vec<basic_block> bbs;
375
  struct phiprop_d *phivn;
H.J. Lu committed
376
  bool did_something = false;
377 378 379
  basic_block bb;
  gimple_stmt_iterator gsi;
  unsigned i;
380
  size_t n;
381 382 383

  calculate_dominance_info (CDI_DOMINATORS);

384 385
  n = num_ssa_names;
  phivn = XCNEWVEC (struct phiprop_d, n);
386

387 388
  /* Walk the dominator tree in preorder.  */
  bbs = get_all_dominated_blocks (CDI_DOMINATORS,
389
				  single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
390
  FOR_EACH_VEC_ELT (bbs, i, bb)
391
    for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
392
      did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n);
393 394

  if (did_something)
395
    gsi_commit_edge_inserts ();
396

397
  bbs.release ();
398 399 400 401 402 403 404 405
  free (phivn);

  return 0;
}

static bool
gate_phiprop (void)
{
406
  return flag_tree_phiprop;
407 408
}

409 410 411
namespace {

const pass_data pass_data_phiprop =
412
{
413 414 415 416 417 418 419 420 421 422 423
  GIMPLE_PASS, /* type */
  "phiprop", /* name */
  OPTGROUP_NONE, /* optinfo_flags */
  true, /* has_gate */
  true, /* has_execute */
  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_verify_ssa ), /* todo_flags_finish */
424
};
425 426 427 428

class pass_phiprop : public gimple_opt_pass
{
public:
429 430
  pass_phiprop (gcc::context *ctxt)
    : gimple_opt_pass (pass_data_phiprop, ctxt)
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
  {}

  /* opt_pass methods: */
  bool gate () { return gate_phiprop (); }
  unsigned int execute () { return tree_ssa_phiprop (); }

}; // class pass_phiprop

} // anon namespace

gimple_opt_pass *
make_pass_phiprop (gcc::context *ctxt)
{
  return new pass_phiprop (ctxt);
}