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] avoid lowering array_ref and component_ref in c fe


By not lowering &foo[5] to foo + 20 means we don't have to do
as much work to put it back together again.  There were also
cases where we weren't to be able to put it back together.
E.g. &foo[0][0] which would decompose to (int *)&foo, and we
couldn't get rid of the cast.  Should perhaps look into seeing
if we can simplify that back to the array_ref form...

Enhancements in maybe_fold_offset_to_array_ref mean that we
now turn

	int foo[2][2];
	int *p = &foo[0][0];
	*p++ = 1;
	*p++ = 2;
	*p++ = 3;
	*p++ = 4;

back into

	foo[0][0] = 1;
	foo[0][1] = 2;
	foo[1][0] = 3;
	foo[1][1] = 4;

I expect this to become relevant to real code once we're
unrolling loops at the tree level.

There is a hack in place to handle offsetof.  If the array in
question turns out to be an integer constant address, we go ahead
and decompose the addr_expr.  I looked into __builtin_offsetof
like Joseph suggested, but it looked ugly-hard with the grammar
bits.  I left a couple of ??? comments hanging about in relevant
places.

A previous version of this patch handled C++ too, but I can't
find it.  :-/  I'll get that bit taken care of shortly.

Bootstrapped and tested on i686-linux.


r~


        * c-common.c (c_address_looks_like_offsetof): New.
        * c-common.h (c_address_looks_like_offsetof): Declare.
        * c-typeck.c (build_unary_op) <ADDR_EXPR>: Use it.  Don't lower
        address references not destined for offsetof.
        (c_expand_return): Only look inside ARRAY_REF and COMPONENT_REF
        when looking for returning address of local variable.
        * expr.c (expand_expr_1): Don't dereference size of unbounded arrays.
        * gimplify.c (gimplify_addr_expr): Only fold address of variable size
        array elements.
        * tree-simple.c (is_gimple_min_invariant): Also check
        is_gimple_variable before disallowing offset address for type.
        * tree-ssa-ccp.c (maybe_fold_offset_to_aggregate_ref): New.
        (maybe_fold_offset_to_component_ref): Use it.
        (maybe_fold_stmt_indirect, maybe_fold_stmt_plus): Likewise.
        (maybe_fold_offset_to_array_ref): Likewise.  Don't fail for division
        remainder non-zero.
        * varasm.c (initializer_constant_valid_p) <ADDR_EXPR>: Use 
        handled_component_p and look inside references.
        <MINUS_EXPR>: Always look past widening casts.

Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.344.2.53
diff -u -p -c -r1.344.2.53 c-common.c
*** gcc/c-common.c	25 Nov 2003 02:09:30 -0000	1.344.2.53
--- gcc/c-common.c	8 Dec 2003 00:17:25 -0000
*************** c_warn_unused_result (tree *top_p)
*** 6140,6143 ****
--- 6140,6171 ----
      }
  }
  
+ /* Return true if the address of EXP consists of nested ARRAY_REFs
+    and COMPONENT_REFs, with an dereference of an integer constant
+    at the bottom.  */
+ /* ??? It has been suggested that we implement __builtin_offsetof
+    instead, but that's quite ugly grammar-wise, so it is being put
+    off until it is made necessary by fixing the rest of the front
+    end wrt integer constant expression compliance.  */
+ 
+ bool
+ c_address_looks_like_offsetof (tree exp)
+ {
+   if (TREE_CODE (exp) != ARRAY_REF && TREE_CODE (exp) != COMPONENT_REF)
+     return false;
+   do
+     {
+       exp = TREE_OPERAND (exp, 0);
+     }
+   while (TREE_CODE (exp) == ARRAY_REF || TREE_CODE (exp) == COMPONENT_REF);
+ 
+   if (TREE_CODE (exp) != INDIRECT_REF)
+     return false;
+   exp = TREE_OPERAND (exp, 0);
+ 
+   STRIP_NOPS (exp);
+ 
+   return TREE_CODE (exp) == INTEGER_CST;
+ }
+ 
  #include "gt-c-common.h"
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.141.2.39
diff -u -p -c -r1.141.2.39 c-common.h
*** gcc/c-common.h	25 Nov 2003 02:09:31 -0000	1.141.2.39
--- gcc/c-common.h	8 Dec 2003 00:17:26 -0000
*************** extern tree c_walk_subtrees (tree*, int*
*** 1287,1292 ****
--- 1287,1293 ----
  extern int c_tree_chain_matters_p (tree);
  
  extern void c_warn_unused_result (tree *);
+ extern bool c_address_looks_like_offsetof (tree);
  
  /* In c-simplify.c  */
  extern void c_genericize (tree);
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.196.2.33
diff -u -p -c -r1.196.2.33 c-typeck.c
*** gcc/c-typeck.c	25 Nov 2003 02:09:33 -0000	1.196.2.33
--- gcc/c-typeck.c	8 Dec 2003 00:17:31 -0000
*************** build_unary_op (enum tree_code code, tre
*** 2385,2463 ****
  
      case ADDR_EXPR:
        /* Note that this operation never does default_conversion.  */
  
!       /* Let &* cancel out to simplify resulting code.  */
!       if (TREE_CODE (arg) == INDIRECT_REF)
! 	{
! 	  /* Don't let this be an lvalue.  */
! 	  if (lvalue_p (TREE_OPERAND (arg, 0)))
! 	    return non_lvalue (TREE_OPERAND (arg, 0));
! 	  return TREE_OPERAND (arg, 0);
! 	}
  
!       /* For &x[y], return x+y */
!       if (TREE_CODE (arg) == ARRAY_REF)
! 	{
! 	  if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
! 	    return error_mark_node;
  	  return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
  				  TREE_OPERAND (arg, 1), 1);
- 	}
  
!       /* Handle complex lvalues (when permitted)
! 	 by reduction to simpler cases.  */
!       val = unary_complex_lvalue (code, arg, flag);
!       if (val != 0)
! 	return val;
! 
!       /* Anything not already handled and not a true memory reference
! 	 or a non-lvalue array is an error.  */
!       else if (typecode != FUNCTION_TYPE && !flag
! 	       && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
! 	return error_mark_node;
  
!       /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
!       argtype = TREE_TYPE (arg);
  
!       /* If the lvalue is const or volatile, merge that into the type
!          to which the address will point.  Note that you can't get a
! 	 restricted pointer by taking the address of something, so we
! 	 only have to deal with `const' and `volatile' here.  */
!       if ((DECL_P (arg) || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
! 	  && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
  	  argtype = c_build_type_variant (argtype,
  					  TREE_READONLY (arg),
  					  TREE_THIS_VOLATILE (arg));
  
!       argtype = build_pointer_type (argtype);
! 
!       if (!c_mark_addressable (arg))
! 	return error_mark_node;
  
!       {
! 	tree addr;
  
! 	if (TREE_CODE (arg) == COMPONENT_REF)
  	  {
  	    tree field = TREE_OPERAND (arg, 1);
  
  	    addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
  
  	    if (DECL_C_BIT_FIELD (field))
  	      {
! 		error ("attempt to take address of bit-field structure member `%s'",
  		       IDENTIFIER_POINTER (DECL_NAME (field)));
  		return error_mark_node;
  	      }
  
! 	    addr = fold (build (PLUS_EXPR, argtype,
  				convert (argtype, addr),
  				convert (argtype, byte_position (field))));
  	  }
- 	else
- 	  addr = build1 (code, argtype, arg);
  
! 	return addr;
        }
  
      default:
--- 2385,2472 ----
  
      case ADDR_EXPR:
        /* Note that this operation never does default_conversion.  */
+       {
+ 	bool maybe_addressof;
  
! 	/* Let &* cancel out to simplify resulting code.  */
! 	if (TREE_CODE (arg) == INDIRECT_REF)
! 	  {
! 	    /* Don't let this be an lvalue.  */
! 	    if (lvalue_p (TREE_OPERAND (arg, 0)))
! 	      return non_lvalue (TREE_OPERAND (arg, 0));
! 	    return TREE_OPERAND (arg, 0);
! 	  }
  
! 	/* Handle offsetof by detecting a constant at the bottom of a
! 	   sequence of component and array references.  We will want
! 	   to use a PLUS to find the address.  If we don't, then we won't
! 	   have the constant folded early enough to qualify for an
! 	   integer constant expression.  */
! 	/* ??? Note that the common macro definition of offsetof itself
! 	   does not qualify as an integer constant expression.  It has
! 	   been suggested that we implement __builtin_offsetof for this
! 	   case, but that's quite ugly grammar-wise, so it is being put
! 	   off until it is made necessary by fixing the rest of the front
! 	   end wrt integer constant expression compliance.  */
! 	maybe_addressof = c_address_looks_like_offsetof (arg);
! 
!         /* For offsetof, and &x[y], return x+y.  */
! 	if (maybe_addressof && TREE_CODE (arg) == ARRAY_REF)
  	  return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
  				  TREE_OPERAND (arg, 1), 1);
  
! 	/* Handle complex lvalues (when permitted) by reduction to
! 	   simpler cases.  */
! 	val = unary_complex_lvalue (ADDR_EXPR, arg, flag);
! 	if (val != 0)
! 	  return val;
! 
! 	/* Anything not already handled and not a true memory reference
! 	   or a non-lvalue array is an error.  */
! 	if (typecode != FUNCTION_TYPE && !flag
! 	    && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
! 	  return error_mark_node;
  
! 	/* Ordinary case; arg is a COMPONENT_REF or a decl.  */
! 	argtype = TREE_TYPE (arg);
  
! 	/* If the lvalue is const or volatile, merge that into the type
! 	   to which the address will point.  Note that you can't get a
! 	   restricted pointer by taking the address of something, so we
! 	   only have to deal with `const' and `volatile' here.  */
! 	if ((DECL_P (arg) || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
! 	    && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
  	  argtype = c_build_type_variant (argtype,
  					  TREE_READONLY (arg),
  					  TREE_THIS_VOLATILE (arg));
  
! 	argtype = build_pointer_type (argtype);
  
! 	if (!c_mark_addressable (arg))
! 	  return error_mark_node;
  
!         /* For offsetof, and s.f, return &s + offsetof(f).  */
! 	if (maybe_addressof && TREE_CODE (arg) == COMPONENT_REF)
  	  {
  	    tree field = TREE_OPERAND (arg, 1);
+ 	    tree addr;
  
  	    addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
  
  	    if (DECL_C_BIT_FIELD (field))
  	      {
! 		error ("attempt to take address of bit-field "
! 		       "structure member `%s'",
  		       IDENTIFIER_POINTER (DECL_NAME (field)));
  		return error_mark_node;
  	      }
  
! 	    return fold (build (PLUS_EXPR, argtype,
  				convert (argtype, addr),
  				convert (argtype, byte_position (field))));
  	  }
  
! 	return build1 (ADDR_EXPR, argtype, arg);
        }
  
      default:
*************** c_expand_return (tree retval)
*** 6337,6343 ****
  	    case ADDR_EXPR:
  	      inner = TREE_OPERAND (inner, 0);
  
! 	      while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
  		inner = TREE_OPERAND (inner, 0);
  
  	      if (TREE_CODE (inner) == VAR_DECL
--- 6346,6353 ----
  	    case ADDR_EXPR:
  	      inner = TREE_OPERAND (inner, 0);
  
! 	      while (TREE_CODE (inner) == COMPONENT_REF
! 		     || TREE_CODE (inner) == ARRAY_REF)
  		inner = TREE_OPERAND (inner, 0);
  
  	      if (TREE_CODE (inner) == VAR_DECL
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.467.2.67
diff -u -p -c -r1.467.2.67 expr.c
*** gcc/expr.c	5 Dec 2003 16:27:55 -0000	1.467.2.67
--- gcc/expr.c	8 Dec 2003 00:17:39 -0000
*************** expand_expr_1 (tree exp, rtx target, enu
*** 7367,7374 ****
  	       size of the type isn't the same size as the bitfield,
  	       we must use bitfield operations.  */
  	    || (bitsize >= 0
! 		&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
! 		    == INTEGER_CST)
  		&& 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
  					  bitsize)))
  	  {
--- 7367,7374 ----
  	       size of the type isn't the same size as the bitfield,
  	       we must use bitfield operations.  */
  	    || (bitsize >= 0
! 		&& TYPE_SIZE (TREE_TYPE (exp))
! 		&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
  		&& 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
  					  bitsize)))
  	  {
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.125
diff -u -p -c -r1.1.2.125 gimplify.c
*** gcc/gimplify.c	7 Dec 2003 10:07:45 -0000	1.1.2.125
--- gcc/gimplify.c	8 Dec 2003 00:17:42 -0000
*************** gimplify_addr_expr (tree *expr_p, tree *
*** 2429,2443 ****
        break;
  
      case ARRAY_REF:
!       /* Fold &a[6] to (&a + 6).  */
!       ret = gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0),
! 					pre_p, post_p);
  
!       /* This added an INDIRECT_REF.  Fold it away.  */
!       op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
  
!       *expr_p = op0;
!       break;
  
      default:
        /* We use fb_either here because the C frontend sometimes takes
--- 2429,2450 ----
        break;
  
      case ARRAY_REF:
!       /* If the size of the array elements is not constant, computing
! 	 the offset is non-trivial, so expose it.  If we don't do this
! 	 here, then gimplify_array_ref will, and the result won't match
! 	 is_gimple_addr_expr_arg.  */
!       if (!TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (op0))))
! 	{
! 	  ret = gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0),
! 					    pre_p, post_p);
  
! 	  /* This added an INDIRECT_REF.  Fold it away.  */
! 	  op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
  
! 	  *expr_p = op0;
! 	  break;
! 	}
!       /* FALLTHRU */
  
      default:
        /* We use fb_either here because the C frontend sometimes takes
Index: gcc/tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.4.63
diff -u -p -c -r1.1.4.63 tree-simple.c
*** gcc/tree-simple.c	4 Dec 2003 02:22:01 -0000	1.1.4.63
--- gcc/tree-simple.c	8 Dec 2003 00:17:42 -0000
*************** is_gimple_min_invariant (tree t)
*** 286,292 ****
  
      case PLUS_EXPR:
        {
! 	tree op0, op1;
  
  	if (!TREE_INVARIANT (t))
  	  return false;
--- 286,292 ----
  
      case PLUS_EXPR:
        {
! 	tree op0, op1, op00;
  
  	if (!TREE_INVARIANT (t))
  	  return false;
*************** is_gimple_min_invariant (tree t)
*** 304,310 ****
  	   is doing something tricky or stupid, and the later case
  	   can result in constructs that we can't reassemble after
  	   we've already committed to the constant propagation.  */
! 	if (is_gimple_reg_type (TREE_TYPE (TREE_OPERAND (op0, 0))))
  	  return false;
  
  	return true;
--- 304,311 ----
  	   is doing something tricky or stupid, and the later case
  	   can result in constructs that we can't reassemble after
  	   we've already committed to the constant propagation.  */
! 	op00 = TREE_OPERAND (op0, 0);
! 	if (is_gimple_variable (op00) && is_gimple_reg_type (TREE_TYPE (op00)))
  	  return false;
  
  	return true;
Index: gcc/tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.121
diff -u -p -c -r1.1.2.121 tree-ssa-ccp.c
*** gcc/tree-ssa-ccp.c	5 Dec 2003 23:02:24 -0000	1.1.2.121
--- gcc/tree-ssa-ccp.c	8 Dec 2003 00:17:44 -0000
*************** likely_value (tree stmt)
*** 1489,1494 ****
--- 1489,1496 ----
     BASE is an array type.  OFFSET is a byte displacement.  ORIG_TYPE
     is the desired result type.   */
  
+ static tree maybe_fold_offset_to_aggregate_ref (tree, tree, tree);
+ 
  static tree
  maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
  {
*************** maybe_fold_offset_to_array_ref (tree bas
*** 1496,1526 ****
    HOST_WIDE_INT hquo, hrem;
    tree elt_size, min_idx, idx;
    tree array_type, elt_type;
  
    /* Ignore stupid user tricks of indexing non-array variables.  */
    array_type = TREE_TYPE (base);
    if (TREE_CODE (array_type) != ARRAY_TYPE)
      return NULL_TREE;
    elt_type = TREE_TYPE (array_type);
!   if (TYPE_MAIN_VARIANT (orig_type) != TYPE_MAIN_VARIANT (elt_type))
      return NULL_TREE;
! 	
    /* Whee.  Ignore indexing of variable sized types.  */
    elt_size = TYPE_SIZE_UNIT (elt_type);
    if (TREE_CODE (elt_size) != INTEGER_CST)
      return NULL_TREE;
  
!   /* If the division isn't exact, then don't do anything.  Equally
!      invalid as the above indexing of non-array variables.  */
!   if (div_and_round_double (TRUNC_DIV_EXPR, 1,
  			    TREE_INT_CST_LOW (offset),
  			    TREE_INT_CST_HIGH (offset),
  			    TREE_INT_CST_LOW (elt_size),
  			    TREE_INT_CST_HIGH (elt_size),
! 			    &lquo, &hquo, &lrem, &hrem)
!       || lrem || hrem)
!     return NULL_TREE;
    idx = build_int_2_wide (lquo, hquo);
  
    /* Re-bias the index by the min index of the array type.  */
    min_idx = TYPE_DOMAIN (TREE_TYPE (base));
--- 1498,1539 ----
    HOST_WIDE_INT hquo, hrem;
    tree elt_size, min_idx, idx;
    tree array_type, elt_type;
+   bool recurse;
  
    /* Ignore stupid user tricks of indexing non-array variables.  */
    array_type = TREE_TYPE (base);
    if (TREE_CODE (array_type) != ARRAY_TYPE)
      return NULL_TREE;
    elt_type = TREE_TYPE (array_type);
! 
!   /* If the array is of the type we're looking for, then we'll not
!      need to search further.  */
!   if (TYPE_MAIN_VARIANT (orig_type) == TYPE_MAIN_VARIANT (elt_type))
!     recurse = false;
!   /* If the element type is an aggregate, then (given that we have
!      a type mismatch) we'll need to search that type for the subtype.  */
!   else if (AGGREGATE_TYPE_P (elt_type))
!     recurse = true;
!   /* Otherwise we have no way to resolve the matter.  */
!   else
      return NULL_TREE;
! 
    /* Whee.  Ignore indexing of variable sized types.  */
    elt_size = TYPE_SIZE_UNIT (elt_type);
    if (TREE_CODE (elt_size) != INTEGER_CST)
      return NULL_TREE;
  
!   /* If the division overflows... can it overflow?  */
!   if (div_and_round_double (TRUNC_DIV_EXPR,
! 			    TREE_UNSIGNED (TREE_TYPE (offset)),
  			    TREE_INT_CST_LOW (offset),
  			    TREE_INT_CST_HIGH (offset),
  			    TREE_INT_CST_LOW (elt_size),
  			    TREE_INT_CST_HIGH (elt_size),
! 			    &lquo, &hquo, &lrem, &hrem))
!     abort ();
    idx = build_int_2_wide (lquo, hquo);
+   TREE_TYPE (idx) = TREE_TYPE (offset);
  
    /* Re-bias the index by the min index of the array type.  */
    min_idx = TYPE_DOMAIN (TREE_TYPE (base));
*************** maybe_fold_offset_to_array_ref (tree bas
*** 1535,1540 ****
--- 1548,1567 ----
  	}
      }
  
+   if (recurse)
+     {
+       base = build (ARRAY_REF, elt_type, base, idx);
+       offset = build_int_2_wide (lrem, hrem);
+       TREE_TYPE (idx) = TREE_TYPE (offset);
+ 
+       return maybe_fold_offset_to_aggregate_ref (base, offset, orig_type);
+     }
+ 
+   /* If we didn't recurse, and we have a remainder, then what we just
+      computed is wrong.  */
+   if (lrem || hrem)
+     return NULL_TREE;
+ 
    return build (ARRAY_REF, orig_type, base, idx);
  }
  
*************** maybe_fold_offset_to_component_ref (tree
*** 1622,1637 ****
  	base = build1 (INDIRECT_REF, record_type, base);
        base = build (COMPONENT_REF, field_type, base, f);
  
!       t = maybe_fold_offset_to_array_ref (base, offset, orig_type);
!       if (t)
! 	return t;
!       return maybe_fold_offset_to_component_ref (field_type, base, offset,
! 					         orig_type, false);
      }
  
    return NULL_TREE;
  }
  
  /* A subroutine of fold_stmt_r.  Attempt to simplify *(BASE+OFFSET).
     Return the simplified expression, or NULL if nothing could be done.  */
  
--- 1649,1676 ----
  	base = build1 (INDIRECT_REF, record_type, base);
        base = build (COMPONENT_REF, field_type, base, f);
  
!       return maybe_fold_offset_to_aggregate_ref (base, offset, orig_type);
      }
  
    return NULL_TREE;
  }
  
+ /* A subroutine of fold_stmt_r.  Attempts to fold BASE+OFFSET to
+    an aggregate reference to ORIG_TYPE.  */
+ 
+ static tree
+ maybe_fold_offset_to_aggregate_ref (tree base, tree offset, tree orig_type)
+ {
+   tree t;
+ 
+   t = maybe_fold_offset_to_array_ref (base, offset, orig_type);
+   if (t)
+     return t;
+ 
+   return maybe_fold_offset_to_component_ref (TREE_TYPE (base), base,
+ 					     offset, orig_type, false);
+ }
+ 
  /* A subroutine of fold_stmt_r.  Attempt to simplify *(BASE+OFFSET).
     Return the simplified expression, or NULL if nothing could be done.  */
  
*************** maybe_fold_stmt_indirect (tree expr, tre
*** 1670,1683 ****
        /* Strip the ADDR_EXPR.  */
        base = TREE_OPERAND (base, 0);
  
!       /* Try folding *(&B+O) to B[X].  */
!       t = maybe_fold_offset_to_array_ref (base, offset, TREE_TYPE (expr));
!       if (t)
! 	return t;
! 
!       /* Try folding *(&B+O) to B.X.  */
!       t = maybe_fold_offset_to_component_ref (TREE_TYPE (base), base, offset,
! 					      TREE_TYPE (expr), false);
        if (t)
  	return t;
  
--- 1709,1715 ----
        /* Strip the ADDR_EXPR.  */
        base = TREE_OPERAND (base, 0);
  
!       t = maybe_fold_offset_to_aggregate_ref (base, offset, TREE_TYPE (expr));
        if (t)
  	return t;
  
*************** maybe_fold_stmt_plus (tree expr)
*** 1800,1809 ****
    ptd_type = TREE_TYPE (ptr_type);
  
    /* At which point we can try some of the same things as for indirects.  */
!   t = maybe_fold_offset_to_array_ref (op0, op1, ptd_type);
!   if (!t)
!     t = maybe_fold_offset_to_component_ref (TREE_TYPE (op0), op0, op1,
! 					    ptd_type, false);
    if (t)
      t = build1 (ADDR_EXPR, ptr_type, t);
  
--- 1832,1838 ----
    ptd_type = TREE_TYPE (ptr_type);
  
    /* At which point we can try some of the same things as for indirects.  */
!   t = maybe_fold_offset_to_aggregate_ref (op0, op1, ptd_type);
    if (t)
      t = build1 (ADDR_EXPR, ptr_type, t);
  
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.295.2.38
diff -u -p -c -r1.295.2.38 varasm.c
*** gcc/varasm.c	25 Nov 2003 02:09:57 -0000	1.295.2.38
--- gcc/varasm.c	8 Dec 2003 00:17:47 -0000
*************** initializer_constant_valid_p (tree value
*** 3534,3540 ****
  
      case ADDR_EXPR:
      case FDESC_EXPR:
!       return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
  
      case VIEW_CONVERT_EXPR:
      case NON_LVALUE_EXPR:
--- 3534,3549 ----
  
      case ADDR_EXPR:
      case FDESC_EXPR:
!       /* Go inside any operations that get_inner_reference can handle and
! 	 see if what's inside is a constant.  */
!       for (value = TREE_OPERAND (value, 0);
! 	   handled_component_p (value);
! 	   value = TREE_OPERAND (value, 0))
! 	if (TREE_CODE (value) == ARRAY_REF
! 	    && TREE_CODE (TREE_OPERAND (value, 1)) != INTEGER_CST)
! 	  break;
! 
!       return staticp (value) ? value : 0;
  
      case VIEW_CONVERT_EXPR:
      case NON_LVALUE_EXPR:
*************** initializer_constant_valid_p (tree value
*** 3615,3688 ****
        break;
  
      case MINUS_EXPR:
!       if (! INTEGRAL_TYPE_P (endtype)
! 	  || TYPE_PRECISION (endtype) >= POINTER_SIZE)
! 	{
! 	  tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
! 						      endtype);
! 	  tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
! 						      endtype);
! 	  /* Win if second argument is absolute.  */
! 	  if (valid1 == null_pointer_node)
! 	    return valid0;
! 	  /* Win if both arguments have the same relocation.
! 	     Then the value is absolute.  */
! 	  if (valid0 == valid1 && valid0 != 0)
! 	    return null_pointer_node;
  
! 	  /* Since GCC guarantees that string constants are unique in the
! 	     generated code, a subtraction between two copies of the same
! 	     constant string is absolute.  */
! 	  if (valid0 && TREE_CODE (valid0) == STRING_CST &&
! 	      valid1 && TREE_CODE (valid1) == STRING_CST &&
! 	      TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
! 	    return null_pointer_node;
! 	}
  
!       /* Support differences between labels.  */
!       if (INTEGRAL_TYPE_P (endtype))
! 	{
! 	  tree op0, op1;
! 	  op0 = TREE_OPERAND (value, 0);
! 	  op1 = TREE_OPERAND (value, 1);
! 
! 	  /* Like STRIP_NOPS except allow the operand mode to widen.
! 	     This works around a feature of fold that simplifies
! 	     (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
! 	     that the narrower operation is cheaper.  */
! 
! 	  while (TREE_CODE (op0) == NOP_EXPR
! 		 || TREE_CODE (op0) == CONVERT_EXPR
! 		 || TREE_CODE (op0) == NON_LVALUE_EXPR)
! 	    {
! 	      tree inner = TREE_OPERAND (op0, 0);
! 	      if (inner == error_mark_node
! 	          || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
! 		  || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
! 		      > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
! 		break;
! 	      op0 = inner;
! 	    }
! 
! 	  while (TREE_CODE (op1) == NOP_EXPR
! 		 || TREE_CODE (op1) == CONVERT_EXPR
! 		 || TREE_CODE (op1) == NON_LVALUE_EXPR)
! 	    {
! 	      tree inner = TREE_OPERAND (op1, 0);
! 	      if (inner == error_mark_node
! 	          || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
! 		  || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
! 		      > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
! 		break;
! 	      op1 = inner;
! 	    }
! 
! 	  if (TREE_CODE (op0) == ADDR_EXPR
! 	      && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
! 	      && TREE_CODE (op1) == ADDR_EXPR
! 	      && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
! 	    return null_pointer_node;
! 	}
        break;
  
      default:
--- 3624,3694 ----
        break;
  
      case MINUS_EXPR:
!       {
! 	tree op0, op1, valid0, valid1;
  
! 	op0 = TREE_OPERAND (value, 0);
! 	op1 = TREE_OPERAND (value, 1);
  
! 	/* Like STRIP_NOPS except allow the operand mode to widen.
! 	   This works around a feature of fold that simplifies
! 	   (short)(p1 - p2) to ((short)p1 - (short)p2) under the
! 	   theory that the narrower operation is cheaper.  */
! 
! 	while (TREE_CODE (op0) == NOP_EXPR
! 	       || TREE_CODE (op0) == CONVERT_EXPR
! 	       || TREE_CODE (op0) == NON_LVALUE_EXPR)
! 	  {
! 	    tree inner = TREE_OPERAND (op0, 0);
! 	    if (inner == error_mark_node
! 	        || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
! 		|| (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
! 		    > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
! 	      break;
! 	    op0 = inner;
! 	  }
! 
! 	while (TREE_CODE (op1) == NOP_EXPR
! 	       || TREE_CODE (op1) == CONVERT_EXPR
! 	       || TREE_CODE (op1) == NON_LVALUE_EXPR)
! 	  {
! 	    tree inner = TREE_OPERAND (op1, 0);
! 	    if (inner == error_mark_node
! 	        || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
! 		|| (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
! 		    > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
! 	      break;
! 	    op1 = inner;
! 	  }
! 
! 	valid0 = initializer_constant_valid_p (op0, endtype);
! 	valid1 = initializer_constant_valid_p (op1, endtype);
! 
! 	/* Win if second argument is absolute.  */
! 	if (valid1 == null_pointer_node)
! 	  return valid0;
! 
! 	/* Other winning solutions require both valid.  */
! 	if (valid0 && valid1)
! 	  {
! 	    /* If both arguments have the same relocation then the
! 	       value is absolute.  */
! 	    if (valid0 == valid1)
! 	      return null_pointer_node;
! 
! 	    /* Since GCC guarantees that string constants are unique in the
! 	       generated code, a subtraction between two copies of the same
! 	       constant string is absolute.  */
! 	    if (TREE_CODE (valid0) == STRING_CST
! 	        && operand_equal_p (valid0, valid1, 0))
! 	      return null_pointer_node;
! 
!             /* Support differences between labels.  */
! 	    if (TREE_CODE (valid0) == LABEL_DECL
! 		&& TREE_CODE (valid1) == LABEL_DECL)
! 	      return null_pointer_node;
! 	  }
!       }
        break;
  
      default:


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