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]

[ast-optimizer-branch] PATCH to simplify ADDR_EXPR


Fixing another departure from the SIMPLE grammar; we now simplify the
operand of an ADDR_EXPR.  I've improved simplify_lvalue_expr to apply to
all cases of simplifying something where what we want is an lvalue,
splitting out most of simplify_expr into a common subroutine.

This fixes a significant bug in which non-simple COMPONENT_REFs were
incorrectly simplified by making a temporary copy of the object and then
referring to a member of the temp.  We now properly store the address of
the object in the temp, and indirect.

Booted and tested i686-pc-linux-gnu; this patch fixes some gcc failures.

2002-06-08  Jason Merrill  <jason@redhat.com>

	* tree-simple.c (is_simple_unary_expr): Only allow the address of
	a varname.
	(is_simple_id): Allow STRING_CST.
	* c-simplify.c (simplify_expr_common): Split out from simplify_expr.
	Do simplify ADDR_EXPR.
	(simplify_lvalue_expr): Use it and build_addr_expr.  Take
	simple_test_f.
	(simplify_modify_expr): Adjust.
	(build_addr_expr): New fn.
	(simplify_array_ref): Use simplify_lvalue_expr.
	(simplify_component_ref): Likewise.
	
*** c-simplify.c.~1~	Sat Jun  8 10:03:36 2002
--- c-simplify.c	Sat Jun  8 16:23:53 2002
*************** static void simplify_do_stmt         PAR
*** 61,66 ****
--- 61,68 ----
  static void simplify_if_stmt         PARAMS ((tree, tree *));
  static void simplify_switch_stmt     PARAMS ((tree, tree *));
  static void simplify_return_stmt     PARAMS ((tree, tree *));
+ static bool simplify_expr_common     PARAMS ((tree *, tree *, tree *,
+                                               int (*) PARAMS ((tree)), tree));
  static void simplify_expr            PARAMS ((tree *, tree *, tree *,
                                                int (*) PARAMS ((tree)), tree));
  static void simplify_array_ref       PARAMS ((tree *, tree *, tree *, tree));
*************** static void simplify_boolean_expr    PAR
*** 74,80 ****
  static void simplify_compound_expr   PARAMS ((tree *, tree *, tree *, tree));
  static void simplify_expr_wfl        PARAMS ((tree *, tree *, tree *,
                                                int (*) PARAMS ((tree)), tree));
! static void simplify_lvalue_expr     PARAMS ((tree *, tree *, tree *, tree));
  static void make_type_writable       PARAMS ((tree));
  static tree add_tree                 PARAMS ((tree, tree *));
  static tree insert_before_continue   PARAMS ((tree, tree));
--- 76,83 ----
  static void simplify_compound_expr   PARAMS ((tree *, tree *, tree *, tree));
  static void simplify_expr_wfl        PARAMS ((tree *, tree *, tree *,
                                                int (*) PARAMS ((tree)), tree));
! static void simplify_lvalue_expr     PARAMS ((tree *, tree *, tree *,
! 					      int (*) PARAMS ((tree)), tree));
  static void make_type_writable       PARAMS ((tree));
  static tree add_tree                 PARAMS ((tree, tree *));
  static tree insert_before_continue   PARAMS ((tree, tree));
*************** static tree convert_to_stmt_chain    PAR
*** 84,89 ****
--- 87,93 ----
  static int  stmt_has_effect          PARAMS ((tree));
  static int  expr_has_effect          PARAMS ((tree));
  static tree mostly_copy_tree_r       PARAMS ((tree *, int *, void *));
+ static tree build_addr_expr	     PARAMS ((tree));
  
  /* Local variables.  */
  static FILE *dump_file;
*************** simplify_return_stmt (stmt, pre_p)
*** 960,967 ****
  	where simplifying an expression requires creating new statement
  	trees.  */
  
! static void
! simplify_expr (expr_p, pre_p, post_p, simple_test_f, stmt)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
--- 964,971 ----
  	where simplifying an expression requires creating new statement
  	trees.  */
  
! static bool
! simplify_expr_common (expr_p, pre_p, post_p, simple_test_f, stmt)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 972,978 ****
      abort ();
  
    if ((*simple_test_f) (*expr_p))
!     return;
  
    /* First deal with the special cases.  */
    switch (TREE_CODE (*expr_p))
--- 976,982 ----
      abort ();
  
    if ((*simple_test_f) (*expr_p))
!     return true;
  
    /* First deal with the special cases.  */
    switch (TREE_CODE (*expr_p))
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1025,1034 ****
  	break;
        }
  
-     /* Address expressions must not be simplified.  If they are, we may
-        end up taking the address of a temporary, instead of the address
-        of the original object.  */
      case ADDR_EXPR:
        break;
  
      /* va_arg expressions should also be left alone to avoid confusing the
--- 1029,1037 ----
  	break;
        }
  
      case ADDR_EXPR:
+       simplify_lvalue_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ 			    is_simple_varname, stmt);
        break;
  
      /* va_arg expressions should also be left alone to avoid confusing the
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1137,1147 ****
        }
      }
  
!   /* Test the simplified expression, if it's sufficiently simple already,
!      return.  */
!   if ((*simple_test_f) (*expr_p))
!     return;
    
    /* Otherwise, we need to create a new temporary to hold the simplified
       expression.  At this point, the expression should be simple enough to
       qualify as a SIMPLE assignment RHS.  Otherwise, simplification has
--- 1140,1163 ----
        }
      }
  
!   /* Test the simplified expression.  */
!   return (*simple_test_f) (*expr_p);
! }
! 
! static void
! simplify_expr (expr_p, pre_p, post_p, simple_test_f, stmt)
!      tree *expr_p;
!      tree *pre_p;
!      tree *post_p;
!      int (*simple_test_f) PARAMS ((tree));
!      tree stmt;
! {
!   bool ok = simplify_expr_common (expr_p, pre_p, post_p, simple_test_f, stmt);
    
+   /* If it's sufficiently simple already, return.  */
+   if (ok)
+     return;
+ 
    /* Otherwise, we need to create a new temporary to hold the simplified
       expression.  At this point, the expression should be simple enough to
       qualify as a SIMPLE assignment RHS.  Otherwise, simplification has
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1166,1171 ****
--- 1182,1207 ----
  
  /* }}} */
  
+ /* Build an expression for the address of T.  Folds away INDIRECT_REF to
+    avoid confusing the simplify process.  */
+ 
+ static tree
+ build_addr_expr (t)
+      tree t;
+ {
+   tree ptrtype = build_pointer_type (TREE_TYPE (t));
+   if (TREE_CODE (t) == INDIRECT_REF)
+     {
+       t = TREE_OPERAND (t, 0);
+       if (TREE_TYPE (t) != ptrtype)
+ 	t = build1 (NOP_EXPR, ptrtype, t);
+     }
+   else
+     t = build1 (ADDR_EXPR, ptrtype, t);
+ 
+   return t;
+ }
+   
  /** {{{ simplify_array_ref ()
  
      Re-write the ARRAY_REF node pointed by EXPR_P.
*************** simplify_array_ref (expr_p, pre_p, post_
*** 1191,1197 ****
       tree *post_p;
       tree stmt;
  {
!   tree base, array;
    varray_type dim_stack;
  
    if (TREE_CODE (*expr_p) != ARRAY_REF)
--- 1227,1233 ----
       tree *post_p;
       tree stmt;
  {
!   tree *p;
    varray_type dim_stack;
  
    if (TREE_CODE (*expr_p) != ARRAY_REF)
*************** simplify_array_ref (expr_p, pre_p, post_
*** 1201,1237 ****
  
    /* Create a stack with all the dimensions of the array so that they can
       be simplified from left to right.  */
!   base = *expr_p;
!   VARRAY_PUSH_GENERIC_PTR (dim_stack, (PTR)&(TREE_OPERAND (*expr_p, 1)));
!   while (TREE_CODE (TREE_OPERAND (base, 0)) == ARRAY_REF)
!     {
!       base = TREE_OPERAND (base, 0);
!       VARRAY_PUSH_GENERIC_PTR (dim_stack, (PTR)&(TREE_OPERAND (base, 1)));
!     }
  
!   /* After the loop above, 'base' contains the leftmost ARRAY_REF,
       and 'dim_stack' is a stack of pointers to all the dimensions in left
       to right order (the leftmost dimension is at the top of the stack).
  
       Simplify the base, and then each of the dimensions from left to
       right.  */
  
!   array = TREE_OPERAND (base, 0);
!   if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE)
!     abort ();
!   if (! is_simple_arraybase (array))
!     {
!       array = fold (build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (array)),
! 			    array));
!       simplify_expr (&array, pre_p, post_p, is_simple_id, stmt);
!       array = build_indirect_ref (array, "");
!       TREE_OPERAND (base, 0) = array;
!     }
  
!   while (VARRAY_ACTIVE_SIZE (dim_stack) > 0)
      {
        tree *dim_p = (tree *)VARRAY_TOP_GENERIC_PTR (dim_stack);
-       VARRAY_POP (dim_stack);
        simplify_expr (dim_p, pre_p, post_p, is_simple_val, stmt);
      }
  
--- 1237,1257 ----
  
    /* Create a stack with all the dimensions of the array so that they can
       be simplified from left to right.  */
!   for (p = expr_p; TREE_CODE (*p) == ARRAY_REF; p = &TREE_OPERAND (*p, 0))
!     VARRAY_PUSH_GENERIC_PTR (dim_stack, (PTR) &TREE_OPERAND (*p, 1));
  
!   /* After the loop above, 'p' points to the first non-ARRAY_REF,
       and 'dim_stack' is a stack of pointers to all the dimensions in left
       to right order (the leftmost dimension is at the top of the stack).
  
       Simplify the base, and then each of the dimensions from left to
       right.  */
  
!   simplify_lvalue_expr (p, pre_p, post_p, is_simple_arraybase, stmt);
  
!   for (; VARRAY_ACTIVE_SIZE (dim_stack) > 0; VARRAY_POP (dim_stack))
      {
        tree *dim_p = (tree *)VARRAY_TOP_GENERIC_PTR (dim_stack);
        simplify_expr (dim_p, pre_p, post_p, is_simple_val, stmt);
      }
  
*************** simplify_self_mod_expr (expr_p, pre_p, p
*** 1275,1284 ****
    /* Simplify the LHS into a SIMPLE lvalue.  We need to deep copy the first
       operand because it will be simplified twice.  Once to convert it into
       a SIMPLE lvalue and the second time when we simplify the resulting
!      binary expression on the RHS of the assignment.  */
    lvalue = TREE_OPERAND (*expr_p, 0);
    walk_tree (&lvalue, copy_tree_r, NULL, NULL);
!   simplify_lvalue_expr (&lvalue, pre_p, post_p, stmt);
  
    /* Determine whether we need to create a PLUS or a MINUS operation.  */
    lhs = TREE_OPERAND (*expr_p, 0);
--- 1295,1307 ----
    /* Simplify the LHS into a SIMPLE lvalue.  We need to deep copy the first
       operand because it will be simplified twice.  Once to convert it into
       a SIMPLE lvalue and the second time when we simplify the resulting
!      binary expression on the RHS of the assignment.
! 
!      ??? This duplicates side-effects.  FIXME!  */
    lvalue = TREE_OPERAND (*expr_p, 0);
    walk_tree (&lvalue, copy_tree_r, NULL, NULL);
!   simplify_lvalue_expr (&lvalue, pre_p, post_p, is_simple_modify_expr_lhs,
! 			stmt);
  
    /* Determine whether we need to create a PLUS or a MINUS operation.  */
    lhs = TREE_OPERAND (*expr_p, 0);
*************** simplify_component_ref (expr_p, pre_p, p
*** 1326,1339 ****
       tree *post_p;
       tree stmt;
  {
    if (TREE_CODE (*expr_p) != COMPONENT_REF)
      abort ();
  
!   simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
!                  is_simple_compref_lhs, stmt);
  
!   simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_id,
!                  stmt);
  }
  
  /* }}} */
--- 1349,1366 ----
       tree *post_p;
       tree stmt;
  {
+   tree *p;
+ 
    if (TREE_CODE (*expr_p) != COMPONENT_REF)
      abort ();
  
!   for (p = expr_p; TREE_CODE (*p) == COMPONENT_REF; p = &TREE_OPERAND (*p, 0))
!     if (! is_simple_id (TREE_OPERAND (*p, 1)))
!       /* The RHS of a COMPONENT_REF should always be a FIELD_DECL.  */
!       abort ();
  
!   /* Now we're down to the first bit that isn't a COMPONENT_REF.  */
!   simplify_lvalue_expr (p, pre_p, post_p, is_simple_arraybase, stmt);
  }
  
  /* }}} */
*************** simplify_modify_expr (expr_p, pre_p, pos
*** 1508,1514 ****
    if (TREE_CODE (*expr_p) != MODIFY_EXPR)
      abort ();
  
!   simplify_lvalue_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, stmt);
    simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_rhs,
                   stmt);
  
--- 1535,1542 ----
    if (TREE_CODE (*expr_p) != MODIFY_EXPR)
      abort ();
  
!   simplify_lvalue_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			is_simple_modify_expr_lhs, stmt);
    simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_rhs,
                   stmt);
  
*************** simplify_expr_wfl (expr_p, pre_p, post_p
*** 1768,1825 ****
  	trees.  */
  
  static void
! simplify_lvalue_expr (expr_p, pre_p, post_p, stmt)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
       tree stmt;
  {
!   if (is_simple_modify_expr_lhs (*expr_p))
!     return;
  
!   if (TREE_CODE (*expr_p) == INDIRECT_REF)
!     {
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id,
! 	             stmt);
!     }
!   else if (TREE_CODE (*expr_p) == COMPONENT_REF
! 	   && TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INDIRECT_REF)
!     {
!       tree t = TREE_OPERAND (*expr_p, 0);
!       simplify_expr (&TREE_OPERAND (t, 0), pre_p, post_p, is_simple_id, stmt);
!     }
!   else if (TREE_CODE (*expr_p) == ARRAY_REF)
!     {
!       simplify_expr (expr_p, pre_p, post_p, is_simple_varname, stmt);
!     }
!   else if (TREE_CODE (*expr_p) == COMPONENT_REF)
      {
!       /* Load the address of the base structure or union into a
! 	 temporary.  Since address expressions are never simplified, we
! 	 don't need to simplify the new lvalue.  */
!       tree lvalue, tmp, base;
!       
!       base = TREE_OPERAND (*expr_p, 0);
!       lvalue = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base);
!       tmp = create_tmp_var (TREE_TYPE (lvalue));
!       add_tree (build_modify_expr (tmp, NOP_EXPR, lvalue), pre_p);
!       
!       /* Re-write the base of the structure with a reference to the new
! 	 temporary.  */
!       TREE_OPERAND (*expr_p, 0) = build1 (INDIRECT_REF, TREE_TYPE (base), tmp);
      }
!   else if (TREE_CODE (*expr_p) == REALPART_EXPR
! 	   || TREE_CODE (*expr_p) == IMAGPART_EXPR)
      {
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 		     is_simple_varname, stmt);
      }
-   else
-     abort ();
  
!   /* If we end up with a temporary variable, we've done something wrong.  */
!   if (simple_tmp_var_p (*expr_p))
      abort ();
  }
  
  /* }}} */
--- 1796,1849 ----
  	trees.  */
  
  static void
! simplify_lvalue_expr (expr_p, pre_p, post_p, simple_test_f, stmt)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
+      int (*simple_test_f) PARAMS ((tree));
       tree stmt;
  {
!   bool ok;
!   tree expr;
  
!   if (TREE_CODE (*expr_p) == REALPART_EXPR
!       || TREE_CODE (*expr_p) == IMAGPART_EXPR)
      {
!       simplify_lvalue_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			    simple_test_f, stmt);
!       return;
      }
! 
!   ok = simplify_expr_common (expr_p, pre_p, post_p, simple_test_f, stmt);
! 
!   /* If it's sufficiently simple already, return.  */
!   if (ok)
!     return;
! 
!   /* Otherwise, we need to create a new temporary to hold the address of
!      the simplified expression.  At this point, the expression should be
!      simple enough to qualify as a SIMPLE varname.  Otherwise,
!      simplification has failed.  */
!   if (!is_simple_varname (*expr_p))
      {
!       fprintf (stderr, "Expression is not a SIMPLE varname:\n");
!       debug_tree (*expr_p);
!       fprintf (stderr, "\n");
!       abort ();
      }
  
!   /* So take the address of the expression, store it in a temporary, and
!      replace the expression with an INDIRECT_REF of that temporary.  */
!   expr = *expr_p;
!   expr = build_addr_expr (expr);
!   simplify_expr (&expr, pre_p, post_p, is_simple_id, stmt);
!   expr = build_indirect_ref (expr, "");
! 
!   /* Make sure the INDIRECT_REF matches our predicate.  */
!   if (!(*simple_test_f) (expr))
      abort ();
+ 
+   *expr_p = expr;
  }
  
  /* }}} */
*** tree-simple.c.~1~	Sat Jun  8 10:03:36 2002
--- tree-simple.c	Sat Jun  8 13:08:22 2002
*************** Boston, MA 02111-1307, USA.  */
*** 121,138 ****
        unary_expr
  	      : simp_expr
  	      | '*' ID
! 	      | '&' original_expr	=> Original grammar only allows
! 					   taking the address of varnames.
! 					   But we can't simplify
! 					   address expressions because we
! 					   may end up taking the address of
! 					   a temporary variable.
! 					   FIXME: It should be possible to
! 					   simplify this somewhat (i.e.,
! 					   simplify parts of
! 					   'original_expr' that do not
! 					   imply converting 'original_expr'
! 					   into a temporary).
  	      | call_expr
  	      | unop val
  	      | '(' cast ')' varname
--- 121,127 ----
        unary_expr
  	      : simp_expr
  	      | '*' ID
! 	      | '&' varname
  	      | call_expr
  	      | unop val
  	      | '(' cast ')' varname
*************** is_simple_unary_expr (t)
*** 578,587 ****
        && is_simple_id (TREE_OPERAND (t, 0)))
      return 1;
  
!   /* Original grammar only allows taking the address of a varname.
!      However, we cannot simplify the operand of an address expression
!      (we might end up taking the address of a temporary).  */
!   if (TREE_CODE (t) == ADDR_EXPR)
      return 1;
  
    if (is_simple_call_expr (t))
--- 567,574 ----
        && is_simple_id (TREE_OPERAND (t, 0)))
      return 1;
  
!   if (TREE_CODE (t) == ADDR_EXPR
!       && is_simple_varname (TREE_OPERAND (t, 0)))
      return 1;
  
    if (is_simple_call_expr (t))
*************** is_simple_id (t)
*** 772,777 ****
--- 759,766 ----
  	  /* Allow the address of a function decl.  */
  	  || (TREE_CODE (t) == ADDR_EXPR
  	      && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
+ 	  /* Allow string constants.  */
+ 	  || TREE_CODE (t) == STRING_CST
  	  /* Allow C99 compound literals.  */
  	  || TREE_CODE (t) == COMPOUND_LITERAL_EXPR);
  }

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