This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Handle __builtin_unreachable () using assertions in VRP


On Tue, 29 Oct 2013, Jakub Jelinek wrote:

> On Tue, Oct 29, 2013 at 12:28:49PM +0100, Richard Biener wrote:
> > Otherwise ok.
> 
> So like this?

Yes, Thanks.
Richard.

> 2013-10-29  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
> 	* tree-cfg.h (assert_unreachable_fallthru_edge_p): New prototype.
> 	* tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): New function.
> 	(remove_range_assertions): If ASSERT_EXPR_VAR has no other immediate
> 	uses but in the condition and ASSERT_EXPR and the other successor of
> 	the predecessor bb is __builtin_unreachable (), set_range_info of the
> 	ASSERT_EXPR_VAR to the range info of the ASSERT_EXPR's lhs.
> 
> --- gcc/tree-cfg.c.jj	2013-10-29 09:25:55.000000000 +0100
> +++ gcc/tree-cfg.c	2013-10-29 14:32:53.235150267 +0100
> @@ -380,6 +380,50 @@ computed_goto_p (gimple t)
>  	  && TREE_CODE (gimple_goto_dest (t)) != LABEL_DECL);
>  }
>  
> +/* Returns true for edge E where e->src ends with a GIMPLE_COND and
> +   the other edge points to a bb with just __builtin_unreachable ().
> +   I.e. return true for C->M edge in:
> +   <bb C>:
> +   ...
> +   if (something)
> +     goto <bb N>;
> +   else
> +     goto <bb M>;
> +   <bb N>:
> +   __builtin_unreachable ();
> +   <bb M>:  */
> +
> +bool
> +assert_unreachable_fallthru_edge_p (edge e)
> +{
> +  basic_block pred_bb = e->src;
> +  gimple last = last_stmt (pred_bb);
> +  if (last && gimple_code (last) == GIMPLE_COND)
> +    {
> +      basic_block other_bb = EDGE_SUCC (pred_bb, 0)->dest;
> +      if (other_bb == e->dest)
> +	other_bb = EDGE_SUCC (pred_bb, 1)->dest;
> +      if (EDGE_COUNT (other_bb->succs) == 0)
> +	{
> +	  gimple_stmt_iterator gsi = gsi_after_labels (other_bb);
> +	  gimple stmt;
> +
> +	  if (gsi_end_p (gsi))
> +	    return false;
> +	  stmt = gsi_stmt (gsi);
> +	  if (is_gimple_debug (stmt))
> +	    {
> +	      gsi_next_nondebug (&gsi);
> +	      if (gsi_end_p (gsi))
> +		return false;
> +	      stmt = gsi_stmt (gsi);
> +	    }
> +	  return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE);
> +	}
> +    }
> +  return false;
> +}
> +
>  
>  /* Search the CFG for any computed gotos.  If found, factor them to a
>     common computed goto site.  Also record the location of that site so
> --- gcc/tree-vrp.c.jj	2013-10-29 09:25:38.382477963 +0100
> +++ gcc/tree-vrp.c	2013-10-29 14:36:23.695060600 +0100
> @@ -6459,6 +6459,33 @@ check_all_array_refs (void)
>      }
>  }
>  
> +/* Return true if all imm uses of VAR are either in STMT, or
> +   feed (optionally through a chain of single imm uses) GIMPLE_COND
> +   in basic block COND_BB.  */
> +
> +static bool
> +all_imm_uses_in_stmt_or_feed_cond (tree var, gimple stmt, basic_block cond_bb)
> +{
> +  use_operand_p use_p, use2_p;
> +  imm_use_iterator iter;
> +
> +  FOR_EACH_IMM_USE_FAST (use_p, iter, var)
> +    if (USE_STMT (use_p) != stmt)
> +      {
> +	gimple use_stmt = USE_STMT (use_p);
> +	if (is_gimple_debug (use_stmt))
> +	  continue;
> +	while (is_gimple_assign (use_stmt)
> +	       && single_imm_use (gimple_assign_lhs (use_stmt),
> +				  &use2_p, &use_stmt))
> +	  ;
> +	if (gimple_code (use_stmt) != GIMPLE_COND
> +	    || gimple_bb (use_stmt) != cond_bb)
> +	  return false;
> +      }
> +  return true;
> +}
> +
>  /* Convert range assertion expressions into the implied copies and
>     copy propagate away the copies.  Doing the trivial copy propagation
>     here avoids the need to run the full copy propagation pass after
> @@ -6488,12 +6515,16 @@ remove_range_assertions (void)
>  {
>    basic_block bb;
>    gimple_stmt_iterator si;
> +  /* 1 if looking at ASSERT_EXPRs immediately at the beginning of
> +     a basic block preceeded by GIMPLE_COND branching to it and
> +     __builtin_trap, -1 if not yet checked, 0 otherwise.  */
> +  int is_unreachable;
>  
>    /* Note that the BSI iterator bump happens at the bottom of the
>       loop and no bump is necessary if we're removing the statement
>       referenced by the current BSI.  */
>    FOR_EACH_BB (bb)
> -    for (si = gsi_start_bb (bb); !gsi_end_p (si);)
> +    for (si = gsi_after_labels (bb), is_unreachable = -1; !gsi_end_p (si);)
>        {
>  	gimple stmt = gsi_stmt (si);
>  	gimple use_stmt;
> @@ -6501,6 +6532,7 @@ remove_range_assertions (void)
>  	if (is_gimple_assign (stmt)
>  	    && gimple_assign_rhs_code (stmt) == ASSERT_EXPR)
>  	  {
> +	    tree lhs = gimple_assign_lhs (stmt);
>  	    tree rhs = gimple_assign_rhs1 (stmt);
>  	    tree var;
>  	    tree cond = fold (ASSERT_EXPR_COND (rhs));
> @@ -6509,22 +6541,49 @@ remove_range_assertions (void)
>  
>  	    gcc_assert (cond != boolean_false_node);
>  
> -	    /* Propagate the RHS into every use of the LHS.  */
>  	    var = ASSERT_EXPR_VAR (rhs);
> -	    FOR_EACH_IMM_USE_STMT (use_stmt, iter,
> -				   gimple_assign_lhs (stmt))
> +	    gcc_assert (TREE_CODE (var) == SSA_NAME);
> +
> +	    if (!POINTER_TYPE_P (TREE_TYPE (lhs))
> +		&& SSA_NAME_RANGE_INFO (lhs))
> +	      {
> +		if (is_unreachable == -1)
> +		  {
> +		    is_unreachable = 0;
> +		    if (single_pred_p (bb)
> +			&& assert_unreachable_fallthru_edge_p
> +						    (single_pred_edge (bb)))
> +		      is_unreachable = 1;
> +		  }
> +		/* Handle
> +		   if (x_7 >= 10 && x_7 < 20)
> +		     __builtin_unreachable ();
> +		   x_8 = ASSERT_EXPR <x_7, ...>;
> +		   if the only uses of x_7 are in the ASSERT_EXPR and
> +		   in the condition.  In that case, we can copy the
> +		   range info from x_8 computed in this pass also
> +		   for x_7.  */
> +		if (is_unreachable
> +		    && all_imm_uses_in_stmt_or_feed_cond (var, stmt,
> +							  single_pred (bb)))
> +		  set_range_info (var, SSA_NAME_RANGE_INFO (lhs)->min,
> +				  SSA_NAME_RANGE_INFO (lhs)->max);
> +	      }
> +
> +	    /* Propagate the RHS into every use of the LHS.  */
> +	    FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
>  	      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
> -		{
> -		  SET_USE (use_p, var);
> -		  gcc_assert (TREE_CODE (var) == SSA_NAME);
> -		}
> +		SET_USE (use_p, var);
>  
>  	    /* And finally, remove the copy, it is not needed.  */
>  	    gsi_remove (&si, true);
>  	    release_defs (stmt);
>  	  }
>  	else
> -	  gsi_next (&si);
> +	  {
> +	    gsi_next (&si);
> +	    is_unreachable = 0;
> +	  }
>        }
>  }
>  
> --- gcc/tree-cfg.h.jj	2013-10-21 09:00:52.000000000 +0200
> +++ gcc/tree-cfg.h	2013-10-29 14:17:52.927812547 +0100
> @@ -51,6 +51,7 @@ extern bool is_ctrl_stmt (gimple);
>  extern bool is_ctrl_altering_stmt (gimple);
>  extern bool simple_goto_p (gimple);
>  extern bool stmt_ends_bb_p (gimple);
> +extern bool assert_unreachable_fallthru_edge_p (edge);
>  extern void delete_tree_cfg_annotations (void);
>  extern gimple first_stmt (basic_block);
>  extern gimple last_stmt (basic_block);
> 
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]