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]

[tree-ssa] Remove useless null pointer checks


This is a first cut at removal of useless null pointer checks based
on the knowledge that after a memory load/store we know the pointer
used must not be null.

This doesn't (yet) subsume the RTL version, mostly because NOP_EXPR
conversions still get in the way (as is true for a number of optimizations
we want to do on trees).

In the process of putting together this patch I uncovered a latent bug
in our statement removal code.

Basically if we have a COMPOUND_EXPR with two empty arms and the arms
belong to different basic blocks, removal of the COMPOUND_EXPR leaves
a dangling basic block -- we have references to it in PHI nodes and
such, but the statements in the block have been disconnected from
the rest of the IL.  This can cause variables to be uninitialized on
some paths through the program.  In fact, it may have been the cause of
some of our PPC problems (my PPC builds are getting a lot farther with
this bug fixed).

Bootstrapped and regression tested on i686-pc-linux-gnu.  Bootstrap on PPC
progresses farther with this patch than without (it's still running and
won't complete until tomorrow at best).

	* tree-cfg.c (bsi_remove): Don't remove a COMPOUND_EXPR with empty
	arms if the arms are in different basic blocks.

	* tree-ssa-dom.c (record_cond_is_false): New function.
	(record_cond_is_true): Similarly.
	(get_eq_expr_value): Use record_cond_expr_is_{true,false}.
	(optimize_stmt): Fix minor formatting issue.  If we encounter an
	INDIRECT_REF, record that the dereferenced pointer can not be
	null.



Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.137
diff -c -3 -p -r1.1.4.137 tree-cfg.c
*** tree-cfg.c	29 Jul 2003 04:37:50 -0000	1.1.4.137
--- tree-cfg.c	31 Jul 2003 00:38:46 -0000
*************** bsi_remove (block_stmt_iterator *i)
*** 1988,1997 ****
      {
        if (TREE_CODE (t) == COMPOUND_EXPR)
  	{
  	  remove_stmt (&TREE_OPERAND (t, 0));
  
! 	  /* If both operands are empty, delete the whole COMPOUND_EXPR.  */
! 	  if (IS_EMPTY_STMT (TREE_OPERAND (t, 1)))
  	    remove_stmt (i->tp);
  	}
        else
--- 1988,2001 ----
      {
        if (TREE_CODE (t) == COMPOUND_EXPR)
  	{
+ 	  basic_block bb = bb_for_stmt (TREE_OPERAND (t, 0));
+ 
  	  remove_stmt (&TREE_OPERAND (t, 0));
  
! 	  /* If both operands are empty and they belong to the same basic
! 	     block, then delete the whole COMPOUND_EXPR.  */
! 	  if (IS_EMPTY_STMT (TREE_OPERAND (t, 1))
! 	      && bb == bb_for_stmt (TREE_OPERAND (t, 1)))
  	    remove_stmt (i->tp);
  	}
        else
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.13
diff -c -3 -p -r1.1.2.13 tree-ssa-dom.c
*** tree-ssa-dom.c	29 Jul 2003 14:57:30 -0000	1.1.2.13
--- tree-ssa-dom.c	31 Jul 2003 00:38:47 -0000
*************** static tree get_eq_expr_value (tree, int
*** 94,99 ****
--- 94,101 ----
  static hashval_t avail_expr_hash (const void *);
  static int avail_expr_eq (const void *, const void *);
  static void htab_statistics (FILE *, htab_t);
+ static void record_cond_is_false (tree cond, varray_type *, htab_t);
+ static void record_cond_is_true (tree cond, varray_type *, htab_t);
  
  /* Optimize function FNDECL based on the dominator tree.  This does
     simple const/copy propagation and redundant expression elimination using
*************** htab_statistics (FILE *file, htab_t htab
*** 409,414 ****
--- 411,443 ----
  	   htab_collisions (htab));
  }
  
+ /* Enter a statement into the available expression hash table indicating
+    that the condition COND is true.  */
+ 
+ static void
+ record_cond_is_true (tree cond,
+ 		     varray_type *block_avail_exprs_p,
+ 		     htab_t const_and_copies)
+ {
+   tree stmt;
+ 
+   stmt = build (MODIFY_EXPR, boolean_type_node, integer_one_node, cond);
+   lookup_avail_expr (stmt, block_avail_exprs_p, const_and_copies);
+ }
+ 
+ /* Enter a statement into the available expression hash table indicating
+    that the condition COND is false.  */
+ 
+ static void
+ record_cond_is_false (tree cond,
+ 		      varray_type *block_avail_exprs_p,
+ 		      htab_t const_and_copies)
+ {
+   tree stmt;
+ 
+   stmt = build (MODIFY_EXPR, boolean_type_node, integer_zero_node, cond);
+   lookup_avail_expr (stmt, block_avail_exprs_p, const_and_copies);
+ }
  
  /* Optimize the statement pointed by iterator SI into SSA form. 
     
*************** optimize_stmt (block_stmt_iterator si, v
*** 504,510 ****
  	       GCC extensions.  */
  	    if (TREE_CODE (val) == SSA_NAME
  		&& !may_propagate_copy (*op_p, val))
! 		continue;
  
  	    /* Gather statistics.  */
  	    if (is_unchanging_value (val) || is_optimizable_addr_expr (val))
--- 533,539 ----
  	       GCC extensions.  */
  	    if (TREE_CODE (val) == SSA_NAME
  		&& !may_propagate_copy (*op_p, val))
! 	      continue;
  
  	    /* Gather statistics.  */
  	    if (is_unchanging_value (val) || is_optimizable_addr_expr (val))
*************** optimize_stmt (block_stmt_iterator si, v
*** 615,620 ****
--- 644,693 ----
  	}
      }
  
+   /* If this is an assignment statement, look at both sides for pointer
+      dereferences.
+ 
+      If a pointer is dereferenced, then we know that the pointer must be
+      nonnull.  In which case we can enter some equivalences into the
+      hash tables.  */
+   if (TREE_CODE (stmt) == MODIFY_EXPR)
+     {
+       int i;
+ 
+       for (i = 0; i < 2; i++)
+ 	{
+ 	  tree t = TREE_OPERAND (stmt, i);
+ 
+ 	  /* Strip away any COMPONENT_REFs.  */
+ 	  while (TREE_CODE (t) == COMPONENT_REF)
+ 	    t = TREE_OPERAND (t, 0);
+ 
+ 	  /* Now see if this is a pointer dereference.  */
+ 	  if (TREE_CODE (t) == INDIRECT_REF)
+ 	    {
+ 	      tree op = TREE_OPERAND (t, 0);
+ 	      tree cond;
+ 
+ 	      /* If the pointer is a SSA variable, then enter new
+ 		 equivalences into the hash table.  */
+ 	      if (TREE_CODE (op) == SSA_NAME)
+ 		{
+ 		  cond = build (EQ_EXPR, boolean_type_node,
+ 				op, null_pointer_node);
+ 		  record_cond_is_false (cond,
+ 					block_avail_exprs_p,
+ 					const_and_copies);
+ 
+ 		  cond = build (NE_EXPR, boolean_type_node,
+ 				op, null_pointer_node);
+ 		  record_cond_is_true (cond,
+ 				       block_avail_exprs_p,
+ 				       const_and_copies);
+ 		}
+ 	    }
+ 	}
+     }
+ 
    /* If STMT is a COND_EXPR and it was modified, then we may know
       where it goes.  In which case we can remove some edges, simplify
       some PHI nodes, maybe even avoid optimizing some blocks completely,
*************** get_eq_expr_value (tree if_stmt, int tru
*** 804,811 ****
       the available expression table.  */
    if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<')
      {
-       tree temp;
- 
        /* When we find an available expression in the hash table, we replace
  	 the expression with the LHS of the statement in the hash table.
  
--- 877,882 ----
*************** get_eq_expr_value (tree if_stmt, int tru
*** 816,850 ****
  	 condition into the hash table.  */
        if (true_arm)
  	{
! 	  /* Insert 1 = cond into the available expression table.  */
! 	  temp = build (MODIFY_EXPR, TREE_TYPE (cond),
! 			integer_one_node, cond);
! 	  temp = lookup_avail_expr (temp,
! 				    block_avail_exprs_p,
! 				    const_and_copies);
! 
! 	  /* Insert 0 = cond' into the hash table.  */
! 	  temp = build (MODIFY_EXPR, TREE_TYPE (cond),
! 			integer_zero_node, invert_truthvalue (cond));
! 	  temp = lookup_avail_expr (temp,
! 				    block_avail_exprs_p,
! 				    const_and_copies);
  	}
        else
  	{
! 	  /* Insert 1 = cond' into the available expression table.  */
! 	  temp = build (MODIFY_EXPR, TREE_TYPE (cond),
! 			integer_one_node, invert_truthvalue (cond));
! 	  temp = lookup_avail_expr (temp,
! 				    block_avail_exprs_p,
! 				    const_and_copies);
! 
! 	  /* Insert 0 = cond into the available expression table.  */
! 	  temp = build (MODIFY_EXPR, TREE_TYPE (cond),
! 			integer_zero_node, cond);
! 	  temp = lookup_avail_expr (temp,
! 				    block_avail_exprs_p,
! 				    const_and_copies);
  	}
      }
  
--- 887,903 ----
  	 condition into the hash table.  */
        if (true_arm)
  	{
! 	  record_cond_is_true (cond, block_avail_exprs_p, const_and_copies);
! 	  record_cond_is_false (invert_truthvalue (cond),
! 				block_avail_exprs_p,
! 				const_and_copies);
  	}
        else
  	{
! 	  record_cond_is_true (invert_truthvalue (cond),
! 			       block_avail_exprs_p,
! 			       const_and_copies);
! 	  record_cond_is_false (cond, block_avail_exprs_p, const_and_copies);
  	}
      }
  







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