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]

[PATCH RFC/RFA] refactor initializer_constant_valid_p, fixes label difference bug


initializer_constant_valid_p is a weird predicate because on one hand its users only consider its result as boolean (NULL/not NULL), on the other hand it returns a tree and performs some complicated tests on the return value.

The reason it performs these tests is that some values that are valid constant initializers may not be folded; so initializer_constant_valid_p tries to do this folding itself by associating a tree with a "relocation base" (e.g. "a" for "&a[5]").

My attempt to simplify this started from the observation that all of these values *are* nowadays folded, which makes the computations in initializer_constant_valid_p pointless. Actually this patch had quite some ramifications, as I'll show.

Starting from the analysis of initializer_constant_valid_p, the only interesting cases are PLUS_EXPR and MINUS_EXPR.

MINUS_EXPR catches two cases: one is &a[5] - &a[2], which is done by returning "a" as the relocation base for both and then returning null_pointer_node because the relocation bases cancel each other. The other is &&label2 - &&label1, where the code for ADDR_EXPR returns the label itself as the relocation base -- then initalizer_constant_valid_p treats two LABEL_DECL relocation bases as if they always cancel each other.

In my patch, the first special case is removed because it is handled by fold. I was worried that folding may not detect some patterns because of associativity problems. However this does not happen because the type system forces the presence of parentheses that help the folder to do the right thing. For example, in this example

  int a[5], b[5];
  const int x = &a[5] + (&b[3] - &b[1]) - a;

this is the only valid parenthesization of the definition of x.

The second special case is handled by not recursing and matching directly the ADDR_EXPR<LABEL_DECL> - ADDR_EXPR<LABEL_DECL> pattern.

Regarding PLUS_EXPR and POINTER_PLUS_EXPR, it would call itself recursively on the operands and perform this three-state operation on the results (called valid0 and valid1 here):

   valid1 \ valid0      NULL_TREE     null_pointer_node      other
   NULL_TREE            NULL_TREE     NULL_TREE              NULL_TREE
   null_pointer_node    NULL_TREE     null_pointer_node      valid0
   other                NULL_TREE     valid1                 NULL_TREE

So, this patch introduces a new initializer_constant_absolute_p. This actually fixes a bug. Before the patch, this function was diagnosed as wrong...

  int f()
  {
    struct s { int a[3]; };
    static const void *x = (&&a - &&b) + 5;
    static int y = (&&a - &&b) + 5;

    return x;
    a: abort ();
    b: return y;
  }

... while now it is compiled correctly (whatever it means). Again, fold comes to the rescue and makes us able to deal with this too:

  int f()
  {
    struct s { int a[3]; };
    static const void *x = &&a + 5 - &&b;
    static int y = &&a + 5 - &&b;

    return x;
    a: abort ();
    b: return y;
  }

On the other hand this highlighted a bug in final.c, which was not prepared to handle MINUS expressions in targets whose assembler has no parentheses. So this patch adds this capability.

Bootstrapped/regtested i686-pc-linux-gnu, including Ada. Ok? Or more precisely, is it worth it? :-)

(By the way, the reason to do this cleanup is to tackle the other extra-obscure predicate, staticp. It also returns a tree and its value was only used by initializer_constant_valid_p).

Paolo
2008-04-25  Paolo Bonzini  <bonzini@gnu.org>

	* tree.h (categorize_ctor_elements): Fix documentation.
	* expr.c (categorize_ctor_elements_1): Fix calls to
	initializer_constant_valid_p.
	(categorize_ctor_elements): Fix documentation.
	* output.h (initializer_constant_valid_p): Fix documentation.
	* final.c (output_addr_const_1): New, from...
	(output_addr_const): ... this one.  Call it from here.
	* varasm.c (initializer_constant_absolute_p): New.
	(initializer_constant_valid_p): Return bool.  Simplify assuming
	more powerful folding and correct POINTER_PLUS_EXPR semantics.

2008-04-25  Paolo Bonzini  <bonzini@gnu.org>

	* cp/typeck.c (build_ptrmemfunc1): Fix calls to
	initializer_constant_valid_p.

Index: tree.h
===================================================================
--- tree.h	(revision 134628)
+++ tree.h	(working copy)
@@ -4411,7 +4411,7 @@ extern bool initializer_zerop (const_tre
      is not the largest element in the union, then set *p_must_clear.
 
    Return whether or not CTOR is a valid static constant initializer, the same
-   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
+   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR))".  */
 
 extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
 				      bool *);
Index: final.c
===================================================================
--- final.c	(revision 134628)
+++ final.c	(working copy)
@@ -3363,18 +3363,70 @@ output_address (rtx x)
 }
 
 /* Print an integer constant expression in assembler syntax.
-   Addition and subtraction are the only arithmetic
-   that may appear in these expressions.  */
+   Recursive workhorse, handling simplification of addition and
+   subtraction.  */
 
-void
-output_addr_const (FILE *file, rtx x)
+static void
+output_addr_const_1 (FILE *file, rtx x, char op)
 {
   char buf[256];
+  HOST_WIDE_INT val;
 
  restart:
   switch (GET_CODE (x))
     {
+    case PLUS:
+      /* Some assemblers need integer constants to appear last (eg masm).  */
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+	{
+	  output_addr_const_1 (file, XEXP (x, 1), op);
+	  output_addr_const_1 (file, XEXP (x, 0), op == '-' ? '-' : '+');
+	}
+      else
+	{
+          output_addr_const_1 (file, XEXP (x, 0), op);
+          output_addr_const_1 (file, XEXP (x, 1), op == '-' ? '-' : '+');
+	}
+      return;
+
+    case MINUS:
+      /* Avoid outputting things like x-x or x+5-x,
+	 since some assemblers can't handle that.  */
+      x = simplify_subtraction (x);
+      if (GET_CODE (x) != MINUS)
+	goto restart;
+
+      output_addr_const_1 (file, XEXP (x, 0), op);
+      output_addr_const_1 (file, XEXP (x, 1), op == '-' ? '+' : '-');
+      return;
+
+    case CONST_INT:
+      val = INTVAL (x);
+      if (op == '-')
+	op = '+', val = -val;
+      if (val >= 0 && op == '+')
+	putc ('+', file);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
+      return;
+
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+    case SUBREG:
+    case TRUNCATE:
+    case CONST:
+      output_addr_const_1 (file, XEXP (x, 0), op);
+      return;
+
+    default:
+      break;
+    }
+
+  if (op)
+    putc (op, file);
+
+  switch (GET_CODE (x))
+    {
     case PC:
       putc ('.', file);
       break;
 
@@ -3400,16 +3453,6 @@ output_addr_const (FILE *file, rtx x)
 #endif
       break;
 
-    case CONST_INT:
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
-      break;
-
-    case CONST:
-      /* This used to output parentheses around the expression,
-	 but that does not work on the 386 (either ATT or BSD assembler).  */
-      output_addr_const (file, XEXP (x, 0));
-      break;
-
     case CONST_DOUBLE:
       if (GET_MODE (x) == VOIDmode)
 	{
@@ -3435,56 +3478,13 @@ output_addr_const (FILE *file, rtx x)
 	       (unsigned HOST_WIDE_INT) CONST_FIXED_VALUE_LOW (x));
       break;
 
-    case PLUS:
-      /* Some assemblers need integer constants to appear last (eg masm).  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
-	{
-	  output_addr_const (file, XEXP (x, 1));
-	  if (INTVAL (XEXP (x, 0)) >= 0)
-	    fprintf (file, "+");
-	  output_addr_const (file, XEXP (x, 0));
-	}
-      else
-	{
-	  output_addr_const (file, XEXP (x, 0));
-	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
-	      || INTVAL (XEXP (x, 1)) >= 0)
-	    fprintf (file, "+");
-	  output_addr_const (file, XEXP (x, 1));
-	}
-      break;
-
-    case MINUS:
-      /* Avoid outputting things like x-x or x+5-x,
-	 since some assemblers can't handle that.  */
-      x = simplify_subtraction (x);
-      if (GET_CODE (x) != MINUS)
-	goto restart;
-
-      output_addr_const (file, XEXP (x, 0));
-      fprintf (file, "-");
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
-	  || GET_CODE (XEXP (x, 1)) == PC
-	  || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
-	output_addr_const (file, XEXP (x, 1));
-      else
-	{
-	  fputs (targetm.asm_out.open_paren, file);
-	  output_addr_const (file, XEXP (x, 1));
-	  fputs (targetm.asm_out.close_paren, file);
-	}
-      break;
-
-    case ZERO_EXTEND:
-    case SIGN_EXTEND:
-    case SUBREG:
-    case TRUNCATE:
-      output_addr_const (file, XEXP (x, 0));
-      break;
-
     default:
 #ifdef OUTPUT_ADDR_CONST_EXTRA
+      if (op == '-')
+        fputs (targetm.asm_out.open_paren, file);
       OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
+      if (op == '-')
+        fputs (targetm.asm_out.close_paren, file);
       break;
 
     fail:
@@ -3492,6 +3492,17 @@ output_addr_const (FILE *file, rtx x)
       output_operand_lossage ("invalid expression as operand");
     }
 }
+
+/* Print an integer constant expression in assembler syntax.
+   Addition and subtraction are the only arithmetic
+   that may appear in these expressions.  */
+
+void
+output_addr_const (FILE *file, rtx x)
+{
+  output_addr_const_1 (file, x, 0);
+}
+
 
 /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
    %R prints the value of REGISTER_PREFIX.
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 134628)
+++ cp/typeck.c	(working copy)
@@ -6396,10 +6396,8 @@ build_ptrmemfunc1 (tree type, tree delta
   u = build_constructor (type, v);
   TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta);
   TREE_STATIC (u) = (TREE_CONSTANT (u)
-		     && (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
-			 != NULL_TREE)
-		     && (initializer_constant_valid_p (delta, TREE_TYPE (delta))
-			 != NULL_TREE));
+		     && initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
+		     && initializer_constant_valid_p (delta, TREE_TYPE (delta)));
   return u;
 }
 
Index: expr.c
===================================================================
--- expr.c	(revision 134628)
+++ expr.c	(working copy)
@@ -4845,8 +4845,7 @@ categorize_ctor_elements_1 (const_tree c
 	  elt_count += mult;
 
 	  if (const_from_elts_p && const_p)
-	    const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
-		      != NULL_TREE;
+	    const_p = initializer_constant_valid_p (value, TREE_TYPE (value));
 	  break;
 	}
     }
@@ -4902,7 +4901,7 @@ categorize_ctor_elements_1 (const_tree c
      is not the largest element in the union, then set *p_must_clear.
 
    Return whether or not CTOR is a valid static constant initializer, the same
-   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
+   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR))".  */
 
 bool
 categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
Index: varasm.c
===================================================================
--- varasm.c	(revision 134628)
+++ varasm.c	(working copy)
@@ -4001,17 +4001,59 @@ constructor_static_from_elts_p (const_tr
 	  && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
 }
 
-/* Return nonzero if VALUE is a valid constant-valued expression
+/* Return true if the value is absolute, i.e. it does not refer to the
+   address of a static variable.  */
+
+static bool
+initializer_constant_absolute_p (tree value, tree endtype)
+{
+  switch (TREE_CODE (value))
+    {
+    case CONSTRUCTOR:
+      if (constructor_static_from_elts_p (value))
+	{
+	  unsigned HOST_WIDE_INT idx;
+	  tree elt;
+
+	  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
+	    if (!initializer_constant_absolute_p (elt, TREE_TYPE (elt)))
+	      return false;
+
+	  return true;
+	}
+
+      return TREE_STATIC (value);
+
+    case MINUS_EXPR:
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+      /* These always produce absolute values, but we need to
+	 ascertain their validity anyway.  */
+      return initializer_constant_valid_p (value, endtype);
+
+    case INTEGER_CST:
+    case VECTOR_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Return true if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
-   element of a "constant" initializer.
+   element of a "constant" initializer. 
 
-   Return null_pointer_node if the value is absolute;
-   if it is relocatable, return the variable that determines the relocation.
    We assume that VALUE has been folded as much as possible;
    therefore, we do not need to check for such things as
    arithmetic-combinations of integers.  */
 
-tree
+bool
 initializer_constant_valid_p (tree value, tree endtype)
 {
   switch (TREE_CODE (value))
@@ -4021,24 +4063,15 @@ initializer_constant_valid_p (tree value
 	{
 	  unsigned HOST_WIDE_INT idx;
 	  tree elt;
-	  bool absolute = true;
 
 	  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
-	    {
-	      tree reloc;
-	      reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
-	      if (!reloc)
-		return NULL_TREE;
-	      if (reloc != null_pointer_node)
-		absolute = false;
-	    }
-	  /* For a non-absolute relocation, there is no single
-	     variable that can be "the variable that determines the
-	     relocation."  */
-	  return absolute ? null_pointer_node : error_mark_node;
+	    if (!initializer_constant_valid_p (elt, TREE_TYPE (elt)))
+	      return false;
+
+	  return true;
 	}
 
-      return TREE_STATIC (value) ? null_pointer_node : NULL_TREE;
+      return TREE_STATIC (value);
 
     case INTEGER_CST:
     case VECTOR_CST:
@@ -4046,29 +4079,29 @@ initializer_constant_valid_p (tree value
     case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
-      return null_pointer_node;
+      return true;
 
     case ADDR_EXPR:
     case FDESC_EXPR:
       value = staticp (TREE_OPERAND (value, 0));
-      if (value)
-	{
-	  /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
-	     be a constant, this is old-skool offsetof-like nonsense.  */
-	  if (TREE_CODE (value) == INDIRECT_REF
-	      && TREE_CONSTANT (TREE_OPERAND (value, 0)))
-	    return null_pointer_node;
-	  /* Taking the address of a nested function involves a trampoline.  */
-	  if (TREE_CODE (value) == FUNCTION_DECL
-	      && decl_function_context (value)
-	      && !DECL_NO_STATIC_CHAIN (value))
-	    return NULL_TREE;
-	  /* "&{...}" requires a temporary to hold the constructed
-	     object.  */
-	  if (TREE_CODE (value) == CONSTRUCTOR)
-	    return NULL_TREE;
-	}
-      return value;
+      if (!value)
+	return false;
+
+      /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
+	 be a constant, this is old-skool offsetof-like nonsense.  */
+      if (TREE_CODE (value) == INDIRECT_REF
+	  && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+	return true;
+      /* Taking the address of a nested function involves a trampoline.  */
+      if (TREE_CODE (value) == FUNCTION_DECL
+	  && decl_function_context (value)
+	  && !DECL_NO_STATIC_CHAIN (value))
+	return false;
+      /* "&{...}" requires a temporary to hold the constructed object.  */
+      if (TREE_CODE (value) == CONSTRUCTOR)
+	return false;
+
+      return true;
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -4101,12 +4134,7 @@ initializer_constant_valid_p (tree value
 	/* Allow conversions between other integer types only if
 	   explicit value.  */
 	if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
-	  {
-	    tree inner = initializer_constant_valid_p (src, endtype);
-	    if (inner == null_pointer_node)
-	      return null_pointer_node;
-	    break;
-	  }
+	  return initializer_constant_valid_p (src, endtype);
 
 	/* Allow (int) &foo provided int is as wide as a pointer.  */
 	if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
@@ -4121,9 +4149,9 @@ initializer_constant_valid_p (tree value
 	  {
 	    if (TREE_CODE (src) == INTEGER_CST
 		&& TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))
-	      return null_pointer_node;
+	      return true;
 	    if (integer_zerop (src))
-	      return null_pointer_node;
+	      return true;
 	    else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
 	      return initializer_constant_valid_p (src, endtype);
 	  }
@@ -4136,106 +4164,742@@ initializer_constant_valid_p (tree value
 
     case POINTER_PLUS_EXPR:
     case PLUS_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);
-	  /* If either term is absolute, use the other term's relocation.  */
-	  if (valid0 == null_pointer_node)
-	    return valid1;
-	  if (valid1 == null_pointer_node)
-	    return valid0;
-	}
+      if (initializer_constant_absolute_p (TREE_OPERAND (value, 1), endtype)
+	  && initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype))
+	return true;
+      if (initializer_constant_absolute_p (TREE_OPERAND (value, 0), endtype)
+	  && initializer_constant_valid_p (TREE_OPERAND (value, 1), endtype))
+	return true;
       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
-	      && operand_equal_p (valid0, valid1, 1))
-	    return null_pointer_node;
-	}
-
-      /* Support narrowing differences.  */
-      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;
-	    }
+      {
+	tree op0, op1;
 
-	  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;
-	    }
+	op0 = TREE_OPERAND (value, 0);
+	op1 = TREE_OPERAND (value, 1);
+
+        /* Support narrowing differences.  */
+        if (INTEGRAL_TYPE_P (endtype))
+	  {
+	    /* 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;
+	      }
 
-	  op0 = initializer_constant_valid_p (op0, endtype);
-	  op1 = initializer_constant_valid_p (op1, endtype);
+	    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;
+	      }
+	  }
 
-	  /* Both initializers must be known.  */
-	  if (op0 && op1)
-	    {
-	      if (op0 == op1)
-		return null_pointer_node;
+	/* Support differences between labels.  */
+        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 true;
+
+	/* Assuming all folding has been done, things like
+	   &a[1] - &a[0] won't survive until here.  */
+        if (! INTEGRAL_TYPE_P (endtype)
+	    || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+	  return (initializer_constant_valid_p (op0, endtype)
+	 	  && initializer_constant_valid_p (op1, endtype));
 
-	      /* Support differences between labels.  */
-	      if (TREE_CODE (op0) == LABEL_DECL
-		  && TREE_CODE (op1) == LABEL_DECL)
-		return null_pointer_node;
-
-	      if (TREE_CODE (op0) == STRING_CST
-		  && TREE_CODE (op1) == STRING_CST
-		  && operand_equal_p (op0, op1, 1))
-		return null_pointer_node;
-	    }
-	}
-      break;
+        break;
+      }
 
     default:
       break;
Index: output.h
===================================================================
--- output.h	(revision 134628)
+++ output.h	(working copy)
@@ -285,16 +285,10 @@ extern void output_object_blocks (void);
 
 extern bool constructor_static_from_elts_p (const_tree);
 
-/* Return nonzero if VALUE is a valid constant-valued expression
+/* Return whether if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
-   element of a "constant" initializer.
-
-   Return null_pointer_node if the value is absolute;
-   if it is relocatable, return the variable that determines the relocation.
-   We assume that VALUE has been folded as much as possible;
-   therefore, we do not need to check for such things as
-   arithmetic-combinations of integers.  */
-extern tree initializer_constant_valid_p (tree, tree);
+   element of a "constant" initializer.  */
+extern bool initializer_constant_valid_p (tree, tree);
 
 /* Output assembler code for constant EXP to FILE, with no label.
    This includes the pseudo-op such as ".int" or ".byte", and a newline.

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