diff mbox

Pack global state of forwprop to one structure

Message ID 20150921211518.GC19502@virgil.suse.cz
State New
Headers show

Commit Message

Martin Jambor Sept. 21, 2015, 9:15 p.m. UTC
Hi,

the following patch almost removes the global state of pass_forwprop.
Only almost, because the pass calls fold_const with its own valueize
function which uses lattices, and changing the prototype of valueize
(by adding a void *data parameter) is something I am not going to
undertake without knowing it would be accepted, especially since there
might be people who would prefer to pass the data via some C++ism,
rather than a void pointer.  It is also probably more work than I have
time for this week.

The patch nevertheless puts global state in one structure and all but
this one function (and the execute method, into which the variable
should be eventually moved) access it through a pointer parameter.
Along the way I streamlined how cfg_changed is communicated from three
functions, now they set the flag in the state structure instead of
returning magic number 2 which the caller then tests for only to set
the flag in that case.

My motivation is a bug in HSA run-time and/or finalizer, which does
not allow me to run the following pattern of code:

  pointer = &local_decl; /* address of first private decl is 0 */
  pointer->field = tmp;  /* this oopses on my RC kernel */

Because I'm in the process of changing the HSA omp lowering/expansion
in a way that routinely produces such statements, I need to run some
sort of simple forward propagation even at -O0 (on functions that are
to be expanded only to HSAIL and not on host).  To do that, making
forward_propagate_addr_expr public is very useful, but it has to know
when it is called from outside the pass so that it does not try to
update the inner state.

The forward propagation is a hack and I actually I hope I will be able
to remove it before proposing merging to trunk.  But this patch seems
useful on its own, so I would like to commit it.

Bootstrapped and tested on x86_64-linux.  OK for trunk?

Thanks,

Martin


2015-09-21  Martin Jambor  <mjambor@suse.cz>

	* tree-ssa-forwprop.c (struct fwp_state): New type.
	(pass_state): New variable.
	(cfg_changed): Moved to fwp_state.
	(to_purge): Likewise.
	(lattice): Likewise.
	(fwprop_set_lattice_val): Use state received in a new parameter.
	(fwprop_invalidate_lattice): Likewise.
	(remove_prop_source_from_use): Likewise.
	(forward_propagate_into_comparison): Likewise. Set state->cfg_changed
	instead of returning two.
	(forward_propagate_into_gimple_cond): Likewise.
	(tidy_after_forward_propagate_addr): Use state received in a new
	parameter.
	(forward_propagate_addr_expr_1): Likewise.
	(forward_propagate_addr_expr): Likewise.
	(simplify_gimple_switch_label_vec): Likewise.
	(simplify_gimple_switch): Likewise.
	(simplify_builtin_call): Likewise.
	(simplify_permutation): Likewise.  Set state->cfg_changed instead of
	returning two.
	(fwprop_ssa_val): Use pass_state.
	(namespace): Likewise.  Removed checks for return value of two.
---
 gcc/tree-ssa-forwprop.c | 282 ++++++++++++++++++++++++------------------------
 1 file changed, 142 insertions(+), 140 deletions(-)

Comments

Richard Biener Sept. 22, 2015, 7:53 a.m. UTC | #1
On Mon, 21 Sep 2015, Martin Jambor wrote:

> Hi,
> 
> the following patch almost removes the global state of pass_forwprop.
> Only almost, because the pass calls fold_const with its own valueize
> function which uses lattices, and changing the prototype of valueize
> (by adding a void *data parameter) is something I am not going to
> undertake without knowing it would be accepted, especially since there
> might be people who would prefer to pass the data via some C++ism,
> rather than a void pointer.  It is also probably more work than I have
> time for this week.
> 
> The patch nevertheless puts global state in one structure and all but
> this one function (and the execute method, into which the variable
> should be eventually moved) access it through a pointer parameter.
> Along the way I streamlined how cfg_changed is communicated from three
> functions, now they set the flag in the state structure instead of
> returning magic number 2 which the caller then tests for only to set
> the flag in that case.
> 
> My motivation is a bug in HSA run-time and/or finalizer, which does
> not allow me to run the following pattern of code:
> 
>   pointer = &local_decl; /* address of first private decl is 0 */
>   pointer->field = tmp;  /* this oopses on my RC kernel */
> 
> Because I'm in the process of changing the HSA omp lowering/expansion
> in a way that routinely produces such statements, I need to run some
> sort of simple forward propagation even at -O0 (on functions that are
> to be expanded only to HSAIL and not on host).  To do that, making
> forward_propagate_addr_expr public is very useful, but it has to know
> when it is called from outside the pass so that it does not try to
> update the inner state.
> 
> The forward propagation is a hack and I actually I hope I will be able
> to remove it before proposing merging to trunk.  But this patch seems
> useful on its own, so I would like to commit it.
> 
> Bootstrapped and tested on x86_64-linux.  OK for trunk?

Hmm, I think the "canonical" way to do all this is to make all
functions methods of the pass instance and the globals member
variables, no?

Doing it with an extra object passed to each function is so non-C++.

[yeah, I can see that for your purpose this wouldn't fly ...]

So no, I think this isn't a step in the right direction.

Sorry,
Richard.

> Thanks,
> 
> Martin
> 
> 
> 2015-09-21  Martin Jambor  <mjambor@suse.cz>
> 
> 	* tree-ssa-forwprop.c (struct fwp_state): New type.
> 	(pass_state): New variable.
> 	(cfg_changed): Moved to fwp_state.
> 	(to_purge): Likewise.
> 	(lattice): Likewise.
> 	(fwprop_set_lattice_val): Use state received in a new parameter.
> 	(fwprop_invalidate_lattice): Likewise.
> 	(remove_prop_source_from_use): Likewise.
> 	(forward_propagate_into_comparison): Likewise. Set state->cfg_changed
> 	instead of returning two.
> 	(forward_propagate_into_gimple_cond): Likewise.
> 	(tidy_after_forward_propagate_addr): Use state received in a new
> 	parameter.
> 	(forward_propagate_addr_expr_1): Likewise.
> 	(forward_propagate_addr_expr): Likewise.
> 	(simplify_gimple_switch_label_vec): Likewise.
> 	(simplify_gimple_switch): Likewise.
> 	(simplify_builtin_call): Likewise.
> 	(simplify_permutation): Likewise.  Set state->cfg_changed instead of
> 	returning two.
> 	(fwprop_ssa_val): Use pass_state.
> 	(namespace): Likewise.  Removed checks for return value of two.
> ---
>  gcc/tree-ssa-forwprop.c | 282 ++++++++++++++++++++++++------------------------
>  1 file changed, 142 insertions(+), 140 deletions(-)
> 
> diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
> index ccfde5f..343c1de 100644
> --- a/gcc/tree-ssa-forwprop.c
> +++ b/gcc/tree-ssa-forwprop.c
> @@ -188,44 +188,55 @@ along with GCC; see the file COPYING3.  If not see
>  
>     This will (of course) be extended as other needs arise.  */
>  
> -static bool forward_propagate_addr_expr (tree, tree, bool);
> +/* Structure holding state of the forward propagation pass.  */
>  
> -/* Set to true if we delete dead edges during the optimization.  */
> -static bool cfg_changed;
> +struct fwp_state
> +{
> +  /* Set to true if we delete dead edges during the optimization.  */
> +  bool cfg_changed;
>  
> -static tree rhs_to_tree (tree type, gimple stmt);
> +  /* Bitmap of basic blocks containing dead outgoing EH edges.  */
> +  bitmap to_purge;
>  
> -static bitmap to_purge;
> +  /* Const-and-copy lattice.  */
> +  vec<tree> lattice;
> +};
>  
> -/* Const-and-copy lattice.  */
> -static vec<tree> lattice;
> +/* Global state of the  */
> +static struct fwp_state pass_state;
> +
> +static bool forward_propagate_addr_expr (fwp_state *, tree, tree, bool);
> +static tree rhs_to_tree (tree type, gimple stmt);
> +
> +/* Set the lattice entry for NAME to VAL.  STATE points to global state
> +   information of the pass.  */
>  
> -/* Set the lattice entry for NAME to VAL.  */
>  static void
> -fwprop_set_lattice_val (tree name, tree val)
> +fwprop_set_lattice_val (fwp_state *state, tree name, tree val)
>  {
>    if (TREE_CODE (name) == SSA_NAME)
>      {
> -      if (SSA_NAME_VERSION (name) >= lattice.length ())
> +      if (SSA_NAME_VERSION (name) >= state->lattice.length ())
>  	{
> -	  lattice.reserve (num_ssa_names - lattice.length ());
> -	  lattice.quick_grow_cleared (num_ssa_names);
> +	  state->lattice.reserve (num_ssa_names - state->lattice.length ());
> +	  state->lattice.quick_grow_cleared (num_ssa_names);
>  	}
> -      lattice[SSA_NAME_VERSION (name)] = val;
> +      state->lattice[SSA_NAME_VERSION (name)] = val;
>      }
>  }
>  
> -/* Invalidate the lattice entry for NAME, done when releasing SSA names.  */
> +/* Invalidate the lattice entry for NAME, done when releasing SSA names.  STATE
> +   points to global state information of the pass.  */
> +
>  static void
> -fwprop_invalidate_lattice (tree name)
> +fwprop_invalidate_lattice (fwp_state *state, tree name)
>  {
>    if (name
>        && TREE_CODE (name) == SSA_NAME
> -      && SSA_NAME_VERSION (name) < lattice.length ())
> -    lattice[SSA_NAME_VERSION (name)] = NULL_TREE;
> +      && SSA_NAME_VERSION (name) < state->lattice.length ())
> +    state->lattice[SSA_NAME_VERSION (name)] = NULL_TREE;
>  }
>  
> -
>  /* Get the statement we can propagate from into NAME skipping
>     trivial copies.  Returns the statement which defines the
>     propagation source or NULL_TREE if there is no such one.
> @@ -307,15 +318,15 @@ can_propagate_from (gimple def_stmt)
>    return true;
>  }
>  
> -/* Remove a chain of dead statements starting at the definition of
> -   NAME.  The chain is linked via the first operand of the defining statements.
> -   If NAME was replaced in its only use then this function can be used
> -   to clean up dead stmts.  The function handles already released SSA
> -   names gracefully.
> -   Returns true if cleanup-cfg has to run.  */
> +/* Remove a chain of dead statements starting at the definition of NAME.  STATE
> +   points to global state information of the pass.  The chain is linked via the
> +   first operand of the defining statements.  If NAME was replaced in its only
> +   use then this function can be used to clean up dead stmts.  The function
> +   handles already released SSA names gracefully.  Returns true if cleanup-cfg
> +   has to run.  */
>  
>  static bool
> -remove_prop_source_from_use (tree name)
> +remove_prop_source_from_use (fwp_state *state, tree name)
>  {
>    gimple_stmt_iterator gsi;
>    gimple stmt;
> @@ -338,8 +349,8 @@ remove_prop_source_from_use (tree name)
>      gsi = gsi_for_stmt (stmt);
>      unlink_stmt_vdef (stmt);
>      if (gsi_remove (&gsi, true))
> -      bitmap_set_bit (to_purge, bb->index);
> -    fwprop_invalidate_lattice (gimple_get_lhs (stmt));
> +      bitmap_set_bit (state->to_purge, bb->index);
> +    fwprop_invalidate_lattice (state, gimple_get_lhs (stmt));
>      release_defs (stmt);
>  
>      name = is_gimple_assign (stmt) ? gimple_assign_rhs1 (stmt) : NULL_TREE;
> @@ -479,17 +490,17 @@ forward_propagate_into_comparison_1 (gimple stmt,
>    return tmp;
>  }
>  
> -/* Propagate from the ssa name definition statements of the assignment
> -   from a comparison at *GSI into the conditional if that simplifies it.
> -   Returns 1 if the stmt was modified and 2 if the CFG needs cleanup,
> -   otherwise returns 0.  */
> +/* Propagate from the ssa name definition statements of the assignment from a
> +   comparison at *GSI into the conditional if that simplifies it.  STATE points
> +   to global state information of the pass.  Return true if the stmt was
> +   modified, set athe appropriate flag in STATE if the cfg has been
> +   modified.  */
>  
> -static int 
> -forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
> +static bool
> +forward_propagate_into_comparison (fwp_state *state, gimple_stmt_iterator *gsi)
>  {
>    gimple stmt = gsi_stmt (*gsi);
>    tree tmp;
> -  bool cfg_changed = false;
>    tree type = TREE_TYPE (gimple_assign_lhs (stmt));
>    tree rhs1 = gimple_assign_rhs1 (stmt);
>    tree rhs2 = gimple_assign_rhs2 (stmt);
> @@ -505,34 +516,34 @@ forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
>        update_stmt (gsi_stmt (*gsi));
>  
>        if (TREE_CODE (rhs1) == SSA_NAME)
> -	cfg_changed |= remove_prop_source_from_use (rhs1);
> +	state->cfg_changed |= remove_prop_source_from_use (state, rhs1);
>        if (TREE_CODE (rhs2) == SSA_NAME)
> -	cfg_changed |= remove_prop_source_from_use (rhs2);
> -      return cfg_changed ? 2 : 1;
> +	state->cfg_changed |= remove_prop_source_from_use (state, rhs2);
> +      return true;
>      }
>  
> -  return 0;
> +  return false;
>  }
>  
> -/* Propagate from the ssa name definition statements of COND_EXPR
> -   in GIMPLE_COND statement STMT into the conditional if that simplifies it.
> -   Returns zero if no statement was changed, one if there were
> -   changes and two if cfg_cleanup needs to run.
> +/* Propagate from the ssa name definition statements of COND_EXPR in
> +   GIMPLE_COND statement STMT into the conditional if that simplifies it.
> +   STATE points to global state information of the pass.  Return true if any
> +   changes have been performed.  Set the appropriate flag in STATE if cfg has
> +   been modified.
>  
>     This must be kept in sync with forward_propagate_into_cond.  */
>  
> -static int
> -forward_propagate_into_gimple_cond (gcond *stmt)
> +static bool
> +forward_propagate_into_gimple_cond (fwp_state *state, gcond *stmt)
>  {
>    tree tmp;
>    enum tree_code code = gimple_cond_code (stmt);
> -  bool cfg_changed = false;
>    tree rhs1 = gimple_cond_lhs (stmt);
>    tree rhs2 = gimple_cond_rhs (stmt);
>  
>    /* We can do tree combining on SSA_NAME and comparison expressions.  */
>    if (TREE_CODE_CLASS (gimple_cond_code (stmt)) != tcc_comparison)
> -    return 0;
> +    return false;
>  
>    tmp = forward_propagate_into_comparison_1 (stmt, code,
>  					     boolean_type_node,
> @@ -552,10 +563,11 @@ forward_propagate_into_gimple_cond (gcond *stmt)
>        update_stmt (stmt);
>  
>        if (TREE_CODE (rhs1) == SSA_NAME)
> -	cfg_changed |= remove_prop_source_from_use (rhs1);
> +	state->cfg_changed |= remove_prop_source_from_use (state, rhs1);
>        if (TREE_CODE (rhs2) == SSA_NAME)
> -	cfg_changed |= remove_prop_source_from_use (rhs2);
> -      return (cfg_changed || is_gimple_min_invariant (tmp)) ? 2 : 1;
> +	state->cfg_changed |= remove_prop_source_from_use (state, rhs2);
> +      state->cfg_changed |= is_gimple_min_invariant (tmp);
> +      return true;
>      }
>  
>    /* Canonicalize _Bool == 0 and _Bool != 1 to _Bool != 0 by swapping edges.  */
> @@ -572,16 +584,15 @@ forward_propagate_into_gimple_cond (gcond *stmt)
>        gimple_cond_set_rhs (stmt, build_zero_cst (TREE_TYPE (rhs1)));
>        EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
>        EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
> -      return 1;
> +      return true;
>      }
>  
> -  return 0;
> +  return false;
>  }
>  
> -
> -/* Propagate from the ssa name definition statements of COND_EXPR
> -   in the rhs of statement STMT into the conditional if that simplifies it.
> -   Returns true zero if the stmt was changed.  */
> +/* Attempt to propagate values into a COND_EXPR, which is the RHS of an
> +   assignment pointed to by GSI_P.  Returns true true if the stmt was
> +   changed.  */
>  
>  static bool
>  forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
> @@ -646,11 +657,11 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
>     relevant data structures to match.  */
>  
>  static void
> -tidy_after_forward_propagate_addr (gimple stmt)
> +tidy_after_forward_propagate_addr (fwp_state *state, gimple stmt)
>  {
>    /* We may have turned a trapping insn into a non-trapping insn.  */
>    if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
> -    bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
> +    bitmap_set_bit (state->to_purge, gimple_bb (stmt)->index);
>  
>    if (TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
>       recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
> @@ -667,7 +678,7 @@ tidy_after_forward_propagate_addr (gimple stmt)
>     be not totally successful, yet things may have been changed).  */
>  
>  static bool
> -forward_propagate_addr_expr_1 (tree name, tree def_rhs,
> +forward_propagate_addr_expr_1 (fwp_state *state, tree name, tree def_rhs,
>  			       gimple_stmt_iterator *use_stmt_gsi,
>  			       bool single_use_p)
>  {
> @@ -685,7 +696,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>    /* Do not perform copy-propagation but recurse through copy chains.  */
>    if (TREE_CODE (lhs) == SSA_NAME
>        && rhs_code == SSA_NAME)
> -    return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
> +    return forward_propagate_addr_expr (state, lhs, def_rhs, single_use_p);
>  
>    /* The use statement could be a conversion.  Recurse to the uses of the
>       lhs as copyprop does not copy through pointer to integer to pointer
> @@ -711,7 +722,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>  	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
>  	  && (TYPE_PRECISION (TREE_TYPE (lhs))
>  	      >= TYPE_PRECISION (TREE_TYPE (def_rhs))))
> -	return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
> +	return forward_propagate_addr_expr (state, lhs, def_rhs, single_use_p);
>  
>        return false;
>      }
> @@ -745,7 +756,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>        /* Recurse.  If we could propagate into all uses of lhs do not
>  	 bother to replace into the current use but just pretend we did.  */
>        if (TREE_CODE (new_def_rhs) == ADDR_EXPR
> -	  && forward_propagate_addr_expr (lhs, new_def_rhs, single_use_p))
> +	  && forward_propagate_addr_expr (state, lhs, new_def_rhs, single_use_p))
>  	return true;
>  
>        if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_def_rhs)))
> @@ -791,7 +802,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>  	  TREE_OPERAND (lhs, 0) = new_ptr;
>  	  TREE_OPERAND (lhs, 1)
>  	    = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (lhs, 1)), off);
> -	  tidy_after_forward_propagate_addr (use_stmt);
> +	  tidy_after_forward_propagate_addr (state, use_stmt);
>  	  /* Continue propagating into the RHS if this was not the only use.  */
>  	  if (single_use_p)
>  	    return true;
> @@ -837,7 +848,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>  	  TREE_THIS_VOLATILE (new_lhs) = TREE_THIS_VOLATILE (lhs);
>  	  TREE_SIDE_EFFECTS (new_lhs) = TREE_SIDE_EFFECTS (lhs);
>  	  *def_rhs_basep = saved;
> -	  tidy_after_forward_propagate_addr (use_stmt);
> +	  tidy_after_forward_propagate_addr (state, use_stmt);
>  	  /* Continue propagating into the RHS if this was not the
>  	     only use.  */
>  	  if (single_use_p)
> @@ -883,7 +894,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>  	  TREE_OPERAND (rhs, 1)
>  	    = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (rhs, 1)), off);
>  	  fold_stmt_inplace (use_stmt_gsi);
> -	  tidy_after_forward_propagate_addr (use_stmt);
> +	  tidy_after_forward_propagate_addr (state, use_stmt);
>  	  return res;
>  	}
>        /* If the RHS is a plain dereference and the value type is the same as
> @@ -924,7 +935,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>  	  TREE_SIDE_EFFECTS (new_rhs) = TREE_SIDE_EFFECTS (rhs);
>  	  *def_rhs_basep = saved;
>  	  fold_stmt_inplace (use_stmt_gsi);
> -	  tidy_after_forward_propagate_addr (use_stmt);
> +	  tidy_after_forward_propagate_addr (state, use_stmt);
>  	  return res;
>  	}
>      }
> @@ -960,7 +971,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>        gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
>        use_stmt = gsi_stmt (*use_stmt_gsi);
>        update_stmt (use_stmt);
> -      tidy_after_forward_propagate_addr (use_stmt);
> +      tidy_after_forward_propagate_addr (state, use_stmt);
>        return true;
>      }
>  
> @@ -980,7 +991,8 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
>     Returns true, if all uses have been propagated into.  */
>  
>  static bool
> -forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
> +forward_propagate_addr_expr (fwp_state *state, tree name, tree rhs,
> +			     bool parent_single_use_p)
>  {
>    imm_use_iterator iter;
>    gimple use_stmt;
> @@ -1002,7 +1014,7 @@ forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
>  	}
>  
>        gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
> -      result = forward_propagate_addr_expr_1 (name, rhs, &gsi,
> +      result = forward_propagate_addr_expr_1 (state, name, rhs, &gsi,
>  					      single_use_p);
>        /* If the use has moved to a different statement adjust
>  	 the update machinery for the old statement too.  */
> @@ -1022,7 +1034,7 @@ forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
>  	  && has_zero_uses (gimple_assign_lhs (use_stmt)))
>  	{
>  	  gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
> -	  fwprop_invalidate_lattice (gimple_get_lhs (use_stmt));
> +	  fwprop_invalidate_lattice (state, gimple_get_lhs (use_stmt));
>  	  release_defs (use_stmt);
>  	  gsi_remove (&gsi, true);
>  	}
> @@ -1036,7 +1048,8 @@ forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
>     have values outside the range of the new type.  */
>  
>  static void
> -simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
> +simplify_gimple_switch_label_vec (fwp_state *state, gswitch *stmt,
> +				  tree index_type)
>  {
>    unsigned int branch_num = gimple_switch_num_labels (stmt);
>    auto_vec<tree> labels (branch_num);
> @@ -1092,7 +1105,7 @@ simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
>  	  if (! bitmap_bit_p (target_blocks, e->dest->index))
>  	    {
>  	      remove_edge (e);
> -	      cfg_changed = true;
> +	      state->cfg_changed = true;
>  	      free_dominance_info (CDI_DOMINATORS);
>  	    }
>  	  else
> @@ -1106,7 +1119,7 @@ simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
>     the condition which we may be able to optimize better.  */
>  
>  static bool
> -simplify_gimple_switch (gswitch *stmt)
> +simplify_gimple_switch (fwp_state *state, gswitch *stmt)
>  {
>    /* The optimization that we really care about is removing unnecessary
>       casts.  That will let us do much better in propagating the inferred
> @@ -1142,7 +1155,7 @@ simplify_gimple_switch (gswitch *stmt)
>  		  && (!max || int_fits_type_p (max, ti)))
>  		{
>  		  gimple_switch_set_index (stmt, def);
> -		  simplify_gimple_switch_label_vec (stmt, ti);
> +		  simplify_gimple_switch_label_vec (state, stmt, ti);
>  		  update_stmt (stmt);
>  		  return true;
>  		}
> @@ -1250,7 +1263,8 @@ constant_pointer_difference (tree p1, tree p2)
>     call if the latter can be stored by pieces during expansion.  */
>  
>  static bool
> -simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
> +simplify_builtin_call (fwp_state *state, gimple_stmt_iterator *gsi_p,
> +		       tree callee2)
>  {
>    gimple stmt1, stmt2 = gsi_stmt (*gsi_p);
>    tree vuse = gimple_vuse (stmt2);
> @@ -1417,11 +1431,11 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
>  	      update_stmt (stmt1);
>  	      unlink_stmt_vdef (stmt2);
>  	      gsi_remove (gsi_p, true);
> -	      fwprop_invalidate_lattice (gimple_get_lhs (stmt2));
> +	      fwprop_invalidate_lattice (state, gimple_get_lhs (stmt2));
>  	      release_defs (stmt2);
>  	      if (lhs1 && DECL_FUNCTION_CODE (callee1) == BUILT_IN_MEMPCPY)
>  		{
> -		  fwprop_invalidate_lattice (lhs1);
> +		  fwprop_invalidate_lattice (state, lhs1);
>  		  release_ssa_name (lhs1);
>  		}
>  	      return true;
> @@ -1444,7 +1458,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
>  				   build_int_cst (TREE_TYPE (len2), src_len));
>  	      unlink_stmt_vdef (stmt1);
>  	      gsi_remove (&gsi, true);
> -	      fwprop_invalidate_lattice (gimple_get_lhs (stmt1));
> +	      fwprop_invalidate_lattice (state, gimple_get_lhs (stmt1));
>  	      release_defs (stmt1);
>  	      update_stmt (stmt2);
>  	      return false;
> @@ -1850,11 +1864,12 @@ is_combined_permutation_identity (tree mask1, tree mask2)
>    return maybe_identity1 ? 1 : maybe_identity2 ? 2 : 0;
>  }
>  
> -/* Combine a shuffle with its arguments.  Returns 1 if there were any
> -   changes made, 2 if cfg-cleanup needs to run.  Else it returns 0.  */
> - 
> -static int
> -simplify_permutation (gimple_stmt_iterator *gsi)
> +/* Combine a shuffle with its arguments.  STATE points to global state
> +   information of the pass.  Return true if there were any changes made, set
> +   the appropriate flag in STATE if cfg has been modified.  */
> +
> +static bool
> +simplify_permutation (fwp_state *state, gimple_stmt_iterator *gsi)
>  {
>    gimple stmt = gsi_stmt (*gsi);
>    gimple def_stmt;
> @@ -1869,7 +1884,7 @@ simplify_permutation (gimple_stmt_iterator *gsi)
>    op2 = gimple_assign_rhs3 (stmt);
>  
>    if (TREE_CODE (op2) != VECTOR_CST)
> -    return 0;
> +    return false;
>  
>    if (TREE_CODE (op0) == VECTOR_CST)
>      {
> @@ -1880,13 +1895,13 @@ simplify_permutation (gimple_stmt_iterator *gsi)
>      {
>        def_stmt = get_prop_source_stmt (op0, false, &single_use_op0);
>        if (!def_stmt || !can_propagate_from (def_stmt))
> -	return 0;
> +	return false;
>  
>        code = gimple_assign_rhs_code (def_stmt);
>        arg0 = gimple_assign_rhs1 (def_stmt);
>      }
>    else
> -    return 0;
> +    return false;
>  
>    /* Two consecutive shuffles.  */
>    if (code == VEC_PERM_EXPR)
> @@ -1895,31 +1910,31 @@ simplify_permutation (gimple_stmt_iterator *gsi)
>        int ident;
>  
>        if (op0 != op1)
> -	return 0;
> +	return false;
>        op3 = gimple_assign_rhs3 (def_stmt);
>        if (TREE_CODE (op3) != VECTOR_CST)
> -	return 0;
> +	return false;
>        ident = is_combined_permutation_identity (op3, op2);
>        if (!ident)
> -	return 0;
> +	return false;
>        orig = (ident == 1) ? gimple_assign_rhs1 (def_stmt)
>  			  : gimple_assign_rhs2 (def_stmt);
>        gimple_assign_set_rhs1 (stmt, unshare_expr (orig));
>        gimple_assign_set_rhs_code (stmt, TREE_CODE (orig));
>        gimple_set_num_ops (stmt, 2);
>        update_stmt (stmt);
> -      return remove_prop_source_from_use (op0) ? 2 : 1;
> +      state->cfg_changed |= remove_prop_source_from_use (state, op0);
> +      return true;
>      }
>  
>    /* Shuffle of a constructor.  */
>    else if (code == CONSTRUCTOR || code == VECTOR_CST)
>      {
>        tree opt;
> -      bool ret = false;
>        if (op0 != op1)
>  	{
>  	  if (TREE_CODE (op0) == SSA_NAME && !single_use_op0)
> -	    return 0;
> +	    return false;
>  
>  	  if (TREE_CODE (op1) == VECTOR_CST)
>  	    arg1 = op1;
> @@ -1929,37 +1944,38 @@ simplify_permutation (gimple_stmt_iterator *gsi)
>  
>  	      gimple def_stmt2 = get_prop_source_stmt (op1, true, NULL);
>  	      if (!def_stmt2 || !can_propagate_from (def_stmt2))
> -		return 0;
> +		return false;
>  
>  	      code2 = gimple_assign_rhs_code (def_stmt2);
>  	      if (code2 != CONSTRUCTOR && code2 != VECTOR_CST)
> -		return 0;
> +		return false;
>  	      arg1 = gimple_assign_rhs1 (def_stmt2);
>  	    }
>  	  else
> -	    return 0;
> +	    return false;
>  	}
>        else
>  	{
>  	  /* Already used twice in this statement.  */
>  	  if (TREE_CODE (op0) == SSA_NAME && num_imm_uses (op0) > 2)
> -	    return 0;
> +	    return false;
>  	  arg1 = arg0;
>  	}
>        opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE (op0), arg0, arg1, op2);
>        if (!opt
>  	  || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE (opt) != VECTOR_CST))
> -	return 0;
> +	return false;
>        gimple_assign_set_rhs_from_tree (gsi, opt);
>        update_stmt (gsi_stmt (*gsi));
>        if (TREE_CODE (op0) == SSA_NAME)
> -	ret = remove_prop_source_from_use (op0);
> +	state->cfg_changed |= remove_prop_source_from_use (state, op0);
>        if (op0 != op1 && TREE_CODE (op1) == SSA_NAME)
> -	ret |= remove_prop_source_from_use (op1);
> -      return ret ? 2 : 1;
> +	state->cfg_changed |= remove_prop_source_from_use (state, op1);
> +
> +      return true;
>      }
>  
> -  return 0;
> +  return false;
>  }
>  
>  /* Recognize a VEC_PERM_EXPR.  Returns true if there were any changes.  */
> @@ -2060,9 +2076,9 @@ fwprop_ssa_val (tree name)
>  {
>    /* First valueize NAME.  */
>    if (TREE_CODE (name) == SSA_NAME
> -      && SSA_NAME_VERSION (name) < lattice.length ())
> +      && SSA_NAME_VERSION (name) < pass_state.lattice.length ())
>      {
> -      tree val = lattice[SSA_NAME_VERSION (name)];
> +      tree val = pass_state.lattice[SSA_NAME_VERSION (name)];
>        if (val)
>  	name = val;
>      }
> @@ -2109,16 +2125,16 @@ pass_forwprop::execute (function *fun)
>  {
>    unsigned int todoflags = 0;
>  
> -  cfg_changed = false;
> +  pass_state.cfg_changed = false;
> +  pass_state.to_purge = BITMAP_ALLOC (NULL);
> +  pass_state.lattice.create (num_ssa_names);
> +  pass_state.lattice.quick_grow_cleared (num_ssa_names);
>  
>    /* Combine stmts with the stmts defining their operands.  Do that
>       in an order that guarantees visiting SSA defs before SSA uses.  */
> -  lattice.create (num_ssa_names);
> -  lattice.quick_grow_cleared (num_ssa_names);
>    int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
>    int postorder_num = inverted_post_order_compute (postorder);
>    auto_vec<gimple, 4> to_fixup;
> -  to_purge = BITMAP_ALLOC (NULL);
>    for (int i = 0; i < postorder_num; ++i)
>      {
>        gimple_stmt_iterator gsi;
> @@ -2162,9 +2178,9 @@ pass_forwprop::execute (function *fun)
>  		   || !DECL_P (base)
>  		   || decl_address_invariant_p (base))
>  		  && !stmt_references_abnormal_ssa_name (stmt)
> -		  && forward_propagate_addr_expr (lhs, rhs, true))
> +		  && forward_propagate_addr_expr (&pass_state, lhs, rhs, true))
>  		{
> -		  fwprop_invalidate_lattice (gimple_get_lhs (stmt));
> +		  fwprop_invalidate_lattice (&pass_state, gimple_get_lhs (stmt));
>  		  release_defs (stmt);
>  		  gsi_remove (&gsi, true);
>  		}
> @@ -2180,7 +2196,7 @@ pass_forwprop::execute (function *fun)
>  		  /* ???  Better adjust the interface to that function
>  		     instead of building new trees here.  */
>  		  && forward_propagate_addr_expr
> -		       (lhs,
> +		       (&pass_state, lhs,
>  			build1_loc (gimple_location (stmt),
>  				    ADDR_EXPR, TREE_TYPE (rhs),
>  				    fold_build2 (MEM_REF,
> @@ -2189,7 +2205,7 @@ pass_forwprop::execute (function *fun)
>  						 fold_convert (ptr_type_node,
>  							       off))), true))
>  		{
> -		  fwprop_invalidate_lattice (gimple_get_lhs (stmt));
> +		  fwprop_invalidate_lattice (&pass_state, gimple_get_lhs (stmt));
>  		  release_defs (stmt);
>  		  gsi_remove (&gsi, true);
>  		}
> @@ -2328,7 +2344,7 @@ pass_forwprop::execute (function *fun)
>  	      changed = true;
>  	      stmt = gsi_stmt (gsi);
>  	      if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
> -		bitmap_set_bit (to_purge, bb->index);
> +		bitmap_set_bit (pass_state.to_purge, bb->index);
>  	      if (!was_noreturn
>  		  && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
>  		to_fixup.safe_push (stmt);
> @@ -2337,7 +2353,7 @@ pass_forwprop::execute (function *fun)
>  	      if (gcond *cond = dyn_cast <gcond *> (stmt))
>  		if (gimple_cond_true_p (cond)
>  		    || gimple_cond_false_p (cond))
> -		  cfg_changed = true;
> +		  pass_state.cfg_changed = true;
>  	      update_stmt (stmt);
>  	    }
>  
> @@ -2359,25 +2375,15 @@ pass_forwprop::execute (function *fun)
>  		      }
>  		  }
>  		else if (TREE_CODE_CLASS (code) == tcc_comparison)
> -		  {
> -		    int did_something;
> -		    did_something = forward_propagate_into_comparison (&gsi);
> -		    if (did_something == 2)
> -		      cfg_changed = true;
> -		    changed = did_something != 0;
> -		  }
> +		  changed = forward_propagate_into_comparison (&pass_state,
> +							       &gsi);
>  		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;
> -		  }
> +		  changed = simplify_permutation (&pass_state, &gsi);
>  		else if (code == BIT_FIELD_REF)
>  		  changed = simplify_bitfield_ref (&gsi);
>                  else if (code == CONSTRUCTOR
> @@ -2387,25 +2393,21 @@ pass_forwprop::execute (function *fun)
>  	      }
>  
>  	    case GIMPLE_SWITCH:
> -	      changed = simplify_gimple_switch (as_a <gswitch *> (stmt));
> +	      changed = simplify_gimple_switch (&pass_state,
> +						as_a <gswitch *> (stmt));
>  	      break;
>  
>  	    case GIMPLE_COND:
> -	      {
> -		int did_something
> -		  = forward_propagate_into_gimple_cond (as_a <gcond *> (stmt));
> -		if (did_something == 2)
> -		  cfg_changed = true;
> -		changed = did_something != 0;
> +	      changed = forward_propagate_into_gimple_cond
> +		(&pass_state, as_a <gcond *> (stmt));
>  		break;
> -	      }
>  
>  	    case GIMPLE_CALL:
>  	      {
>  		tree callee = gimple_call_fndecl (stmt);
>  		if (callee != NULL_TREE
>  		    && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
> -		  changed = simplify_builtin_call (&gsi, callee);
> +		  changed = simplify_builtin_call (&pass_state, &gsi, callee);
>  		break;
>  	      }
>  
> @@ -2441,7 +2443,7 @@ pass_forwprop::execute (function *fun)
>  			val = fwprop_ssa_val (rhs);
>  		      else if (is_gimple_min_invariant (rhs))
>  			val = rhs;
> -		      fwprop_set_lattice_val (lhs, val);
> +		      fwprop_set_lattice_val (&pass_state, lhs, val);
>  		    }
>  		}
>  
> @@ -2450,7 +2452,7 @@ pass_forwprop::execute (function *fun)
>  	}
>      }
>    free (postorder);
> -  lattice.release ();
> +  pass_state.lattice.release ();
>  
>    /* Fixup stmts that became noreturn calls.  This may require splitting
>       blocks and thus isn't possible during the walk.  Do this
> @@ -2465,13 +2467,13 @@ pass_forwprop::execute (function *fun)
>  	  print_gimple_stmt (dump_file, stmt, 0, 0);
>  	  fprintf (dump_file, "\n");
>  	}
> -      cfg_changed |= fixup_noreturn_call (stmt);
> +      pass_state.cfg_changed |= fixup_noreturn_call (stmt);
>      }
>  
> -  cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
> -  BITMAP_FREE (to_purge);
> +  pass_state.cfg_changed |= gimple_purge_all_dead_eh_edges (pass_state.to_purge);
> +  BITMAP_FREE (pass_state.to_purge);
>  
> -  if (cfg_changed)
> +  if (pass_state.cfg_changed)
>      todoflags |= TODO_cleanup_cfg;
>  
>    return todoflags;
>
diff mbox

Patch

diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index ccfde5f..343c1de 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -188,44 +188,55 @@  along with GCC; see the file COPYING3.  If not see
 
    This will (of course) be extended as other needs arise.  */
 
-static bool forward_propagate_addr_expr (tree, tree, bool);
+/* Structure holding state of the forward propagation pass.  */
 
-/* Set to true if we delete dead edges during the optimization.  */
-static bool cfg_changed;
+struct fwp_state
+{
+  /* Set to true if we delete dead edges during the optimization.  */
+  bool cfg_changed;
 
-static tree rhs_to_tree (tree type, gimple stmt);
+  /* Bitmap of basic blocks containing dead outgoing EH edges.  */
+  bitmap to_purge;
 
-static bitmap to_purge;
+  /* Const-and-copy lattice.  */
+  vec<tree> lattice;
+};
 
-/* Const-and-copy lattice.  */
-static vec<tree> lattice;
+/* Global state of the  */
+static struct fwp_state pass_state;
+
+static bool forward_propagate_addr_expr (fwp_state *, tree, tree, bool);
+static tree rhs_to_tree (tree type, gimple stmt);
+
+/* Set the lattice entry for NAME to VAL.  STATE points to global state
+   information of the pass.  */
 
-/* Set the lattice entry for NAME to VAL.  */
 static void
-fwprop_set_lattice_val (tree name, tree val)
+fwprop_set_lattice_val (fwp_state *state, tree name, tree val)
 {
   if (TREE_CODE (name) == SSA_NAME)
     {
-      if (SSA_NAME_VERSION (name) >= lattice.length ())
+      if (SSA_NAME_VERSION (name) >= state->lattice.length ())
 	{
-	  lattice.reserve (num_ssa_names - lattice.length ());
-	  lattice.quick_grow_cleared (num_ssa_names);
+	  state->lattice.reserve (num_ssa_names - state->lattice.length ());
+	  state->lattice.quick_grow_cleared (num_ssa_names);
 	}
-      lattice[SSA_NAME_VERSION (name)] = val;
+      state->lattice[SSA_NAME_VERSION (name)] = val;
     }
 }
 
-/* Invalidate the lattice entry for NAME, done when releasing SSA names.  */
+/* Invalidate the lattice entry for NAME, done when releasing SSA names.  STATE
+   points to global state information of the pass.  */
+
 static void
-fwprop_invalidate_lattice (tree name)
+fwprop_invalidate_lattice (fwp_state *state, tree name)
 {
   if (name
       && TREE_CODE (name) == SSA_NAME
-      && SSA_NAME_VERSION (name) < lattice.length ())
-    lattice[SSA_NAME_VERSION (name)] = NULL_TREE;
+      && SSA_NAME_VERSION (name) < state->lattice.length ())
+    state->lattice[SSA_NAME_VERSION (name)] = NULL_TREE;
 }
 
-
 /* Get the statement we can propagate from into NAME skipping
    trivial copies.  Returns the statement which defines the
    propagation source or NULL_TREE if there is no such one.
@@ -307,15 +318,15 @@  can_propagate_from (gimple def_stmt)
   return true;
 }
 
-/* Remove a chain of dead statements starting at the definition of
-   NAME.  The chain is linked via the first operand of the defining statements.
-   If NAME was replaced in its only use then this function can be used
-   to clean up dead stmts.  The function handles already released SSA
-   names gracefully.
-   Returns true if cleanup-cfg has to run.  */
+/* Remove a chain of dead statements starting at the definition of NAME.  STATE
+   points to global state information of the pass.  The chain is linked via the
+   first operand of the defining statements.  If NAME was replaced in its only
+   use then this function can be used to clean up dead stmts.  The function
+   handles already released SSA names gracefully.  Returns true if cleanup-cfg
+   has to run.  */
 
 static bool
-remove_prop_source_from_use (tree name)
+remove_prop_source_from_use (fwp_state *state, tree name)
 {
   gimple_stmt_iterator gsi;
   gimple stmt;
@@ -338,8 +349,8 @@  remove_prop_source_from_use (tree name)
     gsi = gsi_for_stmt (stmt);
     unlink_stmt_vdef (stmt);
     if (gsi_remove (&gsi, true))
-      bitmap_set_bit (to_purge, bb->index);
-    fwprop_invalidate_lattice (gimple_get_lhs (stmt));
+      bitmap_set_bit (state->to_purge, bb->index);
+    fwprop_invalidate_lattice (state, gimple_get_lhs (stmt));
     release_defs (stmt);
 
     name = is_gimple_assign (stmt) ? gimple_assign_rhs1 (stmt) : NULL_TREE;
@@ -479,17 +490,17 @@  forward_propagate_into_comparison_1 (gimple stmt,
   return tmp;
 }
 
-/* Propagate from the ssa name definition statements of the assignment
-   from a comparison at *GSI into the conditional if that simplifies it.
-   Returns 1 if the stmt was modified and 2 if the CFG needs cleanup,
-   otherwise returns 0.  */
+/* Propagate from the ssa name definition statements of the assignment from a
+   comparison at *GSI into the conditional if that simplifies it.  STATE points
+   to global state information of the pass.  Return true if the stmt was
+   modified, set athe appropriate flag in STATE if the cfg has been
+   modified.  */
 
-static int 
-forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
+static bool
+forward_propagate_into_comparison (fwp_state *state, gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
   tree tmp;
-  bool cfg_changed = false;
   tree type = TREE_TYPE (gimple_assign_lhs (stmt));
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -505,34 +516,34 @@  forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
       update_stmt (gsi_stmt (*gsi));
 
       if (TREE_CODE (rhs1) == SSA_NAME)
-	cfg_changed |= remove_prop_source_from_use (rhs1);
+	state->cfg_changed |= remove_prop_source_from_use (state, rhs1);
       if (TREE_CODE (rhs2) == SSA_NAME)
-	cfg_changed |= remove_prop_source_from_use (rhs2);
-      return cfg_changed ? 2 : 1;
+	state->cfg_changed |= remove_prop_source_from_use (state, rhs2);
+      return true;
     }
 
-  return 0;
+  return false;
 }
 
-/* Propagate from the ssa name definition statements of COND_EXPR
-   in GIMPLE_COND statement STMT into the conditional if that simplifies it.
-   Returns zero if no statement was changed, one if there were
-   changes and two if cfg_cleanup needs to run.
+/* Propagate from the ssa name definition statements of COND_EXPR in
+   GIMPLE_COND statement STMT into the conditional if that simplifies it.
+   STATE points to global state information of the pass.  Return true if any
+   changes have been performed.  Set the appropriate flag in STATE if cfg has
+   been modified.
 
    This must be kept in sync with forward_propagate_into_cond.  */
 
-static int
-forward_propagate_into_gimple_cond (gcond *stmt)
+static bool
+forward_propagate_into_gimple_cond (fwp_state *state, gcond *stmt)
 {
   tree tmp;
   enum tree_code code = gimple_cond_code (stmt);
-  bool cfg_changed = false;
   tree rhs1 = gimple_cond_lhs (stmt);
   tree rhs2 = gimple_cond_rhs (stmt);
 
   /* We can do tree combining on SSA_NAME and comparison expressions.  */
   if (TREE_CODE_CLASS (gimple_cond_code (stmt)) != tcc_comparison)
-    return 0;
+    return false;
 
   tmp = forward_propagate_into_comparison_1 (stmt, code,
 					     boolean_type_node,
@@ -552,10 +563,11 @@  forward_propagate_into_gimple_cond (gcond *stmt)
       update_stmt (stmt);
 
       if (TREE_CODE (rhs1) == SSA_NAME)
-	cfg_changed |= remove_prop_source_from_use (rhs1);
+	state->cfg_changed |= remove_prop_source_from_use (state, rhs1);
       if (TREE_CODE (rhs2) == SSA_NAME)
-	cfg_changed |= remove_prop_source_from_use (rhs2);
-      return (cfg_changed || is_gimple_min_invariant (tmp)) ? 2 : 1;
+	state->cfg_changed |= remove_prop_source_from_use (state, rhs2);
+      state->cfg_changed |= is_gimple_min_invariant (tmp);
+      return true;
     }
 
   /* Canonicalize _Bool == 0 and _Bool != 1 to _Bool != 0 by swapping edges.  */
@@ -572,16 +584,15 @@  forward_propagate_into_gimple_cond (gcond *stmt)
       gimple_cond_set_rhs (stmt, build_zero_cst (TREE_TYPE (rhs1)));
       EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
       EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
-      return 1;
+      return true;
     }
 
-  return 0;
+  return false;
 }
 
-
-/* Propagate from the ssa name definition statements of COND_EXPR
-   in the rhs of statement STMT into the conditional if that simplifies it.
-   Returns true zero if the stmt was changed.  */
+/* Attempt to propagate values into a COND_EXPR, which is the RHS of an
+   assignment pointed to by GSI_P.  Returns true true if the stmt was
+   changed.  */
 
 static bool
 forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
@@ -646,11 +657,11 @@  forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
    relevant data structures to match.  */
 
 static void
-tidy_after_forward_propagate_addr (gimple stmt)
+tidy_after_forward_propagate_addr (fwp_state *state, gimple stmt)
 {
   /* We may have turned a trapping insn into a non-trapping insn.  */
   if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
-    bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
+    bitmap_set_bit (state->to_purge, gimple_bb (stmt)->index);
 
   if (TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
      recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
@@ -667,7 +678,7 @@  tidy_after_forward_propagate_addr (gimple stmt)
    be not totally successful, yet things may have been changed).  */
 
 static bool
-forward_propagate_addr_expr_1 (tree name, tree def_rhs,
+forward_propagate_addr_expr_1 (fwp_state *state, tree name, tree def_rhs,
 			       gimple_stmt_iterator *use_stmt_gsi,
 			       bool single_use_p)
 {
@@ -685,7 +696,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
   /* Do not perform copy-propagation but recurse through copy chains.  */
   if (TREE_CODE (lhs) == SSA_NAME
       && rhs_code == SSA_NAME)
-    return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
+    return forward_propagate_addr_expr (state, lhs, def_rhs, single_use_p);
 
   /* The use statement could be a conversion.  Recurse to the uses of the
      lhs as copyprop does not copy through pointer to integer to pointer
@@ -711,7 +722,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (TYPE_PRECISION (TREE_TYPE (lhs))
 	      >= TYPE_PRECISION (TREE_TYPE (def_rhs))))
-	return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
+	return forward_propagate_addr_expr (state, lhs, def_rhs, single_use_p);
 
       return false;
     }
@@ -745,7 +756,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       /* Recurse.  If we could propagate into all uses of lhs do not
 	 bother to replace into the current use but just pretend we did.  */
       if (TREE_CODE (new_def_rhs) == ADDR_EXPR
-	  && forward_propagate_addr_expr (lhs, new_def_rhs, single_use_p))
+	  && forward_propagate_addr_expr (state, lhs, new_def_rhs, single_use_p))
 	return true;
 
       if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_def_rhs)))
@@ -791,7 +802,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 	  TREE_OPERAND (lhs, 0) = new_ptr;
 	  TREE_OPERAND (lhs, 1)
 	    = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (lhs, 1)), off);
-	  tidy_after_forward_propagate_addr (use_stmt);
+	  tidy_after_forward_propagate_addr (state, use_stmt);
 	  /* Continue propagating into the RHS if this was not the only use.  */
 	  if (single_use_p)
 	    return true;
@@ -837,7 +848,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 	  TREE_THIS_VOLATILE (new_lhs) = TREE_THIS_VOLATILE (lhs);
 	  TREE_SIDE_EFFECTS (new_lhs) = TREE_SIDE_EFFECTS (lhs);
 	  *def_rhs_basep = saved;
-	  tidy_after_forward_propagate_addr (use_stmt);
+	  tidy_after_forward_propagate_addr (state, use_stmt);
 	  /* Continue propagating into the RHS if this was not the
 	     only use.  */
 	  if (single_use_p)
@@ -883,7 +894,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 	  TREE_OPERAND (rhs, 1)
 	    = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (rhs, 1)), off);
 	  fold_stmt_inplace (use_stmt_gsi);
-	  tidy_after_forward_propagate_addr (use_stmt);
+	  tidy_after_forward_propagate_addr (state, use_stmt);
 	  return res;
 	}
       /* If the RHS is a plain dereference and the value type is the same as
@@ -924,7 +935,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 	  TREE_SIDE_EFFECTS (new_rhs) = TREE_SIDE_EFFECTS (rhs);
 	  *def_rhs_basep = saved;
 	  fold_stmt_inplace (use_stmt_gsi);
-	  tidy_after_forward_propagate_addr (use_stmt);
+	  tidy_after_forward_propagate_addr (state, use_stmt);
 	  return res;
 	}
     }
@@ -960,7 +971,7 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
       use_stmt = gsi_stmt (*use_stmt_gsi);
       update_stmt (use_stmt);
-      tidy_after_forward_propagate_addr (use_stmt);
+      tidy_after_forward_propagate_addr (state, use_stmt);
       return true;
     }
 
@@ -980,7 +991,8 @@  forward_propagate_addr_expr_1 (tree name, tree def_rhs,
    Returns true, if all uses have been propagated into.  */
 
 static bool
-forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
+forward_propagate_addr_expr (fwp_state *state, tree name, tree rhs,
+			     bool parent_single_use_p)
 {
   imm_use_iterator iter;
   gimple use_stmt;
@@ -1002,7 +1014,7 @@  forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
 	}
 
       gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
-      result = forward_propagate_addr_expr_1 (name, rhs, &gsi,
+      result = forward_propagate_addr_expr_1 (state, name, rhs, &gsi,
 					      single_use_p);
       /* If the use has moved to a different statement adjust
 	 the update machinery for the old statement too.  */
@@ -1022,7 +1034,7 @@  forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
 	  && has_zero_uses (gimple_assign_lhs (use_stmt)))
 	{
 	  gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
-	  fwprop_invalidate_lattice (gimple_get_lhs (use_stmt));
+	  fwprop_invalidate_lattice (state, gimple_get_lhs (use_stmt));
 	  release_defs (use_stmt);
 	  gsi_remove (&gsi, true);
 	}
@@ -1036,7 +1048,8 @@  forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
    have values outside the range of the new type.  */
 
 static void
-simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
+simplify_gimple_switch_label_vec (fwp_state *state, gswitch *stmt,
+				  tree index_type)
 {
   unsigned int branch_num = gimple_switch_num_labels (stmt);
   auto_vec<tree> labels (branch_num);
@@ -1092,7 +1105,7 @@  simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
 	  if (! bitmap_bit_p (target_blocks, e->dest->index))
 	    {
 	      remove_edge (e);
-	      cfg_changed = true;
+	      state->cfg_changed = true;
 	      free_dominance_info (CDI_DOMINATORS);
 	    }
 	  else
@@ -1106,7 +1119,7 @@  simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
    the condition which we may be able to optimize better.  */
 
 static bool
-simplify_gimple_switch (gswitch *stmt)
+simplify_gimple_switch (fwp_state *state, gswitch *stmt)
 {
   /* The optimization that we really care about is removing unnecessary
      casts.  That will let us do much better in propagating the inferred
@@ -1142,7 +1155,7 @@  simplify_gimple_switch (gswitch *stmt)
 		  && (!max || int_fits_type_p (max, ti)))
 		{
 		  gimple_switch_set_index (stmt, def);
-		  simplify_gimple_switch_label_vec (stmt, ti);
+		  simplify_gimple_switch_label_vec (state, stmt, ti);
 		  update_stmt (stmt);
 		  return true;
 		}
@@ -1250,7 +1263,8 @@  constant_pointer_difference (tree p1, tree p2)
    call if the latter can be stored by pieces during expansion.  */
 
 static bool
-simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
+simplify_builtin_call (fwp_state *state, gimple_stmt_iterator *gsi_p,
+		       tree callee2)
 {
   gimple stmt1, stmt2 = gsi_stmt (*gsi_p);
   tree vuse = gimple_vuse (stmt2);
@@ -1417,11 +1431,11 @@  simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
 	      update_stmt (stmt1);
 	      unlink_stmt_vdef (stmt2);
 	      gsi_remove (gsi_p, true);
-	      fwprop_invalidate_lattice (gimple_get_lhs (stmt2));
+	      fwprop_invalidate_lattice (state, gimple_get_lhs (stmt2));
 	      release_defs (stmt2);
 	      if (lhs1 && DECL_FUNCTION_CODE (callee1) == BUILT_IN_MEMPCPY)
 		{
-		  fwprop_invalidate_lattice (lhs1);
+		  fwprop_invalidate_lattice (state, lhs1);
 		  release_ssa_name (lhs1);
 		}
 	      return true;
@@ -1444,7 +1458,7 @@  simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
 				   build_int_cst (TREE_TYPE (len2), src_len));
 	      unlink_stmt_vdef (stmt1);
 	      gsi_remove (&gsi, true);
-	      fwprop_invalidate_lattice (gimple_get_lhs (stmt1));
+	      fwprop_invalidate_lattice (state, gimple_get_lhs (stmt1));
 	      release_defs (stmt1);
 	      update_stmt (stmt2);
 	      return false;
@@ -1850,11 +1864,12 @@  is_combined_permutation_identity (tree mask1, tree mask2)
   return maybe_identity1 ? 1 : maybe_identity2 ? 2 : 0;
 }
 
-/* Combine a shuffle with its arguments.  Returns 1 if there were any
-   changes made, 2 if cfg-cleanup needs to run.  Else it returns 0.  */
- 
-static int
-simplify_permutation (gimple_stmt_iterator *gsi)
+/* Combine a shuffle with its arguments.  STATE points to global state
+   information of the pass.  Return true if there were any changes made, set
+   the appropriate flag in STATE if cfg has been modified.  */
+
+static bool
+simplify_permutation (fwp_state *state, gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
   gimple def_stmt;
@@ -1869,7 +1884,7 @@  simplify_permutation (gimple_stmt_iterator *gsi)
   op2 = gimple_assign_rhs3 (stmt);
 
   if (TREE_CODE (op2) != VECTOR_CST)
-    return 0;
+    return false;
 
   if (TREE_CODE (op0) == VECTOR_CST)
     {
@@ -1880,13 +1895,13 @@  simplify_permutation (gimple_stmt_iterator *gsi)
     {
       def_stmt = get_prop_source_stmt (op0, false, &single_use_op0);
       if (!def_stmt || !can_propagate_from (def_stmt))
-	return 0;
+	return false;
 
       code = gimple_assign_rhs_code (def_stmt);
       arg0 = gimple_assign_rhs1 (def_stmt);
     }
   else
-    return 0;
+    return false;
 
   /* Two consecutive shuffles.  */
   if (code == VEC_PERM_EXPR)
@@ -1895,31 +1910,31 @@  simplify_permutation (gimple_stmt_iterator *gsi)
       int ident;
 
       if (op0 != op1)
-	return 0;
+	return false;
       op3 = gimple_assign_rhs3 (def_stmt);
       if (TREE_CODE (op3) != VECTOR_CST)
-	return 0;
+	return false;
       ident = is_combined_permutation_identity (op3, op2);
       if (!ident)
-	return 0;
+	return false;
       orig = (ident == 1) ? gimple_assign_rhs1 (def_stmt)
 			  : gimple_assign_rhs2 (def_stmt);
       gimple_assign_set_rhs1 (stmt, unshare_expr (orig));
       gimple_assign_set_rhs_code (stmt, TREE_CODE (orig));
       gimple_set_num_ops (stmt, 2);
       update_stmt (stmt);
-      return remove_prop_source_from_use (op0) ? 2 : 1;
+      state->cfg_changed |= remove_prop_source_from_use (state, op0);
+      return true;
     }
 
   /* Shuffle of a constructor.  */
   else if (code == CONSTRUCTOR || code == VECTOR_CST)
     {
       tree opt;
-      bool ret = false;
       if (op0 != op1)
 	{
 	  if (TREE_CODE (op0) == SSA_NAME && !single_use_op0)
-	    return 0;
+	    return false;
 
 	  if (TREE_CODE (op1) == VECTOR_CST)
 	    arg1 = op1;
@@ -1929,37 +1944,38 @@  simplify_permutation (gimple_stmt_iterator *gsi)
 
 	      gimple def_stmt2 = get_prop_source_stmt (op1, true, NULL);
 	      if (!def_stmt2 || !can_propagate_from (def_stmt2))
-		return 0;
+		return false;
 
 	      code2 = gimple_assign_rhs_code (def_stmt2);
 	      if (code2 != CONSTRUCTOR && code2 != VECTOR_CST)
-		return 0;
+		return false;
 	      arg1 = gimple_assign_rhs1 (def_stmt2);
 	    }
 	  else
-	    return 0;
+	    return false;
 	}
       else
 	{
 	  /* Already used twice in this statement.  */
 	  if (TREE_CODE (op0) == SSA_NAME && num_imm_uses (op0) > 2)
-	    return 0;
+	    return false;
 	  arg1 = arg0;
 	}
       opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE (op0), arg0, arg1, op2);
       if (!opt
 	  || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE (opt) != VECTOR_CST))
-	return 0;
+	return false;
       gimple_assign_set_rhs_from_tree (gsi, opt);
       update_stmt (gsi_stmt (*gsi));
       if (TREE_CODE (op0) == SSA_NAME)
-	ret = remove_prop_source_from_use (op0);
+	state->cfg_changed |= remove_prop_source_from_use (state, op0);
       if (op0 != op1 && TREE_CODE (op1) == SSA_NAME)
-	ret |= remove_prop_source_from_use (op1);
-      return ret ? 2 : 1;
+	state->cfg_changed |= remove_prop_source_from_use (state, op1);
+
+      return true;
     }
 
-  return 0;
+  return false;
 }
 
 /* Recognize a VEC_PERM_EXPR.  Returns true if there were any changes.  */
@@ -2060,9 +2076,9 @@  fwprop_ssa_val (tree name)
 {
   /* First valueize NAME.  */
   if (TREE_CODE (name) == SSA_NAME
-      && SSA_NAME_VERSION (name) < lattice.length ())
+      && SSA_NAME_VERSION (name) < pass_state.lattice.length ())
     {
-      tree val = lattice[SSA_NAME_VERSION (name)];
+      tree val = pass_state.lattice[SSA_NAME_VERSION (name)];
       if (val)
 	name = val;
     }
@@ -2109,16 +2125,16 @@  pass_forwprop::execute (function *fun)
 {
   unsigned int todoflags = 0;
 
-  cfg_changed = false;
+  pass_state.cfg_changed = false;
+  pass_state.to_purge = BITMAP_ALLOC (NULL);
+  pass_state.lattice.create (num_ssa_names);
+  pass_state.lattice.quick_grow_cleared (num_ssa_names);
 
   /* Combine stmts with the stmts defining their operands.  Do that
      in an order that guarantees visiting SSA defs before SSA uses.  */
-  lattice.create (num_ssa_names);
-  lattice.quick_grow_cleared (num_ssa_names);
   int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
   int postorder_num = inverted_post_order_compute (postorder);
   auto_vec<gimple, 4> to_fixup;
-  to_purge = BITMAP_ALLOC (NULL);
   for (int i = 0; i < postorder_num; ++i)
     {
       gimple_stmt_iterator gsi;
@@ -2162,9 +2178,9 @@  pass_forwprop::execute (function *fun)
 		   || !DECL_P (base)
 		   || decl_address_invariant_p (base))
 		  && !stmt_references_abnormal_ssa_name (stmt)
-		  && forward_propagate_addr_expr (lhs, rhs, true))
+		  && forward_propagate_addr_expr (&pass_state, lhs, rhs, true))
 		{
-		  fwprop_invalidate_lattice (gimple_get_lhs (stmt));
+		  fwprop_invalidate_lattice (&pass_state, gimple_get_lhs (stmt));
 		  release_defs (stmt);
 		  gsi_remove (&gsi, true);
 		}
@@ -2180,7 +2196,7 @@  pass_forwprop::execute (function *fun)
 		  /* ???  Better adjust the interface to that function
 		     instead of building new trees here.  */
 		  && forward_propagate_addr_expr
-		       (lhs,
+		       (&pass_state, lhs,
 			build1_loc (gimple_location (stmt),
 				    ADDR_EXPR, TREE_TYPE (rhs),
 				    fold_build2 (MEM_REF,
@@ -2189,7 +2205,7 @@  pass_forwprop::execute (function *fun)
 						 fold_convert (ptr_type_node,
 							       off))), true))
 		{
-		  fwprop_invalidate_lattice (gimple_get_lhs (stmt));
+		  fwprop_invalidate_lattice (&pass_state, gimple_get_lhs (stmt));
 		  release_defs (stmt);
 		  gsi_remove (&gsi, true);
 		}
@@ -2328,7 +2344,7 @@  pass_forwprop::execute (function *fun)
 	      changed = true;
 	      stmt = gsi_stmt (gsi);
 	      if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
-		bitmap_set_bit (to_purge, bb->index);
+		bitmap_set_bit (pass_state.to_purge, bb->index);
 	      if (!was_noreturn
 		  && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
 		to_fixup.safe_push (stmt);
@@ -2337,7 +2353,7 @@  pass_forwprop::execute (function *fun)
 	      if (gcond *cond = dyn_cast <gcond *> (stmt))
 		if (gimple_cond_true_p (cond)
 		    || gimple_cond_false_p (cond))
-		  cfg_changed = true;
+		  pass_state.cfg_changed = true;
 	      update_stmt (stmt);
 	    }
 
@@ -2359,25 +2375,15 @@  pass_forwprop::execute (function *fun)
 		      }
 		  }
 		else if (TREE_CODE_CLASS (code) == tcc_comparison)
-		  {
-		    int did_something;
-		    did_something = forward_propagate_into_comparison (&gsi);
-		    if (did_something == 2)
-		      cfg_changed = true;
-		    changed = did_something != 0;
-		  }
+		  changed = forward_propagate_into_comparison (&pass_state,
+							       &gsi);
 		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;
-		  }
+		  changed = simplify_permutation (&pass_state, &gsi);
 		else if (code == BIT_FIELD_REF)
 		  changed = simplify_bitfield_ref (&gsi);
                 else if (code == CONSTRUCTOR
@@ -2387,25 +2393,21 @@  pass_forwprop::execute (function *fun)
 	      }
 
 	    case GIMPLE_SWITCH:
-	      changed = simplify_gimple_switch (as_a <gswitch *> (stmt));
+	      changed = simplify_gimple_switch (&pass_state,
+						as_a <gswitch *> (stmt));
 	      break;
 
 	    case GIMPLE_COND:
-	      {
-		int did_something
-		  = forward_propagate_into_gimple_cond (as_a <gcond *> (stmt));
-		if (did_something == 2)
-		  cfg_changed = true;
-		changed = did_something != 0;
+	      changed = forward_propagate_into_gimple_cond
+		(&pass_state, as_a <gcond *> (stmt));
 		break;
-	      }
 
 	    case GIMPLE_CALL:
 	      {
 		tree callee = gimple_call_fndecl (stmt);
 		if (callee != NULL_TREE
 		    && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
-		  changed = simplify_builtin_call (&gsi, callee);
+		  changed = simplify_builtin_call (&pass_state, &gsi, callee);
 		break;
 	      }
 
@@ -2441,7 +2443,7 @@  pass_forwprop::execute (function *fun)
 			val = fwprop_ssa_val (rhs);
 		      else if (is_gimple_min_invariant (rhs))
 			val = rhs;
-		      fwprop_set_lattice_val (lhs, val);
+		      fwprop_set_lattice_val (&pass_state, lhs, val);
 		    }
 		}
 
@@ -2450,7 +2452,7 @@  pass_forwprop::execute (function *fun)
 	}
     }
   free (postorder);
-  lattice.release ();
+  pass_state.lattice.release ();
 
   /* Fixup stmts that became noreturn calls.  This may require splitting
      blocks and thus isn't possible during the walk.  Do this
@@ -2465,13 +2467,13 @@  pass_forwprop::execute (function *fun)
 	  print_gimple_stmt (dump_file, stmt, 0, 0);
 	  fprintf (dump_file, "\n");
 	}
-      cfg_changed |= fixup_noreturn_call (stmt);
+      pass_state.cfg_changed |= fixup_noreturn_call (stmt);
     }
 
-  cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
-  BITMAP_FREE (to_purge);
+  pass_state.cfg_changed |= gimple_purge_all_dead_eh_edges (pass_state.to_purge);
+  BITMAP_FREE (pass_state.to_purge);
 
-  if (cfg_changed)
+  if (pass_state.cfg_changed)
     todoflags |= TODO_cleanup_cfg;
 
   return todoflags;