diff gcc/varasm.c @ 63:b7f97abdc517 gcc-4.6-20100522

update gcc from gcc-4.5.0 to gcc-4.6
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Mon, 24 May 2010 12:47:05 +0900
parents 77e2b8dfacca
children f6334be47118
line wrap: on
line diff
--- a/gcc/varasm.c	Fri Feb 12 23:41:23 2010 +0900
+++ b/gcc/varasm.c	Mon May 24 12:47:05 2010 +0900
@@ -1,7 +1,7 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -38,7 +38,6 @@
 #include "expr.h"
 #include "hard-reg-set.h"
 #include "regs.h"
-#include "real.h"
 #include "output.h"
 #include "toplev.h"
 #include "hashtab.h"
@@ -170,11 +169,9 @@
 static GTY(()) section *unnamed_sections;
 
 /* Return a nonzero value if DECL has a section attribute.  */
-#ifndef IN_NAMED_SECTION
 #define IN_NAMED_SECTION(DECL) \
   ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
    && DECL_SECTION_NAME (DECL) != NULL_TREE)
-#endif
 
 /* Hash table of named sections.  */
 static GTY((param_is (section))) htab_t section_htab;
@@ -367,7 +364,7 @@
   /* Note that we use the hash of the decl's name, rather than a hash
      of the decl's pointer.  In emutls_finish we iterate through the
      hash table, and we want this traversal to be predictable.  */
-  in.hash = htab_hash_string (IDENTIFIER_POINTER (name));
+  in.hash = IDENTIFIER_HASH_VALUE (name);
   in.base.from = decl;
   loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
   h = (struct tree_map *) *loc;
@@ -405,6 +402,8 @@
 	int foo() { return i; }
 	__thread int i = 1;
      in which I goes from external to locally defined and initialized.  */
+  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
+  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
 
   TREE_STATIC (to) = TREE_STATIC (decl);
   TREE_USED (to) = TREE_USED (decl);
@@ -1174,12 +1173,13 @@
   if (TREE_TYPE (decl) != error_mark_node)
     as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
 
-  /* If the decl has been given an explicit section name, or it resides
-     in a non-generic address space, then it isn't common, and shouldn't
-     be handled as such.  */
-  if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL
-      && ADDR_SPACE_GENERIC_P (as))
-    {
+  if (DECL_COMMON (decl))
+    {
+      /* If the decl has been given an explicit section name, or it resides
+	 in a non-generic address space, then it isn't common, and shouldn't
+	 be handled as such.  */
+      gcc_assert (DECL_SECTION_NAME (decl) == NULL
+		  && ADDR_SPACE_GENERIC_P (as));
       if (DECL_THREAD_LOCAL_P (decl))
 	return tls_comm_section;
       /* This cannot be common bss for an emulated TLS object without
@@ -1355,6 +1355,14 @@
       return;
     }
 
+  /* If this variable belongs to the global constant pool, retrieve the
+     pre-computed RTL or recompute it in LTO mode.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_IN_CONSTANT_POOL (decl))
+    {
+      SET_DECL_RTL (decl, output_constant_def (DECL_INITIAL (decl), 1));
+      return;
+    }
+
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
   if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
@@ -1434,6 +1442,10 @@
 
   /* Specifying a section attribute on a variable forces it into a
      non-.bss section, and thus it cannot be common.  */
+  /* FIXME: In general this code should not be necessary because
+     visibility pass is doing the same work.  But notice_global_symbol
+     is called early and it needs to make DECL_RTL to get the name.
+     we take care of recomputing the DECL_RTL after visibility is changed.  */
   if (TREE_CODE (decl) == VAR_DECL
       && DECL_SECTION_NAME (decl) != NULL_TREE
       && DECL_INITIAL (decl) == NULL_TREE
@@ -1474,6 +1486,42 @@
   if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
     mudflap_enqueue_decl (decl);
 }
+
+/* Like make_decl_rtl, but inhibit creation of new alias sets when
+   calling make_decl_rtl.  Also, reset DECL_RTL before returning the
+   rtl.  */
+
+rtx
+make_decl_rtl_for_debug (tree decl)
+{
+  unsigned int save_aliasing_flag, save_mudflap_flag;
+  rtx rtl;
+
+  if (DECL_RTL_SET_P (decl))
+    return DECL_RTL (decl);
+
+  /* Kludge alert!  Somewhere down the call chain, make_decl_rtl will
+     call new_alias_set.  If running with -fcompare-debug, sometimes
+     we do not want to create alias sets that will throw the alias
+     numbers off in the comparison dumps.  So... clearing
+     flag_strict_aliasing will keep new_alias_set() from creating a
+     new set.  It is undesirable to register decl with mudflap
+     in this case as well.  */
+  save_aliasing_flag = flag_strict_aliasing;
+  flag_strict_aliasing = 0;
+  save_mudflap_flag = flag_mudflap;
+  flag_mudflap = 0;
+
+  rtl = DECL_RTL (decl);
+  /* Reset DECL_RTL back, as various parts of the compiler expects
+     DECL_RTL set meaning it is actually going to be output.  */
+  SET_DECL_RTL (decl, NULL);
+
+  flag_strict_aliasing = save_aliasing_flag;
+  flag_mudflap = save_mudflap_flag;
+
+  return rtl;
+}
 
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
@@ -2159,8 +2207,6 @@
   if (flag_syntax_only)
     return;
 
-  app_disable ();
-
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
@@ -2171,6 +2217,19 @@
   gcc_assert (MEM_P (decl_rtl));
   gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
   symbol = XEXP (decl_rtl, 0);
+
+  /* If this symbol belongs to the tree constant pool, output the constant
+     if it hasn't already been written.  */
+  if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+    {
+      tree decl = SYMBOL_REF_DECL (symbol);
+      if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
+	output_constant_def_contents (symbol);
+      return;
+    }
+
+  app_disable ();
+
   name = XSTR (symbol, 0);
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
@@ -2337,13 +2396,15 @@
   /* We want to output annotation for weak and external symbols at
      very last to check if they are references or not.  */
 
-  if (SUPPORTS_WEAK && DECL_WEAK (decl)
+  if (SUPPORTS_WEAK
+      && DECL_WEAK (decl)
       /* TREE_STATIC is a weird and abused creature which is not
 	 generally the right test for whether an entity has been
 	 locally emitted, inlined or otherwise not-really-extern, but
 	 for declarations that can be weak, it happens to be
 	 match.  */
       && !TREE_STATIC (decl)
+      && lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
       && value_member (decl, weak_decls) == NULL_TREE)
     weak_decls = tree_cons (NULL, decl, weak_decls);
 
@@ -2749,7 +2810,6 @@
     {
       if (TREE_CODE (target) == COMPONENT_REF
 	  && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
-
 	{
 	  offset += int_byte_position (TREE_OPERAND (target, 1));
 	  target = TREE_OPERAND (target, 0);
@@ -2761,6 +2821,11 @@
 		     * tree_low_cst (TREE_OPERAND (target, 1), 0));
 	  target = TREE_OPERAND (target, 0);
 	}
+      else if (TREE_CODE (target) == INDIRECT_REF
+	       && TREE_CODE (TREE_OPERAND (target, 0)) == NOP_EXPR
+	       && TREE_CODE (TREE_OPERAND (TREE_OPERAND (target, 0), 0))
+		  == ADDR_EXPR)
+	target = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (target, 0), 0), 0);
       else
 	break;
     }
@@ -2801,7 +2866,6 @@
 static GTY((param_is (struct constant_descriptor_tree)))
      htab_t const_desc_htab;
 
-static struct constant_descriptor_tree * build_constant_desc (tree);
 static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
 
 /* Constant pool accessor function.  */
@@ -2853,6 +2917,18 @@
       return (const_hash_1 (TREE_REALPART (exp)) * 5
 	      + const_hash_1 (TREE_IMAGPART (exp)));
 
+    case VECTOR_CST:
+      {
+	tree link;
+
+	hi = 7 + TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp));
+
+	for (link = TREE_VECTOR_CST_ELTS (exp); link; link = TREE_CHAIN (link))
+	    hi = hi * 563 + const_hash_1 (TREE_VALUE (link));
+
+	return hi;
+      }
+
     case CONSTRUCTOR:
       {
 	unsigned HOST_WIDE_INT idx;
@@ -2981,6 +3057,27 @@
       return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
 	      && compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
 
+    case VECTOR_CST:
+      {
+        tree link1, link2;
+
+        if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1))
+	    != TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2)))
+	  return 0;
+
+	link2 = TREE_VECTOR_CST_ELTS (t2);
+	for (link1 = TREE_VECTOR_CST_ELTS (t1);
+	     link1;
+	     link1 = TREE_CHAIN (link1))
+	  {
+	    if (!compare_constant (TREE_VALUE (link1), TREE_VALUE (link2)))
+	      return 0;
+	    link2 = TREE_CHAIN (link2);
+	  }
+	
+	return 1;
+      }
+
     case CONSTRUCTOR:
       {
 	VEC(constructor_elt, gc) *v1, *v2;
@@ -3041,11 +3138,34 @@
     case FDESC_EXPR:
       {
 	struct addr_const value1, value2;
+	enum rtx_code code;
+	int ret;
 
 	decode_addr_const (t1, &value1);
 	decode_addr_const (t2, &value2);
-	return (value1.offset == value2.offset
-		&& strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+
+	if (value1.offset != value2.offset)
+	  return 0;
+
+	code = GET_CODE (value1.base);
+	if (code != GET_CODE (value2.base))
+	  return 0;
+
+	switch (code)
+	  {
+	  case SYMBOL_REF:
+	    ret = (strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+	    break;
+
+	  case LABEL_REF:
+	    ret = (CODE_LABEL_NUMBER (XEXP (value1.base, 0))
+	           == CODE_LABEL_NUMBER (XEXP (value2.base, 0)));
+	    break;
+
+	  default:
+	    gcc_unreachable ();
+	  }
+	return ret;
       }
 
     case PLUS_EXPR:
@@ -3106,6 +3226,10 @@
       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
 		     copy_constant (TREE_OPERAND (exp, 0)));
 
+    case VECTOR_CST:
+      return build_vector (TREE_TYPE (exp),
+			   copy_list (TREE_VECTOR_CST_ELTS (exp)));
+
     case CONSTRUCTOR:
       {
 	tree copy = copy_node (exp);
@@ -3130,31 +3254,14 @@
     }
 }
 
-/* Return the alignment of constant EXP in bits.  */
-
-static unsigned int
-get_constant_alignment (tree exp)
-{
-  unsigned int align;
-
-  align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
-  align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-  return align;
-}
-
 /* Return the section into which constant EXP should be placed.  */
 
 static section *
-get_constant_section (tree exp)
-{
-  if (IN_NAMED_SECTION (exp))
-    return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
-  else
-    return targetm.asm_out.select_section (exp,
-					   compute_reloc_for_constant (exp),
-					   get_constant_alignment (exp));
+get_constant_section (tree exp, unsigned int align)
+{
+  return targetm.asm_out.select_section (exp,
+					 compute_reloc_for_constant (exp),
+					 align);
 }
 
 /* Return the size of constant EXP in bytes.  */
@@ -3180,11 +3287,11 @@
 static struct constant_descriptor_tree *
 build_constant_desc (tree exp)
 {
-  rtx symbol;
-  rtx rtl;
+  struct constant_descriptor_tree *desc;
+  rtx symbol, rtl;
   char label[256];
   int labelno;
-  struct constant_descriptor_tree *desc;
+  tree decl;
 
   desc = GGC_NEW (struct constant_descriptor_tree);
   desc->value = copy_constant (exp);
@@ -3197,17 +3304,41 @@
   labelno = const_labelno++;
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
-  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
+  /* Construct the VAR_DECL associated with the constant.  */
+  decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label),
+		     TREE_TYPE (exp));
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  TREE_STATIC (decl) = 1;
+  TREE_ADDRESSABLE (decl) = 1;
+  /* We don't set the RTL yet as this would cause varpool to assume that the
+     variable is referenced.  Moreover, it would just be dropped in LTO mode.
+     Instead we set the flag that will be recognized in make_decl_rtl.  */
+  DECL_IN_CONSTANT_POOL (decl) = 1;
+  DECL_INITIAL (decl) = desc->value;
+  /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most
+     architectures so use DATA_ALIGNMENT as well, except for strings.  */
+  if (TREE_CODE (exp) == STRING_CST)
+    {
+#ifdef CONSTANT_ALIGNMENT
+      DECL_ALIGN (decl) = CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl));
+#endif
+    }
+  else
+    align_variable (decl, 0);
+
+  /* Now construct the SYMBOL_REF and the MEM.  */
   if (use_object_blocks_p ())
     {
-      section *sect = get_constant_section (exp);
+      section *sect = get_constant_section (exp, DECL_ALIGN (decl));
       symbol = create_block_symbol (ggc_strdup (label),
 				    get_block_for_section (sect), -1);
     }
   else
     symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
   SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
-  SET_SYMBOL_REF_DECL (symbol, desc->value);
+  SET_SYMBOL_REF_DECL (symbol, decl);
   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
 
   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
@@ -3224,7 +3355,6 @@
      ASM_OUTPUT_LABELREF will have to know how to strip this
      information.  This call might invalidate our local variable
      SYMBOL; we can't use it afterward.  */
-
   targetm.encode_section_info (exp, rtl, true);
 
   desc->rtl = rtl;
@@ -3331,7 +3461,8 @@
 static void
 output_constant_def_contents (rtx symbol)
 {
-  tree exp = SYMBOL_REF_DECL (symbol);
+  tree decl = SYMBOL_REF_DECL (symbol);
+  tree exp = DECL_INITIAL (decl);
   unsigned int align;
 
   /* Make sure any other constants whose addresses appear in EXP
@@ -3348,8 +3479,8 @@
     place_block_symbol (symbol);
   else
     {
-      switch_to_section (get_constant_section (exp));
-      align = get_constant_alignment (exp);
+      align = DECL_ALIGN (decl);
+      switch_to_section (get_constant_section (exp, align));
       if (align > BITS_PER_UNIT)
 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
       assemble_constant_contents (exp, XSTR (symbol, 0), align);
@@ -3374,6 +3505,37 @@
 
   return (desc ? desc->rtl : NULL_RTX);
 }
+
+/* Return a tree representing a reference to constant data in memory
+   for the constant expression EXP.
+
+   This is the counterpart of output_constant_def at the Tree level.  */
+
+tree
+tree_output_constant_def (tree exp)
+{
+  struct constant_descriptor_tree *desc, key;
+  void **loc;
+  tree decl;
+
+  /* Look up EXP in the table of constant descriptors.  If we didn't find
+     it, create a new one.  */
+  key.value = exp;
+  key.hash = const_hash_1 (exp);
+  loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
+
+  desc = (struct constant_descriptor_tree *) *loc;
+  if (desc == 0)
+    {
+      desc = build_constant_desc (exp);
+      desc->hash = key.hash;
+      *loc = desc;
+    }
+
+  decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
+  varpool_finalize_decl (decl);
+  return decl;
+}
 
 /* Used in the hash tables to avoid outputting the same constant
    twice.  Unlike 'struct constant_descriptor_tree', RTX constants
@@ -3843,8 +4005,8 @@
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
     {
-      tree exp = SYMBOL_REF_DECL (x);
-      if (!TREE_ASM_WRITTEN (exp))
+      tree decl = SYMBOL_REF_DECL (x);
+      if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
 	{
 	  n_deferred_constants--;
 	  output_constant_def_contents (x);
@@ -4091,6 +4253,9 @@
 	  && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
 }
 
+static tree initializer_constant_valid_p_1 (tree value, tree endtype,
+					    tree *cache);
+
 /* A subroutine of initializer_constant_valid_p.  VALUE is a MINUS_EXPR,
    PLUS_EXPR or POINTER_PLUS_EXPR.  This looks for cases of VALUE
    which are valid when ENDTYPE is an integer of any size; in
@@ -4100,7 +4265,7 @@
    returns NULL.  */
 
 static tree
-narrowing_initializer_constant_valid_p (tree value, tree endtype)
+narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache)
 {
   tree op0, op1;
 
@@ -4139,11 +4304,14 @@
       op1 = inner;
     }
 
-  op0 = initializer_constant_valid_p (op0, endtype);
-  op1 = initializer_constant_valid_p (op1, endtype);
-
+  op0 = initializer_constant_valid_p_1 (op0, endtype, cache);
+  if (!op0)
+    return NULL_TREE;
+
+  op1 = initializer_constant_valid_p_1 (op1, endtype,
+					cache ? cache + 2 : NULL);
   /* Both initializers must be known.  */
-  if (op0 && op1)
+  if (op1)
     {
       if (op0 == op1
 	  && (op0 == null_pointer_node
@@ -4164,7 +4332,8 @@
   return NULL_TREE;
 }
 
-/* Return nonzero if VALUE is a valid constant-valued expression
+/* Helper function of initializer_constant_valid_p.
+   Return nonzero 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.
 
@@ -4172,10 +4341,12 @@
    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
-initializer_constant_valid_p (tree value, tree endtype)
+   arithmetic-combinations of integers.
+
+   Use CACHE (pointer to 2 tree values) for caching if non-NULL.  */
+
+static tree
+initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
 {
   tree ret;
 
@@ -4188,18 +4359,33 @@
 	  tree elt;
 	  bool absolute = true;
 
+	  if (cache && cache[0] == value)
+	    return cache[1];
 	  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
 	    {
 	      tree reloc;
-	      reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
+	      reloc = initializer_constant_valid_p_1 (elt, TREE_TYPE (elt),
+						      NULL);
 	      if (!reloc)
-		return NULL_TREE;
+		{
+		  if (cache)
+		    {
+		      cache[0] = value;
+		      cache[1] = NULL_TREE;
+		    }
+		  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."  */
+	  if (cache)
+	    {
+	      cache[0] = value;
+	      cache[1] = absolute ? null_pointer_node : error_mark_node;
+	    }
 	  return absolute ? null_pointer_node : error_mark_node;
 	}
 
@@ -4239,7 +4425,8 @@
       }
 
     case NON_LVALUE_EXPR:
-      return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+      return initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+					     endtype, cache);
 
     case VIEW_CONVERT_EXPR:
       {
@@ -4254,13 +4441,13 @@
 	if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type))
 	  {
 	    if (TYPE_MODE (endtype) == TYPE_MODE (dest_type))
-	      return initializer_constant_valid_p (src, endtype);
+	      return initializer_constant_valid_p_1 (src, endtype, cache);
 	    else
 	      return NULL_TREE;
 	  }
 
 	/* Allow all other kinds of view-conversion.  */
-	return initializer_constant_valid_p (src, endtype);
+	return initializer_constant_valid_p_1 (src, endtype, cache);
       }
 
     CASE_CONVERT:
@@ -4275,18 +4462,18 @@
 	    || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
 	    || (TREE_CODE (dest_type) == OFFSET_TYPE
 		&& TREE_CODE (src_type) == OFFSET_TYPE))
-	  return initializer_constant_valid_p (src, endtype);
+	  return initializer_constant_valid_p_1 (src, endtype, cache);
 
 	/* Allow length-preserving conversions between integer types.  */
 	if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
 	    && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
-	  return initializer_constant_valid_p (src, endtype);
+	  return initializer_constant_valid_p_1 (src, endtype, cache);
 
 	/* 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);
+	    tree inner = initializer_constant_valid_p_1 (src, endtype, cache);
 	    if (inner == null_pointer_node)
 	      return null_pointer_node;
 	    break;
@@ -4295,7 +4482,7 @@
 	/* Allow (int) &foo provided int is as wide as a pointer.  */
 	if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
 	    && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
-	  return initializer_constant_valid_p (src, endtype);
+	  return initializer_constant_valid_p_1 (src, endtype, cache);
 
 	/* Likewise conversions from int to pointers, but also allow
 	   conversions from 0.  */
@@ -4309,14 +4496,14 @@
 	    if (integer_zerop (src))
 	      return null_pointer_node;
 	    else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
-	      return initializer_constant_valid_p (src, endtype);
+	      return initializer_constant_valid_p_1 (src, endtype, cache);
 	  }
 
 	/* Allow conversions to struct or union types if the value
 	   inside is okay.  */
 	if (TREE_CODE (dest_type) == RECORD_TYPE
 	    || TREE_CODE (dest_type) == UNION_TYPE)
-	  return initializer_constant_valid_p (src, endtype);
+	  return initializer_constant_valid_p_1 (src, endtype, cache);
       }
       break;
 
@@ -4326,66 +4513,102 @@
 	 with -frounding-math we hit this with addition of two constants.  */
       if (TREE_CODE (endtype) == REAL_TYPE)
 	return NULL_TREE;
+      if (cache && cache[0] == value)
+	return cache[1];
       if (! INTEGRAL_TYPE_P (endtype)
 	  || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value)))
 	{
-	  tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-						      endtype);
-	  tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
-						      endtype);
+	  tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+	  tree valid0
+	    = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+					      endtype, ncache);
+	  tree valid1
+	    = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
+					      endtype, ncache + 2);
 	  /* 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;
+	    ret = valid1;
+	  else if (valid1 == null_pointer_node)
+	    ret = valid0;
+	  /* Support narrowing pointer differences.  */
+	  else
+	    ret = narrowing_initializer_constant_valid_p (value, endtype,
+							  ncache);
 	}
-
+      else
       /* Support narrowing pointer differences.  */
-      ret = narrowing_initializer_constant_valid_p (value, endtype);
-      if (ret != NULL_TREE)
-	return ret;
-
-      break;
+	ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
+      if (cache)
+	{
+	  cache[0] = value;
+	  cache[1] = ret;
+	}
+      return ret;
 
     case MINUS_EXPR:
       if (TREE_CODE (endtype) == REAL_TYPE)
 	return NULL_TREE;
+      if (cache && cache[0] == value)
+	return cache[1];
       if (! INTEGRAL_TYPE_P (endtype)
 	  || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value)))
 	{
-	  tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-						      endtype);
-	  tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
-						      endtype);
+	  tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+	  tree valid0
+	    = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+					      endtype, ncache);
+	  tree valid1
+	    = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
+					      endtype, ncache + 2);
 	  /* Win if second argument is absolute.  */
 	  if (valid1 == null_pointer_node)
-	    return valid0;
+	    ret = valid0;
 	  /* Win if both arguments have the same relocation.
 	     Then the value is absolute.  */
-	  if (valid0 == valid1 && valid0 != 0)
-	    return null_pointer_node;
-
+	  else if (valid0 == valid1 && valid0 != 0)
+	    ret = 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;
+	  else if (valid0 && TREE_CODE (valid0) == STRING_CST
+		   && valid1 && TREE_CODE (valid1) == STRING_CST
+		   && operand_equal_p (valid0, valid1, 1))
+	    ret = null_pointer_node;
+	  /* Support narrowing differences.  */
+	  else
+	    ret = narrowing_initializer_constant_valid_p (value, endtype,
+							  ncache);
 	}
-
-      /* Support narrowing differences.  */
-      ret = narrowing_initializer_constant_valid_p (value, endtype);
-      if (ret != NULL_TREE)
-	return ret;
-
-      break;
+      else
+	/* Support narrowing differences.  */
+	ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
+      if (cache)
+	{
+	  cache[0] = value;
+	  cache[1] = ret;
+	}
+      return ret;
 
     default:
       break;
     }
 
-  return 0;
+  return NULL_TREE;
+}
+
+/* Return nonzero 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.  */
+tree
+initializer_constant_valid_p (tree value, tree endtype)
+{
+  return initializer_constant_valid_p_1 (value, endtype, NULL);
 }
 
 /* Return true if VALUE is a valid constant-valued expression
@@ -5227,6 +5450,9 @@
     warning (0, "weak declaration of %q+D not supported", decl);
 
   mark_weak (decl);
+  if (!lookup_attribute ("weak", DECL_ATTRIBUTES (decl)))
+    DECL_ATTRIBUTES (decl)
+      = tree_cons (get_identifier ("weak"), NULL, DECL_ATTRIBUTES (decl));
 }
 
 static void
@@ -5425,6 +5651,7 @@
   else if (vnode)
     {
       varpool_mark_needed_node (vnode);
+      vnode->force_output = 1;
       return vnode->decl;
     }
   else
@@ -5441,6 +5668,10 @@
   if (TREE_ASM_WRITTEN (decl))
     return;
 
+  /* We must force creation of DECL_RTL for debug info generation, even though
+     we don't use it here.  */
+  make_decl_rtl (decl);
+
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
@@ -5658,10 +5889,6 @@
 # endif
 #endif
     }
-
-  /* We must force creation of DECL_RTL for debug info generation, even though
-     we don't use it here.  */
-  make_decl_rtl (decl);
   TREE_USED (decl) = 1;
 
   /* A quirk of the initial implementation of aliases required that the user
@@ -5696,8 +5923,10 @@
    the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */
 
 void
-default_assemble_visibility (tree decl, int vis)
-{
+default_assemble_visibility (tree decl ATTRIBUTE_UNUSED, 
+			     int vis ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_GAS_HIDDEN
   static const char * const visibility_types[] = {
     NULL, "protected", "hidden", "internal"
   };
@@ -5707,7 +5936,6 @@
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   type = visibility_types[vis];
 
-#ifdef HAVE_GAS_HIDDEN
   fprintf (asm_out_file, "\t.%s\t", type);
   assemble_name (asm_out_file, name);
   fprintf (asm_out_file, "\n");
@@ -5963,6 +6191,10 @@
   gcc_unreachable ();
 }
 
+#ifndef TLS_SECTION_ASM_FLAG
+#define TLS_SECTION_ASM_FLAG 'T'
+#endif
+
 void
 default_elf_asm_named_section (const char *name, unsigned int flags,
 			       tree decl ATTRIBUTE_UNUSED)
@@ -5993,7 +6225,7 @@
   if (flags & SECTION_STRINGS)
     *f++ = 'S';
   if (flags & SECTION_TLS)
-    *f++ = 'T';
+    *f++ = TLS_SECTION_ASM_FLAG;
   if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
     *f++ = 'G';
   *f = '\0';
@@ -6737,8 +6969,8 @@
   else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
     {
       decl = SYMBOL_REF_DECL (symbol);
-      alignment = get_constant_alignment (decl);
-      size = get_constant_size (decl);
+      alignment = DECL_ALIGN (decl);
+      size = get_constant_size (DECL_INITIAL (decl));
     }
   else
     {
@@ -6884,9 +7116,9 @@
       else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
 	{
 	  decl = SYMBOL_REF_DECL (symbol);
-	  assemble_constant_contents (decl, XSTR (symbol, 0),
-				      get_constant_alignment (decl));
-	  offset += get_constant_size (decl);
+	  assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
+				      DECL_ALIGN (decl));
+	  offset += get_constant_size (DECL_INITIAL (decl));
 	}
       else
 	{
@@ -7031,4 +7263,31 @@
     maybe_assemble_visibility (decl);
 }
 
+/* Create a DEBUG_EXPR_DECL / DEBUG_EXPR pair from RTL expression
+   EXP.  */
+rtx
+make_debug_expr_from_rtl (const_rtx exp)
+{
+  tree ddecl = make_node (DEBUG_EXPR_DECL), type;
+  enum machine_mode mode = GET_MODE (exp);
+  rtx dval;
+
+  DECL_ARTIFICIAL (ddecl) = 1;
+  if (REG_P (exp) && REG_EXPR (exp))
+    type = TREE_TYPE (REG_EXPR (exp));
+  else if (MEM_P (exp) && MEM_EXPR (exp))
+    type = TREE_TYPE (MEM_EXPR (exp));
+  else
+    type = NULL_TREE;
+  if (type && TYPE_MODE (type) == mode)
+    TREE_TYPE (ddecl) = type;
+  else
+    TREE_TYPE (ddecl) = lang_hooks.types.type_for_mode (mode, 1);
+  DECL_MODE (ddecl) = mode;
+  dval = gen_rtx_DEBUG_EXPR (mode);
+  DEBUG_EXPR_TREE_DECL (dval) = ddecl;
+  SET_DECL_RTL (ddecl, dval);
+  return dval;
+}
+
 #include "gt-varasm.h"